C语言小游戏实战代码
·
07.绘制卡通头像
#include <easyx.h>
#include <stdio.h>
#define PI 3.14
int main()
{
initgraph(1024, 1024);
// 设置背景色为白色
setbkcolor(WHITE);
// 使用当前背景色清空窗体
cleardevice();
// 设置描边颜色为黑色,描边线形为实线,粗细为10
setlinecolor(BLACK);
setlinestyle(PS_SOLID, 10);
// 绘制头部
// 设置填充颜色为蓝色
setfillcolor(BLUE);
fillellipse(118, 125, 990, 931);
Sleep(1000);
// 绘制脸
// 设置填充颜色为白色
setfillcolor(WHITE);
fillellipse(189, 271, 919, 931);
Sleep(1000);
// 绘制一对眼睛
fillellipse(375, 170, 555, 420);
fillellipse(555, 170, 735, 420);
Sleep(1000);
// 绘制一对瞳孔
setfillcolor(BLACK);
solidcircle(484, 333, 25);
solidcircle(617, 333, 25);
Sleep(1000);
// 绘制一对高光
setfillcolor(WHITE);
solidcircle(484, 333, 10);
solidcircle(617, 333, 10);
Sleep(1000);
// 绘制鼻子及竖线
setfillcolor(RED);
fillcircle(554, 420, 35);
line(554, 460, 554, 828);
Sleep(1000);
// 嘴巴
arc(320, 510, 789, 827, PI, 2 * PI);
Sleep(1000);
// 胡须
line(125, 313, 296, 410);
line(83, 444, 270, 474);
line(83, 595, 262, 527);
line(819, 414, 990, 320);
line(845, 478, 1029, 448);
line(853, 542, 1029, 660);
getchar();
closegraph();
return 0;
}
09.绘制显示器
#include <easyx.h>
#include <stdio.h>
int main()
{
initgraph(800, 600);
setbkcolor(WHITE);
cleardevice();
// 1.银色圆角矩形
setfillcolor(RGB(232, 235, 240));
solidroundrect(100, 50, 700, 450, 20, 20);
// 2.蓝黑色矩形
setfillcolor(RGB(71, 78, 94));
solidrectangle(100, 390, 700, 410);
// 3.蓝黑色圆角矩形
solidroundrect(100, 50, 700, 410, 20, 20);
// 4.天蓝色矩形屏幕
setfillcolor(RGB(115, 199, 235));
solidrectangle(120, 70, 680, 390);
// 5.银色圆形摄像头
setfillcolor(RGB(232, 235, 240));
solidcircle(400, 60, 5);
// 6.蓝黑色圆形开机键
setfillcolor(RGB(71, 78, 94));
solidcircle(400, 430, 12);
// 7.深灰色椭圆底座
setfillcolor(RGB(218, 219, 224));
solidellipse(275, 515, 525, 545);
// 8.银色梯形支架
setfillcolor(RGB(232, 235, 240));
POINT bigTrapezoid[4] = { {345, 450}, {455, 450}, {475, 530}, {325, 530} };
solidpolygon(bigTrapezoid, 4);
// 9.深灰色梯形阴影
setfillcolor(RGB(218, 219, 224));
POINT smallTrapezoid[4] = { {345, 450}, {455, 450}, {460, 470}, {340, 470} };
solidpolygon(smallTrapezoid, 4);
getchar();
closegraph();
return 0;
}
11.绘制卡通熊
#include <stdio.h>
#include <easyx.h>
int main()
{
initgraph(800, 600);
// 背景
setbkcolor(RGB(169, 92, 10));
cleardevice();
// 耳朵阴影
setfillcolor(RGB(130, 69, 4));
solidcircle(200, 130, 90);
solidcircle(600, 130, 90);
// 留出月牙状阴影
setfillcolor(RGB(255, 178, 50));
solidcircle(200, 120, 90);
solidcircle(600, 120, 90);
// 耳朵剪切区域
HRGN leftEarClip = CreateEllipticRgn(110, 30, 290, 210);
HRGN rightEarClip = CreateEllipticRgn(510, 30, 690, 210);
HRGN earsClip = CreateRectRgn(0, 0, 0, 0);
CombineRgn(earsClip, leftEarClip, rightEarClip, RGN_OR);
setcliprgn(earsClip);
// 留出耳朵高光
setfillcolor(RGB(243, 154, 2));
solidcircle(200, 130, 90);
solidcircle(600, 130, 90);
// 耳朵里面
setfillcolor(RGB(255, 178, 50));
solidcircle(200, 210, 90);
solidcircle(600, 210, 90);
// 释放区域
DeleteObject(leftEarClip);
DeleteObject(rightEarClip);
DeleteObject(earsClip);
// 禁用剪切区域
setcliprgn(NULL);
// 头
setfillcolor(RGB(255, 178, 50));
solidcircle(400, 300, 250);
// 头剪切区域
HRGN headClip = CreateEllipticRgn(150, 50, 650, 550);
setcliprgn(headClip);
// 留出头高光
setfillcolor(RGB(243, 154, 2));
solidcircle(400, 320, 250);
// 释放区域
DeleteObject(headClip);
// 禁用剪切区域
setcliprgn(NULL);
// 眼睛
setfillcolor(RGB(51, 34, 8));
solidcircle(275, 300, 25);
solidcircle(525, 300, 25);
// 白色椭圆阴影
setfillcolor(RGB(130, 69, 4));
solidellipse(310, 385, 490, 485);
// 白色椭圆
setfillcolor(WHITE);
solidellipse(310, 380, 490, 480);
// 鼻子
setfillcolor(RGB(51, 34, 8));
solidcircle(400, 420, 15);
// 胡须
setlinestyle(PS_SOLID, 5);
setlinecolor(RGB(51, 34, 8));
line(400, 420, 370, 450);
line(400, 420, 430, 450);
getchar();
closegraph();
return 0;
}
14.直线运动
#include <easyx.h>
#include <math.h>
#include <stdio.h>
void LinearMotion(int x1, int y1, int x2, int y2, int v)
{
// 速度分量
double vy;
double vx;
// 根据运动类型,计算速度分量大小
if (y2 == y1)
{
// 水平运动
vx = v;
vy = 0;
}
else if (x2 == x1)
{
// 垂直运动
vx = 0;
vy = v;
}
else
{
// 其他运动
// 计算角度θ的正切tanTheta
double tanTheta = (double)abs(y2 - y1) / (double)abs(x2 - x1);
// 已知tanTheta,根据反三角函数计算角度θ
double theta = atan(tanTheta);
// 计算速度分量
vy = sin(theta) * v;
vx = cos(theta) * v;
}
// 根据速度方向的正负,求得速度分量的符号
int vxFlag = 0;
int vyFlag = 0;
if (x2 - x1 > 0)
vxFlag = 1;
else if (x2 - x1 < 0)
vxFlag = -1;
if (y2 - y1 > 0)
vyFlag = 1;
else if (y2 - y1 < 0)
vyFlag = -1;
if (vxFlag == 0 && vyFlag == 0)
return;
vx = vx * vxFlag;
vy = vy * vyFlag;
// 从起始点(x1, y1)开始
double x, y;
x = x1;
y = y1;
// 循环绘制每一帧
while (1)
{
cleardevice();
solidcircle(x, y, 25);
FlushBatchDraw();
Sleep(40);
x += vx;
y += vy;
if (vxFlag == 1)
{
// 符号为正,直到大于等于终止点x2坐标为止
if (x >= x2)
break;
}
else if (vxFlag == -1)
{
// 符号为负,直到小于等于终止点x2坐标为止
if (x <= x2)
break;
}
if (vyFlag == 1)
{
// 符号为正,直到大于等于终止点y2坐标为止
if (y >= y2)
break;
}
else if (vyFlag == -1)
{
// 符号为负,直到小于等于终止点y2坐标为止
if (y <= y2)
break;
}
}
}
int main()
{
initgraph(800, 600);
// 坐标系原点在窗体中心,X轴正方向向右,Y轴正方向向上
setorigin(400, 300);
setaspectratio(1, -1);
// 设置背景色
setbkcolor(RGB(164, 225, 202));
// 使用背景色清空窗体
cleardevice();
// 设置填充颜色为白色WHITE
setfillcolor(WHITE);
// 三角形(P1, P2, P3)
// P1(0, 200)->P2(200, -200)->P3(-200, -200)->P1(0, 200)
LinearMotion(0, 200, 200, -200, 5);
LinearMotion(200, -200, -200, -200, 5);
LinearMotion(-200, -200, 0, 200, 5);
// 三角形(P4, P5, P6)
// P4(0, -200)->P5(-200, 200)->P6(200, 200)->P4(0, -200)
LinearMotion(0, -200, -200, 200, 5);
LinearMotion(-200, 200, 200, 200, 5);
LinearMotion(200, 200, 0, -200, 5);
// 矩形(P5, P6, P2, P3)
// P5(-200, 200)->P6(200, 200)->P2(200, -200)->P3(-200, -200)->P5(-200, 200)
LinearMotion(-200, 200, 200, 200, 5);
LinearMotion(200, 200, 200, -200, 5);
LinearMotion(200, -200, -200, -200, 5);
LinearMotion(-200, -200, -200, 200, 5);
getchar();
closegraph();
return 0;
}
15.弹球小游戏
#include <easyx.h>
#include <stdio.h>
#include <conio.h>
#include <time.h>
typedef struct {
// 圆心坐标
int x, y;
// 速度分量
int vx, vy;
// 小球半径
int r;
// 挡板左边、顶边、右边、底边坐标
int barLeft, barTop, barRight, barBottom;
}GameData;
void reset(GameData* gdata)
{
gdata->x = rand() % (400 + 1) - 200;
gdata->y = rand() % (300 + 1) - 150;
gdata->vx = 5;
gdata->vy = 5;
if (rand() % 2 == 0)
{
gdata->vy = -gdata->vy;
}
if (rand() % 2 == 0)
{
gdata->vx = -gdata->vx;
}
gdata->r = 40;
gdata->barLeft = -150;
gdata->barRight = 150;
gdata->barTop = -280;
gdata->barBottom = -300;
}
int main()
{
initgraph(800, 600);
// 坐标系原点在窗体中心,X轴正方向向右,Y轴正方向向上
setorigin(400, 300);
setaspectratio(1, -1);
// 设置背景色
setbkcolor(RGB(164, 225, 202));
// 使用背景色清空窗体
cleardevice();
// 当前时间作为随机数种子
srand((unsigned int)time(NULL));
// 游戏数据
GameData gdata;
// 初始化游戏数据
reset(&gdata);
while (1)
{
cleardevice();
// 绘制小球
solidcircle(gdata.x, gdata.y, gdata.r);
// 绘制挡板
solidrectangle(gdata.barLeft, gdata.barTop, gdata.barRight, gdata.barBottom);
// 每帧之间休眠40ms
Sleep(40);
// 撞击或越过顶边反弹
if (gdata.y >= 300 - gdata.r)
{
gdata.vy = -gdata.vy;
}
// 撞击或越过左、右边反弹
if (gdata.x <= -400 + gdata.r || gdata.x >= 400 - gdata.r)
{
gdata.vx = -gdata.vx;
}
// 撞击或越过挡板后反弹
if (gdata.barLeft <= gdata.x && gdata.x <= gdata.barRight && gdata.y <= gdata.barTop + gdata.r)
{
gdata.vy = -gdata.vy;
}
// 小球位置变化
gdata.x += gdata.vx;
gdata.y += gdata.vy;
// 控制挡板移动
if (_kbhit() != 0)
{
char c = _getch();
if (c == 'a')
{
if (gdata.barLeft > -400)
{
gdata.barLeft -= 20;
gdata.barRight -= 20;
}
}
else if (c == 'd')
{
if (gdata.barRight < 400)
{
gdata.barLeft += 20;
gdata.barRight += 20;
}
}
}
if (gdata.y <= -300)
{
// 重置游戏初始数据
reset(&gdata);
}
}
closegraph();
return 0;
}
16.贪吃蛇
#include <easyx.h>
#include <stdio.h>
#include <conio.h>
#include <time.h>
#define NODE_WIDTH 40
// 节点
typedef struct {
int x;
int y;
}node;
// 绘制网格
// 横线(0, y), (800, y) 0 <= y <= 600
// 竖线(x, 0),(x, 600) 0 <= x <= 800
void paintGrid()
{
// 横线
for (int y = 0; y < 600; y += NODE_WIDTH)
{
line(0, y, 800, y);
}
// 竖线
for (int x = 0; x < 800; x += NODE_WIDTH)
{
line(x, 0, x, 600);
}
}
void paintSnake(node* snake, int n)
{
int left, top, right, bottom;
for (int i = 0; i < n; i++)
{
// 左上角:【网格x坐标 * 网格宽度, 网格y坐标 * 网格宽度】
left = snake[i].x * NODE_WIDTH;
top = snake[i].y * NODE_WIDTH;
// 右下角:【(网格x坐标 + 1) * 网格宽度, (网格y坐标 + 1) * 网格宽度】
right = (snake[i].x + 1) * NODE_WIDTH;
bottom = (snake[i].y + 1) * NODE_WIDTH;
// 通过左上角与右下角坐标绘制矩形
solidrectangle(left, top, right, bottom);
}
}
// 方向枚举
enum direction
{
eUp,
eDown,
eLeft,
eRight
};
// 蛇身体移动
node snakeMove(node* snake, int length, int direction)
{
//for (int i = 0; i < length; i++)
// printf("(%d, %d)\n", snake[i].x, snake[i].y);
// 记录尾节点
node tail = snake[length - 1];
// 从尾结点开始,前一个节点覆盖后一个节点
// 0 1 2 3 4 0 1 2 3 4
// E D C B A ---> E E D C B
for (int i = length - 1; i > 0; i--)
{
snake[i] = snake[i - 1];
}
// 下一个头节点
node newHead;
newHead = snake[0];
if (direction == eUp)
{
newHead.y--;
}
else if (direction == eDown)
{
newHead.y++;
}
else if (direction == eLeft)
{
newHead.x--;
}
else // right
{
newHead.x++;
}
// 更新头节点
// E D C B A ---> F E D C B
snake[0] = newHead;
//for (int i = 0; i < length; i++)
// printf("(%d, %d)\n", snake[i].x, snake[i].y);
// 返回尾节点
return tail;
}
// 键盘输入改变direction
void changeDirection(enum direction* pD)
{
// 检查输入缓存区中是否有数据
if (_kbhit() != 0)
{
// _getch函数获取输入缓存区中的数据
char c = _getch();
// 判断输入并转向
switch (c)
{
case 'w':
// 向上移动
if (*pD != eDown)
*pD = eUp;
break;
case 's':
// 向下移动
if (*pD != eUp)
*pD = eDown;
break;
case 'a':
// 向左移动
if (*pD != eRight)
*pD = eLeft;
break;
case 'd':
// 向右移动
if (*pD != eLeft)
*pD = eRight;
break;
}
}
}
// 绘制食物
/*
(x * NODE_WIDTH, y * NODE_WIDTH)
@-----------
| |
| |
| |
| |
| |
-----------@ ((x + 1) * NODE_WIDTH, (y + 1) * NODE_WIDTH)
*/
void paintFood(node food)
{
int left, top, right, bottom;
left = food.x * NODE_WIDTH;
top = food.y * NODE_WIDTH;
right = (food.x + 1) * NODE_WIDTH;
bottom = (food.y + 1) * NODE_WIDTH;
setfillcolor(YELLOW);
solidrectangle(left, top, right, bottom);
setfillcolor(WHITE);
}
// 随机创建食物
node createFood(node* snake, int length)
{
node food;
while (1)
{
food.x = rand() % (800 / NODE_WIDTH);
food.y = rand() % (600 / NODE_WIDTH);
int i;
for (i = 0; i < length; i++)
{
if (snake[i].x == food.x && snake[i].y == food.y)
{
break;
}
}
if (i < length)
continue;
else
break;
}
return food;
}
bool isGameOver(node* snake, int length)
{
// 是否撞墙
if (snake[0].x < 0 || snake[0].x > 800 / NODE_WIDTH)
return true;
if (snake[0].y < 0 || snake[0].y > 600 / NODE_WIDTH)
return true;
// 是否吃到蛇身
for (int i = 1; i < length; i++)
{
if (snake[0].x == snake[i].x && snake[0].y == snake[i].y)
return true;
}
return false;
}
void reset(node* snake, int* pLength, enum direction* d)
{
snake[0] = node{ 5, 7 };
snake[1] = node{ 4, 7 };
snake[2] = node{ 3, 7 };
snake[3] = node{ 2, 7 };
snake[4] = node{ 1, 7 };
*pLength = 5;
*d = eRight;
}
int main()
{
initgraph(800, 600);
// 设置背景色
setbkcolor(RGB(164, 225, 202));
// 使用背景色清空窗体
cleardevice();
// 蛇节点坐标
node snake[100] = { {5, 7}, {4, 7}, {3, 7}, {2, 7}, {1, 7} };
// 蛇节点长度
int length = 5;
enum direction d = eRight;
// 食物
srand(unsigned int(time(NULL)));
node food = createFood(snake, length);
while (1)
{
// 清空整个窗体
cleardevice();
// 绘制网格
paintGrid();
// 绘制蛇节点
paintSnake(snake, length);
// 绘制食物
paintFood(food);
// 休眠500ms
Sleep(500);
// 获取键盘输入并将方向存储到变量d
changeDirection(&d);
node lastTail = snakeMove(snake, length, d);
// 新的蛇头节点是否与食物节点重合
if (snake[0].x == food.x && snake[0].y == food.y)
{
// 限制snake节点最大长度
if (length < 100)
{
// 已经吃到食物, 长度+1
snake[length] = lastTail;
length++;
}
// 重新生成新的食物
food = createFood(snake, length);
}
// 游戏是否结束
if (isGameOver(snake, length) == true)
{
// 游戏结束,复位设置,重新生成食物
reset(snake, &length, &d);
food = createFood(snake, length);
}
}
getchar();
closegraph();
return 0;
}
17.多物体运动
#include <easyx.h>
#include <stdio.h>
#include <math.h>
#define NUM_OF_BALLS 1000
#define PI 3.14
typedef struct {
int x;
int y;
int vx;
int vy;
COLORREF color;
}ball;
int main()
{
initgraph(800, 600);
// 坐标系原点在窗体中心,X轴正方向向右,Y轴正方向向上
setorigin(400, 300);
setaspectratio(1, -1);
// 设置背景色
setbkcolor(WHITE);
// 设置描边颜色
setlinecolor(BLACK);
// 使用背景色清空窗体
cleardevice();
int r = 10;
ball* balls = (ball*)malloc(sizeof(ball) * NUM_OF_BALLS);
if (balls == NULL)
{
return -1;
}
for (int i = 0; i < NUM_OF_BALLS; i++)
{
int m, n;
// 圆心x坐标区间:[-400 + r, 400 - r]
m = -400 + r;
n = 400 - r;
balls[i].x = rand() % (n - m + 1) + m;
// 圆心y坐标区间: [-300 + r, 300 - r]
m = -300 + r;
n = 300 - r;
balls[i].y = rand() % (n - m + 1) + m;
// 随机颜色,色相随机,饱和度为80%,明度为90%
balls[i].color = HSVtoRGB((float)(rand() % 360), 0.8f, 0.9f);
// 随机速度大小[3, 8],速度方向与x方向夹角[0, 359]
m = 3;
n = 8;
int v = rand() % (n - m + 1) + m;
double theta;
theta = rand() % 360;
balls[i].vx = v * cos(theta * PI / 180);
balls[i].vy = v * sin(theta * PI / 180);
}
while (1)
{
// 清空画面
cleardevice();
// 绘制多个小球
for (int i = 0; i < NUM_OF_BALLS; i++)
{
setfillcolor(balls[i].color);
fillcircle(balls[i].x, balls[i].y, r);
}
Sleep(40);
// 遍历所有小球,若碰到或越过边界,则反弹
for (int i = 0; i < NUM_OF_BALLS; i++)
{
// 碰到或越过上下边界反弹
if (balls[i].y >= 300 - r || balls[i].y <= -300 + r)
{
balls[i].vy = -balls[i].vy;
}
// 碰到或越过左右边界反弹
if (balls[i].x <= -400 + r || balls[i].x >= 400 - r)
{
balls[i].vx = -balls[i].vx;
}
// 小球移动位置
balls[i].x += balls[i].vx;
balls[i].y += balls[i].vy;
}
}
closegraph();
return 0;
}
18.批量绘图
#include <easyx.h>
#include <stdio.h>
#include <math.h>
#define NUM_OF_BALLS 1000
#define PI 3.14
typedef struct {
int x;
int y;
int vx;
int vy;
COLORREF color;
}ball;
int main()
{
initgraph(800, 600);
// 坐标系原点在窗体中心,X轴正方向向右,Y轴正方向向上
setorigin(400, 300);
setaspectratio(1, -1);
// 设置背景色
setbkcolor(WHITE);
// 设置描边颜色
setlinecolor(BLACK);
// 使用背景色清空窗体
cleardevice();
int r = 10;
ball* balls = (ball*)malloc(sizeof(ball) * NUM_OF_BALLS);
if (balls == NULL)
{
return -1;
}
for (int i = 0; i < NUM_OF_BALLS; i++)
{
int m, n;
// 圆心x坐标区间:[-400 + r, 400 - r]
m = -400 + r;
n = 400 - r;
balls[i].x = rand() % (n - m + 1) + m;
// 圆心y坐标区间: [-300 + r, 300 - r]
m = -300 + r;
n = 300 - r;
balls[i].y = rand() % (n - m + 1) + m;
// 随机颜色,色相随机,饱和度为80%,明度为90%
balls[i].color = HSVtoRGB((float)(rand() % 360), 0.8f, 0.9f);
// 随机速度大小[3, 8],速度方向与x方向夹角[0, 359]
m = 3;
n = 8;
int v = rand() % (n - m + 1) + m;
double theta;
theta = rand() % 360;
balls[i].vx = v * cos(theta * PI / 180);
balls[i].vy = v * sin(theta * PI / 180);
}
// 开始批量绘图
BeginBatchDraw();
while (1)
{
// 清空画面
cleardevice();
// 绘制多个小球
for (int i = 0; i < NUM_OF_BALLS; i++)
{
setfillcolor(balls[i].color);
fillcircle(balls[i].x, balls[i].y, r);
}
// 显示累积的1000个小球,为一帧画面
FlushBatchDraw();
Sleep(40);
// 遍历所有小球,若碰到或越过边界,则反弹
for (int i = 0; i < NUM_OF_BALLS; i++)
{
// 碰到或越过上下边界反弹
if (balls[i].y >= 300 - r || balls[i].y <= -300 + r)
{
balls[i].vy = -balls[i].vy;
}
// 碰到或越过左右边界反弹
if (balls[i].x <= -400 + r || balls[i].x >= 400 - r)
{
balls[i].vx = -balls[i].vx;
}
// 小球移动位置
balls[i].x += balls[i].vx;
balls[i].y += balls[i].vy;
}
}
// 结束批量绘图
EndBatchDraw();
closegraph();
return 0;
}
19.图片
#include <easyx.h>
#include <stdio.h>
int main()
{
initgraph(1200, 480);
IMAGE img;
loadimage(&img, "background.jpg");
putimage(0, 0, &img);
IMAGE imgBear;
loadimage(&imgBear, "bear.png");
putimage(530, 180, &imgBear);
getchar();
closegraph();
}
20.透明图片
#include <easyx.h>
#include <stdio.h>
int main()
{
initgraph(1200, 480);
// 背景图片
IMAGE imgBackground;
loadimage(&imgBackground, "./background.jpg");
// 白背景的黑剪影
IMAGE imgMask;
loadimage(&imgMask, "./mask.jpg");
// 黑背景的熊本体
IMAGE imgBear;
loadimage(&imgBear, "./bear.jpg");
// 背景图片绘制到窗体上
putimage(0, 0, &imgBackground);
// mask.jpg与窗体中图像进行与运算
putimage(530, 180, &imgMask, SRCAND);
// bear.jpg与窗体中图像进行与运算
putimage(530, 180, &imgBear, SRCPAINT);
getchar();
closegraph();
}
21.让熊跑起来
#define _CRT_SECURE_NO_WARNINGS
#include <easyx.h>
#include <stdio.h>
#include <math.h>
#define BEAR_FRAMES 11
void putTransparentImage(int x, int y, const IMAGE* mask, const IMAGE* img)
{
putimage(x, y, mask, SRCAND);
putimage(x, y, img, SRCPAINT);
}
int main()
{
initgraph(1200, 480);
// 设置背景色
setbkcolor(WHITE);
// 使用背景色清空窗体
cleardevice();
IMAGE imgBackground;
loadimage(&imgBackground, "background.jpg");
// load images
IMAGE imgArrBearFrames[BEAR_FRAMES];
for (int i = 0; i < BEAR_FRAMES; i++)
{
char strImgPath[100];
sprintf(strImgPath, "bear/frames/bear%d.png", i);
loadimage(&imgArrBearFrames[i], strImgPath);
}
// load masks
IMAGE imgArrBearMasks[BEAR_FRAMES];
for (int i = 0; i < BEAR_FRAMES; i++)
{
char strImgPath[100];
sprintf(strImgPath, "bear/masks/bearmask%d.png", i);
loadimage(&imgArrBearMasks[i], strImgPath);
}
int frame = 0;
int x = -150;
BeginBatchDraw();
while (1)
{
putimage(0, 0, &imgBackground);
putTransparentImage(x, 180, &imgArrBearMasks[frame], &imgArrBearFrames[frame]);
FlushBatchDraw();
frame++;
x += 10;
if (frame >= BEAR_FRAMES)
frame = 0;
if (x >= 1200 + 150)
x = -150;
Sleep(50);
}
EndBatchDraw();
getchar();
closegraph();
return 0;
}
23.精确帧率控制
#include <easyx.h>
#include <stdio.h>
int main()
{
// 提高系统定时器时钟分辨率为1毫秒
timeBeginPeriod(1);
initgraph(800, 600);
setbkcolor(RGB(164, 225, 202));
cleardevice();
setfillcolor(WHITE);
// 开始时间、结束时间、频率F
LARGE_INTEGER startCount, endCount, F;
// 获取频率F
QueryPerformanceFrequency(&F);
int x = 0, y = 300;
int vx = 5;
BeginBatchDraw();
while (1)
{
// 获取起始计数
QueryPerformanceCounter(&startCount);
// 准备画面
cleardevice();
solidcircle(x, y, 50);
x = x + vx;
if (x <= 0 || x >= 800)
vx = -vx;
// 获取结束计数
QueryPerformanceCounter(&endCount);
// 计算时差
long long elapse = (endCount.QuadPart - startCount.QuadPart)
/ F.QuadPart * 1000000;
// 时差若小于40000,则一直循环,直到时差大于等于40000
// 注意这里的单位是微秒
while (elapse < 40000)
{
// 先休眠一小会,再检查是否超时
Sleep(1);
// 重新获取结束时间
QueryPerformanceCounter(&endCount);
// 更新时差
elapse = (endCount.QuadPart - startCount.QuadPart)
* 1000000 / F.QuadPart;
}
// 绘制画面
FlushBatchDraw();
}
EndBatchDraw();
closegraph();
// timeBeginPeriod与timeEndPeriod必须成对存在,并且传一样的值
timeEndPeriod(1);
return 0;
}
25.打气球
#include <easyx.h>
#include <stdio.h>
#include <math.h>
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define MAX_IN_WINDOW 5
#define BALLOON_RADIUS 30
typedef struct {
int x;
int y;
int r;
int v;
COLORREF color;
}balloon;
balloon generateBalloon()
{
balloon b;
// x坐标在区间[100, 700]之间
int m, n;
m = 100;
n = 700;
b.x = rand() % (n - m + 1) + m;
// y坐标在窗口底部
b.y = WINDOW_HEIGHT;
// 半径为符号常量BALLOON_RADIUS
b.r = BALLOON_RADIUS;
// 速度在区间[1, 3]之间
m = 1;
n = 3;
b.v = rand() % (n - m + 1) + m;
// 颜色RGB值随机
b.color = RGB(rand() % 256, rand() % 256, rand() % 256);
return b;
}
int main()
{
// 创建一个宽度为WINDOW_WIDTH、高度为WINDOW_HEIGHT的窗体,并用白色背景色刷新窗体。
initgraph(WINDOW_WIDTH, WINDOW_HEIGHT);
setbkcolor(WHITE);
cleardevice();
// 气球数组
balloon arrBalloons[MAX_IN_WINDOW];
// 给气球数组赋值
for (int i = 0; i < MAX_IN_WINDOW; i++)
arrBalloons[i] = generateBalloon();
// 当前出现的气球数
int current = MAX_IN_WINDOW;
// 鼠标位置
int mouseX = 0, mouseY = 0;
timeBeginPeriod(1);
LARGE_INTEGER startCount, endCount, F;
QueryPerformanceFrequency(&F);
BeginBatchDraw();
while (1)
{
QueryPerformanceCounter(&startCount);
// 清空窗体
cleardevice();
// 绘制并移动气球
for (int i = 0; i < MAX_IN_WINDOW; i++)
{
// 绘制气球
setfillcolor(arrBalloons[i].color);
solidcircle(arrBalloons[i].x, arrBalloons[i].y, arrBalloons[i].r);
}
// 移动气球
for (int i = 0; i < MAX_IN_WINDOW; i++)
arrBalloons[i].y -= arrBalloons[i].v;
// 删除已飞出窗体外的气球
int i = 0;
while (i < current)
{
int y = arrBalloons[i].y;
// 是否已飞出窗体外
if (y < -BALLOON_RADIUS)
{
// 依次使用后续元素覆盖前驱元素,直到最后一个有效元素为止
for (int j = i; j < current - 1; j++)
arrBalloons[j] = arrBalloons[j + 1];
// 当前气球数减1
current--;
}
else
{
// 数组元素未被删除,i才能自增1
i++;
}
}
// 增加新气球
if (current < MAX_IN_WINDOW)
{
// 气球数组中追加一个气球
arrBalloons[current] = generateBalloon();
// 当前气球数加1
current++;
}
// 绘制准心
// 设置描边颜色为RGB(237, 178, 29)
setlinecolor(RGB(237, 178, 29));
// 线段样式为实线、线段宽度为3
setlinestyle(PS_SOLID, 3);
// 绘制半径为20的描边圆
circle(mouseX, mouseY, 20);
// 绘制十字
line(mouseX - 20, mouseY, mouseX + 20, mouseY);
line(mouseX, mouseY - 20, mouseX, mouseY + 20);
QueryPerformanceCounter(&endCount);
long long elapse = (endCount.QuadPart - startCount.QuadPart)
* 1000000 / F.QuadPart;
// 每秒帧率设置为60,因此最长等待时间为1000000 / 60
while (elapse < 1000000 / 60)
{
Sleep(1);
// 获取鼠标消息
ExMessage msg;
bool isOk = peekmessage(&msg, EX_MOUSE);
// 是否有新消息,没有则无需处理消息
if (isOk == true)
{
// 如果是鼠标移动消息,则更新鼠标位置
if (msg.message == WM_MOUSEMOVE)
{
mouseX = msg.x;
mouseY = msg.y;
}
// 如果是鼠标点击消息,则判断是否点击到气球,点击到将气球删除
else if (msg.message == WM_LBUTTONDOWN)
{
// 检查哪个气球被点击到
int i = 0;
while (i < current)
{
int ballX = arrBalloons[i].x;
int ballY = arrBalloons[i].y;
int distance = (int)sqrt(pow(ballY - msg.y, 2) + pow(ballX - msg.x, 2));
// 是否鼠标与气球的圆心距离小于半径
if (distance < BALLOON_RADIUS)
{
// 依次使用后续元素覆盖前驱元素,直到移动完最后一个有效元素为止
for (int j = i; j < current - 1; j++)
arrBalloons[j] = arrBalloons[j + 1];
// 当前气球数减1
current--;
}
else
{
// 数组元素未被删除,i才能自增1
i++;
}
}
}
}
QueryPerformanceCounter(&endCount);
elapse = (endCount.QuadPart - startCount.QuadPart)
* 1000000 / F.QuadPart;
}
// 批量显示
FlushBatchDraw();
}
EndBatchDraw();
timeEndPeriod(1);
closegraph();
return 0;
}
26.音频
#include <windows.h>
#include <stdio.h>
int main()
{
// 打开音乐
mciSendString("open 起床歌.mp3", NULL, 0, NULL);
printf("打开音乐");
getchar();
// 开始播放
mciSendString("play 起床歌.mp3", NULL, 0, NULL);
printf("开始播放");
getchar();
// 暂停播放
mciSendString("pause 起床歌.mp3", NULL, 0, NULL);
printf("暂停播放");
getchar();
// 继续播放
mciSendString("resume 起床歌.mp3", NULL, 0, NULL);
printf("继续播放");
getchar();
// 停止播放
mciSendString("stop 起床歌.mp3", NULL, 0, NULL);
printf("停止播放");
getchar();
// 关闭音乐
mciSendString("close 起床歌.mp3", NULL, 0, NULL);
printf("关闭音乐");
getchar();
}
27
(1)封装
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student {
void (*setStudentId)(struct student* s, int year, int classNum, int serialNum);
const char* (*getGender)(struct student* s);
void (*setGender)(struct student* s, const char* strGender);
int id; // 学号
char name[20]; // 姓名
int gender; // 性别
int mark; // 分数
};
void setStudentId(struct student* s, int year, int classNum, int serialNum)
{
char buffer[20];
sprintf(buffer, "%d%d%d", year, classNum, serialNum);
int id = atoi(buffer);
s->id = id;
}
const char* getGender(struct student* s)
{
if (s->gender == 0)
{
return "女";
}
else if (s->gender == 1)
{
return "男";
}
return "未知";
}
void setGender(struct student* s, const char* strGender)
{
int numGender;
if (strcmp("男", strGender) == 0)
{
numGender = 1;
}
else if (strcmp("女", strGender) == 0)
{
numGender = 0;
}
else
{
numGender = -1;
}
s->gender = numGender;
}
void initStudent(struct student* s)
{
s->setStudentId = setStudentId;
s->getGender = getGender;
s->setGender = setGender;
}
int main()
{
struct student stu;
// 初始化student
initStudent(&stu);
// 学号:202212326
// 姓名:小明
// 性别: 男
// 分数:98
stu.setStudentId(&stu, 2022, 123, 26);
strcpy(stu.name, "小明");
stu.setGender(&stu, "男");
stu.mark = 98;
// 打印这些数值
printf("学号:%d\n", stu.id);
printf("姓名:%s\n", stu.name);
const char* gender = stu.getGender(&stu);
printf("性别:%s\n", gender);
printf("分数:%d\n", stu.mark);
return 0;
}
(2)继承
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct person {
int id; // 编号
char name[20]; // 姓名
int gender; // 性别
// 设置性别
void (*setGender)(struct person* s, const char* strGender);
// 获取性别
const char* (*getGender)(struct person* s);
};
struct teacher {
struct person super;
char subject[20]; // 任课科目
};
struct student {
struct person super;
int mark; // 分数
// 设置学号
void (*setStudentId)(struct student* s, int year, int classNum, int serialNum);
};
const char* getGender(struct person* p)
{
if (p->gender == 0)
{
return "女";
}
else if (p->gender == 1)
{
return "男";
}
return "未知";
}
void setGender(struct person* p, const char* strGender)
{
int numGender;
if (strcmp("男", strGender) == 0)
{
numGender = 1;
}
else if (strcmp("女", strGender) == 0)
{
numGender = 0;
}
else
{
numGender = -1;
}
p->gender = numGender;
}
void setStudentId(struct student* s, int year, int classNum, int serialNum)
{
char buffer[20];
sprintf(buffer, "%d%d%d", year, classNum, serialNum);
int id = atoi(buffer);
s->super.id = id; // 由s->id = id 修改为 s->super.id = id
}
void initPerson(struct person* p)
{
p->getGender = getGender;
p->setGender = setGender;
}
void initStudent(struct student* s)
{
initPerson(&(s->super));
s->setStudentId = setStudentId;
}
void initTeacher(struct teacher* t)
{
initPerson(&(t->super));
}
int main()
{
struct student stu;
// 初始化student
initStudent(&stu);
// 学号:202212326
// 姓名:小明
// 性别: 男
// 分数:98
stu.setStudentId(&stu, 2022, 123, 26);
strcpy(stu.super.name, "小明");
stu.super.setGender(&stu.super, "男");
stu.mark = 98;
// 打印这些数值
printf("学号:%d\n", stu.super.id);
printf("姓名:%s\n", stu.super.name);
const char* gender = stu.super.getGender(&stu.super);
printf("性别:%s\n", gender);
printf("分数:%d\n", stu.mark);
putchar('\n');
struct teacher t;
// 初始化teacher
initTeacher(&t);
// 工号:12345
// 姓名:林老师
// 性别: 男
// 科目:C语言
t.super.id = 12345;
strcpy(t.super.name, "林老师");
t.super.setGender(&t.super, "男");
strcpy(t.subject, "C语言");
// 打印这些数值
printf("学号:%d\n", t.super.id);
printf("姓名:%s\n", t.super.name);
gender = t.super.getGender(&t.super);
printf("性别:%s\n", gender);
printf("科目:%s\n", t.subject);
return 0;
}
28.多态
#include <easyx.h>
#include <stdio.h>
struct Shape {
void (*draw)(struct Shape*);
};
struct Rect {
struct Shape super;
int left;
int top;
int right;
int bottom;
};
struct Circle {
struct Shape super;
int x;
int y;
int r;
};
struct Triangle {
struct Shape super;
POINT p1;
POINT p2;
POINT p3;
};
void drawRect(struct Rect* r)
{
rectangle(r->left, r->top, r->right, r->bottom);
}
void drawCircle(struct Circle* c)
{
circle(c->x, c->y, c->r);
}
void drawTriangle(struct Triangle* t)
{
line(t->p1.x, t->p1.y, t->p2.x, t->p2.y);
line(t->p2.x, t->p2.y, t->p3.x, t->p3.y);
line(t->p3.x, t->p3.y, t->p1.x, t->p1.y);
}
void initRect(struct Rect* r)
{
r->super.draw = (void (*)(struct Shape*))drawRect;
}
void initCircle(struct Circle* c)
{
c->super.draw = (void (*)(struct Shape*))drawCircle;
}
void initTriangle(struct Triangle* t)
{
t->super.draw = (void (*)(struct Shape*))drawTriangle;
}
int main()
{
initgraph(800, 600);
setaspectratio(1, -1);
setorigin(400, 300);
setbkcolor(WHITE);
setlinecolor(BLACK);
cleardevice();
struct Rect r = { {}, -200, 200, 200, 0 };
struct Circle c = { {}, 0, 0, 100 };
struct Triangle t = { {}, {0, 200}, {-200, 0}, {200, 0} };
initRect(&r);
initCircle(&c);
initTriangle(&t);
struct Shape* arrShape[3] = {
(struct Shape*)&r, (struct Shape*)&c, (struct Shape*)&t };
for (int i = 0; i < 3; i++)
{
arrShape[i]->draw(arrShape[i]);
}
getchar();
closegraph();
return 0;
}
30.动态数组
main.c
#define _CRT_SECURE_NO_WARNINGS
#include "vector.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student {
int id; // 学号
char name[20]; // 姓名
int gender; // 性别
int mark; // 成绩
};
int main()
{
struct vector vec;
vectorInit(&vec);
// append
struct student* s1 = (struct student*)malloc(sizeof(struct student));
s1->id = 1;
strcpy(s1->name, "小明");
s1->gender = 1;
s1->mark = 90;
vec.append(&vec, s1);
for (int i = 0; i < vec.size; i++)
{
struct student* s = (struct student*)vec.get(&vec, i);
printf("%d %s %d %d\n", s->id, s->name, s->gender, s->mark);
}
printf("size:%d\n", vec.size);
printf("capacity:%d\n", vec.capacity);
getchar();
// append追加
struct student* s2 = (struct student*)malloc(sizeof(struct student));
s2->id = 2;
strcpy(s2->name, "小红");
s2->gender = 0;
s2->mark = 95;
vec.append(&vec, s2);
for (int i = 0; i < vec.size; i++)
{
struct student* s = (struct student*)vec.get(&vec, i);
printf("%d %s %d %d\n", s->id, s->name, s->gender, s->mark);
}
printf("size:%d\n", vec.size);
printf("capacity:%d\n", vec.capacity);
getchar();
// remove
// 别忘记销毁小明的数据
free(vec.get(&vec, 0));
vec.remove(&vec, 0);
for (int i = 0; i < vec.size; i++)
{
struct student* s = vec.get(&vec, i);
printf("%d %s %d %d\n", s->id, s->name, s->gender, s->mark);
}
printf("size:%d\n", vec.size);
printf("capacity:%d\n", vec.capacity);
for (int i = 0; i < vec.size; i++)
{
struct student* s = vec.get(&vec, i);
free(s);
}
getchar();
// clear
vec.clear(&vec);
for (int i = 0; i < vec.size; i++)
{
struct student* s = vec.get(&vec, i);
printf("%d %s %d %d\n", s->id, s->name, s->gender, s->mark);
}
printf("size:%d\n", vec.size);
printf("capacity:%d\n", vec.capacity);
getchar();
// 销毁数组
vectorDestroy(&vec);
return 0;
}
vector.h
#pragma once
#include <stdbool.h>
#define VECTOR_INIT_CAPACITY 10
struct vector {
bool (*append)(struct vector* pVec, void* data);
void* (*get)(struct vector* pVec, int index);
void (*clear)(struct vector* pVec);
void (*remove)(struct vector* pVec, int index);
void** pData;
int size;
int capacity;
};
void vectorInit(struct vector*);
void vectorDestroy(struct vector* pVec);
vector.c
#include "vector.h"
#include <stdlib.h>
bool vectorAppend(struct vector* pVec, void* data)
{
if (pVec == NULL || data == NULL)
return false;
// 是否超长
if (pVec->size >= pVec->capacity)
{
// 加长到两倍
void** newData = (void**)realloc(pVec->pData, pVec->capacity * sizeof(void*) * 2);
if (newData == NULL)
{
return false;
}
pVec->pData = newData;
pVec->capacity = 2 * pVec->capacity;
}
pVec->pData[pVec->size] = data;
pVec->size++;
return true;
}
void* vectorGet(struct vector* pVec, int index)
{
if (index >= pVec->size)
return NULL;
return pVec->pData[index];
}
void vectorRemove(struct vector* pVec, int index)
{
for (int i = index; i < pVec->size - 1; i++)
pVec->pData[i] = pVec->pData[i + 1];
pVec->size -= 1;
}
void vectorClear(struct vector* pVec)
{
if (pVec->pData != NULL)
free(pVec->pData);
pVec->pData = (void**)malloc(sizeof(void*) * VECTOR_INIT_CAPACITY);
pVec->capacity = VECTOR_INIT_CAPACITY;
pVec->size = 0;
}
void vectorInit(struct vector* pVec)
{
pVec->get = vectorGet;
pVec->append = vectorAppend;
pVec->remove = vectorRemove;
pVec->clear = vectorClear;
// 初始情况下申请VECTOR_INIT_CAPACITY个element
pVec->pData = (void**)malloc(sizeof(void*) * VECTOR_INIT_CAPACITY);
pVec->capacity = VECTOR_INIT_CAPACITY;
pVec->size = 0;
}
void vectorDestroy(struct vector* pVec)
{
if (pVec->pData == NULL)
return;
free(pVec->pData);
pVec->pData = NULL;
pVec->size = 0;
pVec->capacity = 0;
}
更多推荐
已为社区贡献1条内容
所有评论(0)