EasyX
看这个
开头加上 graphic.h 头文件
绘图窗口与设备
initgraph(int width,int height,int flag=NULL);
initgraph(800,600,EX_NOMINIMIZE | EX_NOCLOSE); //创建禁用最小化和关闭按钮的绘图窗口
initgraph(800,600,EX_SHOWCONSOLE); //带控制台的图形窗口
结尾加上system("pause")或_getch()/*conio.h*/以显式看到画布
最后再加上closegraph()关闭画布
坐标
默认原点在设别的左上角,X轴向右为正,Y轴向下为正,单位是像素
void setorigin(int x,int y) //用于设置坐标原点
setaspectratio(float xasp,float yasp)
//通过设置 x 和 y 方向上的缩放因子,从而修改绘图的缩放比例或坐标轴方向
setaspectratio(2, 1); // x轴方向的缩放因子为2,y轴方向的缩放因子为1(默认值)
circle(100, 100, 100); //x轴方向长度为200,y轴长度为100
setaspectratio(1, -1); // 缩放因子为负数,可以实现坐标轴的翻转,此行可使y轴向上为正
我真是服了,都不许用setaspectratio(1, -1),这是人类能设计出来的吗
initgraph(400, 400);
setaspectratio(1, -1);
outtextxy(200, 200, "hello");
如上代码执行后什么都不会显示
initgraph(400, 400);
setaspectratio(1, -1);
outtextxy(200, -200, "hello");
上述执行后如图:

我真气笑了
update:好像确实是我的问题……应该先设置原点的
范例:
#include <graphics.h>
int main()
{
initgraph(600, 600);
setorigin(0, 600); // 将绘图窗口的左下角作为坐标原点
setaspectratio(1, -1); // 缩放因子为负数,可以实现坐标轴的翻转,此行可使y轴向上为正
circle(100, 100, 100);
system("pause");
closegraph();
return 0;
}
颜色
1.用预定义常量表示颜色(常量名要大写)
2.用16进制
3.RGB(0~255) eg:setlinecolor(RGB(2,2,2));
| 常量 | 值 | 颜色 |
|---|---|---|
| BLACK | 0 | 黑 |
| BLUE | 0xAA0000 | 蓝 |
| GREEN | 0x00AA00 | 绿 |
| CYAN | 0xAAAA00 | 青 |
| RED | 0x0000AA | 红 |
| MAGENTA | 0xAA00AA | 紫 |
| BROWN | 0x0055AA | 棕 |
| LIGHTGRAY | 0xAAAAAA | 浅灰 |
| DARKGRAY | 0x555555 | 深灰 |
| LIGHTBLUE | 0xFF5555 | 亮蓝 |
| LIGHTGREEN | 0x55FF55 | 亮绿 |
| LIGHTCYAN | 0xFFFF55 | 亮青 |
| LIGHTRED | 0x5555FF | 亮红 |
| LIGHTMAGENTA | 0xFF55FF | 亮紫 |
| YELLOW | 0x55FFFF | 黄 |
| WHITE | 0xFFFFFF | 白 |
EasyX图形绘制函数
| 函数用法 | 函数说明 |
|---|---|
| void circle ( int x, int y, int radius ) | 画无填充的圆 |
| fillcircle | 画有边框的填充圆 |
| solidcircle | 画无边框的填充圆 |
| clearcircle | 用当前背景色清空圆形区域 |
| void ellipse ( int left, int top, int right, int bottom ) | 画无填充的椭圆 |
| fillellipse | 画有边框的填充椭圆 |
| solidellipse | 画无边框的填充椭圆 |
| clearellipse | 用当前背景色清空椭圆区域 |
| void pie ( int left, int top, int right, int bottom, double stangle, double endangle ); | 画无填充的扇形 |
| fillpie | 画有边框的填充扇形 |
| solidpie | 画无边框的填充扇形 |
| clearpie | 用当前背景色清空扇形区域 |
| void rectangle ( int left, int top, int right, int bottom ) | 画无填充的矩形 |
| fillrectangle | 画有边框的填充矩形 |
| solidrectangle | 画无边框的填充矩形 |
| clearrectangle | 用当前背景色清空矩形区域 |
| void roundrect ( int left, int top, int right, int bottom, int ellipsewidth, int ellipseheight ) | 画无填充的圆角矩形 |
| fillroundrect | 画有边框的填充圆角矩形 |
| solidroundrect | 画无边框的填充圆角矩形 |
| clearroundrect | 用当前背景色清空圆角矩形区域 |
| void polygon ( const POINT *points, int num ); | 画无填充的多边形 |
| fillpolygon | 画有边框的填充多边形 |
| solidpolygon | 画无边框的填充多边形 |
| clearpolygon | 用当前背景色清空多边形区域 |
| 函数名称 | 函数说明 |
|---|---|
| void putpixel ( int x, int y, COLORREF color ) | 画点 |
| void line ( int x1, int y1, int x2, int y2 ) | 画直线 |
| void arc ( int left, int top, int right, int bottom, double stangle, double endangle ) | 画椭圆弧 |
| void polyline ( const POINT *points, int num ) | 画多条连续的直线 |
| void polybezier ( const POINT *points, int num ) | 画三次方贝塞尔曲线 |
| void floodfill ( int x, int y, COLORREF color, int filltype = FLOODFILLBORDER ) | 填充区域 |
| COLORREF getpixel ( int x, int y ) | 获取坐标点的颜色 |
| int getwidth ( ) | 获取绘图区的宽度 |
| int getheight ( ) | 获取绘图区的高度 |
| setlinecolor( COLOR ) | 设置线条颜色 |
| setfillcolor( COLOR ) | 设置填充颜色 |
| 函数:setlinestyle(PS_SOLID,10)设置线为实线(PS_SOLID),线宽为10 |
关于floodfill函数,第四个参数0表示 FLOODFILLBORDER,1表示FLOODFILLSURFACE,不写默认为0
对于 FLOODFILLBORDER 填充类型,填充动作以 (x, y) 为起点,向周围扩散,直到遇到 border 指定的颜色才会终止。指定的区域必须是封闭的。适用于填充具有固定颜色边界的区域。
对于 FLOODFILLSURFACE 填充类型,填充动作以 (x, y) 为起点,只要邻接的颜色为 color, 填充就会延伸。适用于填充具有多种颜色边界的区域。
在设置背景色之后,并不会改变现有背景色,而是只改变背景色的值
如果需要修改全部背景色,可以在设置背景色后执行 cleardevice() 函数。
所以,
setbkcolor(BLUE); //该语句执行后背景色不会发生实际变化
clearrectangle(350,400,550,500); //该语句执行用背景色清空矩形区域,矩形内为蓝色
EasyX文字输出
字符数组 TCHAR 当字符串用就可以
定义方式为: TCHAR = _T('A') TCHAR s[] = _T("Hello World")
赋值: TCHAR name[10]; _tcscpy_s(name,10,_T("张三"));
将int转化为字符串:TCHAR num[5]; _stprintf_s(num,_T("数字%d"),1024);
settextcolor(BLUE) 设置字体颜色
settextstyle(int height,int width,_T("宋体")) width可以直接填0,自适应,第三个参数是字体
void outtextxy(int x,int y,TCHAR) 在(x,y)位置输出字符串,(x,y)是这个文本框的左上角位置
textheight(text) 获取字符串的高度
textwidth(text) 获取字符串的宽度(不是一个字的宽度)
outtextxy(300 - w / 2, 300 - h / 2, text); // 在屏幕中心绘制文本
setbkmode(TRANSPARENT),透明背景;setbkmode(OPAQUE),背景用背景色填充(默认)
if (_kbhit()) break;
while (!_kbhit())
// 按任意键退出,_kbhit是非阻塞函数,可以终止类似while(1)的循环
添加音乐
把mp3文件放到项目文件夹里
1.引用Winmm.lib链接库
语法:#pragma comment(lib,"Winmm.lib")
2.播放音乐
语法:mciSendString(_T("open v2.mp3 alias bkmusic"),0,0,0); //alias指定别名,v2.mp3 == bkmusic
音乐名v2.mp3必须和程序文件中存储的音乐文件名称相同,否则调用失败
3.循环播放
语法:mciSendString(_T("play bkmusic repeat"),0,0,0); //重复播放bkmusic,即v2.mp3
4.停止播放
mciSendString(_T("close bkmusic"),0,0,0); 可以不写,直接叉掉
双缓冲绘图
双缓冲绘图通过在内存中创建一个与屏幕绘图区域一致的对象,先将图形绘制到内存中的这个对象上,再一次性将这个对象上的图形拷贝到屏幕上,从而减少对屏幕的直接绘图操作,提高绘图效率、消除屏幕闪烁
BeginBatchDraw() 开始批量绘图
EndBatchDraw() EndBatchDraw(int left,int top,int right,int bottom)(指定区域) 结束批量绘制,并执行未完成的绘制任务
FlushBatchDraw() FlushBatchDraw(int left,int top,int right,int bottom)(指定区域) 执行未完成的绘制任务
范例:自动移动的圆,可以把三条语句未注释和注释掉的对比一下,不使用缓冲会屏幕闪烁
#include <graphics.h>
int main()
{
initgraph(640, 480);
//BeginBatchDraw(); // 开启批量绘图
setlinecolor(WHITE); // 设置画线颜色
setfillcolor(RED); // 设置填充颜色
for (int i = 50; i < 600; i++)
{
cleardevice(); // 清屏
circle(i, 100, 40); // 绘制空心圆
floodfill(i, 100, WHITE); // 用红色填充,直到遇到边界为白色为止的区域
//FlushBatchDraw(); // 刷新批量绘图
Sleep(10); // 延时10毫秒
}
//EndBatchDraw(); // 关闭批量绘图
closegraph();
return 0;
}
关于时间的一些函数
控制帧数:
//include <windows.h>
#include <graphics.h>
int main()
{
initgraph(640, 480);
BeginBatchDraw();
setlinecolor(WHITE);
setfillcolor(RED);
for (int i = 50; i < 600; i++)
{
DWORD beginTime = GetTickCount(); // 记录循环开始时间
cleardevice();
circle(i, 100, 40);
floodfill(i, 100, WHITE);
FlushBatchDraw();
DWORD endTime = GetTickCount(); // 记录循环结束时间
DWORD elapsedTime = endTime - beginTime; // 计算循环耗时
if (elapsedTime < 1000 / 60) // 按每秒60帧进行补时
Sleep(1000 / 60 - elapsedTime);
}
EndBatchDraw();
closegraph();
return 0;
}
GetTickCount 是一个 Windows 系统函数,用于获取从操作系统启动以来所经过的毫秒数,通过在代码中的不同位置调用该函数,并计算两次调用之间的差值,可以得知某段代码或某个操作的执行时间。单位:毫秒

图像处理
把图片放到项目文件夹内

IMAGE p; //定义图片变量
p.getwidth(); p.getheight(); //IMAGE类具有内置函数获取宽高
loadimage(&图片变量名,"XX.jpg"/*图片名称*/,int width=0,int height=0); //载入图片
loadimage(NULL, _T("image\\background.jpg")); loadimage(NULL, _T("testt.jpg"), 700, 300,false);
// 第一个参数为NULL时,直接读取图片至绘图窗口
// 第五个参数若为 true,则会调整窗口以适应图片的大小
putimage(int x,int y,&图片变量名); //显示图片,xy是图片左上角的坐标
putimage(0, 0, 900, 600, &img, 115, 0); // 从图像的(115,0)坐标处截取宽900、高600的部分内容显示在窗口(0,0)处
Resize(&img, 600, 400); // 调整IMAGE的尺寸,注意不是缩放
putimage(0, 0, &img, NOTSRCCOPY);,第四个参数是三元光栅操作码

GetImageBuffer 函数,可以设置渐变背景色
#include <graphics.h>
int main()
{
initgraph(600, 400);
DWORD* pMem = GetImageBuffer(); // 获取当前窗口所指图像缓冲区的指针
for (int i = 0; i < 600 * 400; i++)
pMem[i] = BGR(RGB(0, 0, i * 256 / (600 * 400))); // 直接对图像缓冲区每个坐标像素赋值(颜色)
system("pause");
closegraph();
return 0;
}
透明贴图
通过PS制作原图的掩码图和前景图,再进行三元光栅操作叠加而成
#include <graphics.h>
int main()
{
IMAGE imgGuoqi, imgGuohui, imgGuohuiMask, imgGuohuiFg;
loadimage(&imgGuoqi, _T("guoqi.jpg"), 1000, 600); // 加载国旗(背景图)
loadimage(&imgGuohui, _T("guohui.jpg"), 200, 200); // 加载国徽原图(白色周边)
loadimage(&imgGuohuiMask, _T("guohui_mask.jpg"), 200, 200); // 加载国徽掩码图(白色周边+黑色内容)
loadimage(&imgGuohuiFg, _T("guohui_fg.jpg"), 200, 200); // 加载国徽前景图(黑色周边+待显示内容)
initgraph(1000, 600);
putimage(0, 0, &imgGuoqi); // 显示国旗
putimage(0, 0, &imgGuohui); // 显示国徽原图
putimage(0, 200, &imgGuohuiMask); // 显示国徽掩码图
putimage(0, 400, &imgGuohuiFg); // 显示国徽前景图
// 透明贴图
putimage(200, 0, &imgGuohuiMask, SRCAND); // 显示掩码图(SRCAND:按位与)
putimage(200, 0, &imgGuohuiFg, SRCPAINT); // 显示前景图(SRCPAINT:按位或)
system("pause");
closegraph();
return 0;
}
已经有透明底图片了,AlphaBlend 函数实现(推荐)
#include <graphics.h>
#pragma comment(lib, "MSIMG32.LIB") // 链接器在链接过程中包含指定的库文件
void putimage_alpha(int x, int y, IMAGE* img)
{
int w = img->getwidth();
int h = img->getheight();
AlphaBlend(GetImageHDC(NULL), x, y, w, h, GetImageHDC(img), 0, 0, w, h, { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA });
}
int main()
{
initgraph(1000, 600);
IMAGE imgGuoqi, imgBaidu;
loadimage(&imgGuoqi, _T("guoqi.jpg"), 1000, 600); // 加载国旗(背景图)
loadimage(&imgBaidu, _T("baidu.png")); // 加载百度LOGO(PNG格式),baidu.png已经是透明底了!!!
putimage(0, 0, &imgGuoqi); // 显示国旗
putimage(0, 0, &imgBaidu); // 显示百度LOGO
putimage_alpha(0, 300, &imgBaidu); // 显示百度LOGO(透明贴图),这个函数要自己写
system("pause");
closegraph();
return 0;
}

图片动画
是一系列静态的动画帧
#include <graphics.h>
#include <cstdio>
#pragma comment(lib, "MSIMG32.LIB")
const int WINDOW_WIDTH = 1000; //窗口宽度
const int WINDOW_HEIGHT = 600; //窗口高度
const int FRAME = 60; //帧数
const int INTERVAL_MS = 15; //动画帧间隔
const int IMAGE_NUM = 13; //动画图片数
/*
帧率是每秒屏幕刷新的速度,决定了动画的流畅度,确保显示稳定
动画帧间隔是决定图片切换的速度 时间间隔越短,角色动作越快;时间间隔越长,动作越慢。
INTERVAL_MS是代码层面的图片切换速度,实际显示出来的时间间隔还和帧率有关
因为屏幕刷新后新操作才会被呈现,如果在屏幕刷新前切换是不会被显示的
*/
//显示透明图片
void putimage_alpha(int x, int y, IMAGE* img)
{
int w = img->getwidth();
int h = img->getheight();
AlphaBlend(GetImageHDC(NULL), x, y, w, h, GetImageHDC(img), 0, 0, w, h, { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA });
}
int cnt = 0;
int main()
{
bool running = true; //主循环控制
IMAGE imgBackground; //背景图片对象
IMAGE imgPEA[13]; //玩家动画图片
TCHAR imgPath[256]; //动画图片文件路径
int imgIndex = 0; //动画帧索引
static int timer = 0; //动画计时器
loadimage(&imgBackground, _T("image\\background.jpg")); //加载背景图片
for (int i = 0; i < IMAGE_NUM; i++) //加载动画图片
{
_stprintf_s(imgPath, _T("image\\pea\\%d.png"), i + 1); //动画图片路径(格式转换)
loadimage(&imgPEA[i], imgPath); //加载动画图片
}
initgraph(WINDOW_WIDTH, WINDOW_HEIGHT);
BeginBatchDraw();
//主循环
while (running)
{
DWORD beginTime = GetTickCount();
//数据处理
timer += 5;
if (timer > INTERVAL_MS) //定时器超过预定的时间间隔时切换下一张图片
{
imgIndex = (imgIndex + 1) % IMAGE_NUM; //循环切换图片:索引值0-12
timer = 0; //重置计时器
}
//这是我自己写的,我认为这个程序每三帧切换一次图片,于是采用了cnt计数,运行后视觉效果没啥变化
//cnt++;
//if (cnt > 3) {
// imgIndex = (imgIndex + 1) % IMAGE_NUM;
// cnt = 0;
//}
//绘图
cleardevice();
putimage(0, 0, &imgBackground); //绘制背景图片
putimage_alpha(500, 300, &imgPEA[imgIndex]); //绘制豌豆图片
FlushBatchDraw();
//帧延时处理
DWORD endTime = GetTickCount();
DWORD elapsedTime = endTime - beginTime;
if (elapsedTime < 1000 / FRAME)
Sleep(1000 / FRAME - elapsedTime);
}
EndBatchDraw();
closegraph();
return 0;
}
消息处理
ExMessage 是一个结构体
函数:
ExMessage getmessage(BYTE filter=-1) void getmessage(ExMessage *msg,BYTE filter=-1)从消息缓冲区获取一个消息
bool peekmessage(ExMessage *msg,BYTE filter = -1, bool removemsg = true) 从消息缓冲区获取一个消息并立即返回
void flushmessage(BYTE filter = -1) 清空消息缓冲区
参数说明
msg:指向消息结构体 ExMessage 的指针,用来保存获取到的消息。
filter:指定要获取的消息范围,默认 -1 获取所有类别的消息。可以用以下值或值的组合获取指定类别的消息 具体的,EX_MOUSE鼠标消息,EX_KEY按键消息,EX_CHAR字符消息,EX_WINDOW窗口消息
removemsg:在 peekmessage 处理完消息后,是否将其从消息队列中移除。

鼠标消息
ExMessage m;
while (true) {
m = getmessage(EX_MOUSE);
if (m.message == WM_MOUSEMOVE) {
//...
}else if(m.message == WM_LBUTTONDOWN){
//...
}
}
////////////////////////////////////
ExMessage msg;
while (running) {
// 消息处理
while (peekmessage(&msg)) {
if (msg.message == WM_MOUSEMOVE) { // 圆的位置随鼠标位置变化
x = msg.x;
y = msg.y;
}
else if (msg.message == WM_LBUTTONDOWN) { // 左键按下圆变红色
setfillcolor(RED);
}
else if (msg.message == WM_LBUTTONUP) { // 左键松开圆变白色
setfillcolor(WHITE);
}
else if (msg.message == WM_RBUTTONDOWN) { // 右键按下结束主循环
running = false;
}
}
// 绘图
cleardevice(); // 清除屏幕
solidcircle(x, y, r); // 绘制当前帧内容
FlushBatchDraw(); // 刷新批量绘图
}
键盘消息
用键盘控制小球
typedef struct Ball
{
int x; // 小球圆心坐标x
int y; // 小球圆心坐标y
int r; // 小球半径
int dx; // 小球在x轴方向移动的增量
int dy; // 小球在y轴方向移动的增量
COLORREF color; // 小球颜色
} Ball;
int main()
{
bool running = true;
ExMessage msg;
Ball ball = { 300, 300, 20, 5, 5, YELLOW }; // 创建小球并初始化
initgraph(600, 600);
BeginBatchDraw();
while (running)
{
while (peekmessage(&msg))
{
if (msg.message == WM_KEYDOWN) //按键按下状态
{
switch (msg.vkcode) // 判断虚拟键代码
{
case 'w'://小写w // 上键:小球Y坐标减少
case 'W'://大写W
case VK_UP://箭头上
ball.y -= ball.dy;
break;
case 's':
case 'S':
case VK_DOWN: // 下键:小球Y坐标增加
ball.y += ball.dy;
break;
case 'a':
case 'A':
case VK_LEFT: // 右键:小球X坐标减少
ball.x -= ball.dx;
break;
case 'd':
case 'D':
case VK_RIGHT: // 右键:小球X坐标增加
ball.x += ball.dx;
break;
case VK_ESCAPE: // ESC键:结束主循环
running = false;
break;
}
}
}
cleardevice(); // 清除屏幕
setfillcolor(ball.color); // 设置填充颜色
solidcircle(ball.x, ball.y, ball.r); // 绘制无边框填充圆;
FlushBatchDraw();
}
EndBatchDraw();
closegraph();
return 0;
}
虚拟键代码 https://learn.microsoft.com/zh-cn/windows/win32/inputdev/virtual-key-codes
用键盘控制小球(支持斜向运动)
#include <graphics.h>
// 用结构体封装小球属性
typedef struct Ball
{
int x; // 小球圆心坐标x
int y; // 小球圆心坐标y
int r; // 小球半径
int dx; // 小球在x轴方向移动的增量
int dy; // 小球在y轴方向移动的增量
COLORREF color; // 小球颜色
bool isMoveUp = false; // 小球是否向四个方向移动
bool isMoveDown = false;
bool isMoveLeft = false;
bool isMoveRight = false;
} Ball;
int main()
{
bool running = true;
ExMessage msg;
Ball ball = { 300, 300, 20, 5, 5, YELLOW }; // 创建小球并初始化
initgraph(600, 600);
BeginBatchDraw();
while (running)
{
DWORD beginTime = GetTickCount(); // 记录循环开始时间
// 消息处理
while (peekmessage(&msg))
{
if (msg.message == WM_KEYDOWN) // 按下按键处理
{
switch (msg.vkcode)
{
case 'w':
case 'W':
case VK_UP:
ball.isMoveUp = true;
break;
case 's':
case 'S':
case VK_DOWN:
ball.isMoveDown = true;
break;
case 'a':
case 'A':
case VK_LEFT:
ball.isMoveLeft = true;
break;
case 'd':
case 'D':
case VK_RIGHT:
ball.isMoveRight = true;
break;
case VK_ESCAPE:
running = false;
break;
}
}
if (msg.message == WM_KEYUP) // 松开按键处理
{
switch (msg.vkcode)
{
case 'w':
case 'W':
case VK_UP:
ball.isMoveUp = false;
break;
case 's':
case 'S':
case VK_DOWN:
ball.isMoveDown = false;
break;
case 'a':
case 'A':
case VK_LEFT:
ball.isMoveLeft = false;
break;
case 'd':
case 'D':
case VK_RIGHT:
ball.isMoveRight = false;
break;
}
}
}
// 数据处理:根据小球的移动状态设置其坐标
if (ball.isMoveUp)
ball.y -= ball.dy;
if (ball.isMoveDown)
ball.y += ball.dy;
if (ball.isMoveLeft)
ball.x -= ball.dx;
if (ball.isMoveRight)
ball.x += ball.dx;
// 绘图
cleardevice(); // 清除屏幕
setfillcolor(ball.color); // 设置填充颜色
solidcircle(ball.x, ball.y, ball.r); // 绘制无边框填充圆;
FlushBatchDraw();
// 帧延时
DWORD endTime = GetTickCount(); // 记录循环结束时间
DWORD elapsedTime = endTime - beginTime; // 计算循环耗时
if (elapsedTime < 1000 / 60) // 按每秒60帧进行补时
Sleep(1000 / 60 - elapsedTime);
}
EndBatchDraw();
closegraph();
return 0;
}
该代码中需要帧延时,第一个程序中,有按键操作才会有移动,速度取决于按键速度;
(解释一下长按操作也会一直移动的原因:这是因为 Windows 系统的键盘自动重复机制在起作用,系统默认的重复率通常是每秒 30 次左右,这就限制了小球的最大移动速度)
而第二个程序中如果长按一个键,每次循环都为true都会移动,速度取决于刷新频率。
窗口碰撞检测
typedef struct Ball
{
int x; // 小球圆心坐标x
int y; // 小球圆心坐标y
int r; // 小球半径
int dx; // 小球在x轴方向移动的增量
int dy; // 小球在y轴方向移动的增量
COLORREF color; // 小球颜色
bool isMoveUp = false; // 小球是否向四个方向移动
bool isMoveDown = false;
bool isMoveLeft = false;
bool isMoveRight = false;
} Ball;
int main()
{
bool running = true;
ExMessage msg;
Ball ball = { 300, 300, 20, 5, 5, YELLOW }; // 创建小球并初始化
initgraph(WIN_WIDTH, WIN_HEIGHT);
BeginBatchDraw();
while (running)
{
DWORD beginTime = GetTickCount(); // 记录循环开始时间
// 消息处理
while (peekmessage(&msg))
{
if (msg.message == WM_KEYDOWN) // 按下按键处理
{
switch (msg.vkcode)
{
case 'w':
case 'W':
case VK_UP:
ball.isMoveUp = true;
break;
case 's':
case 'S':
case VK_DOWN:
ball.isMoveDown = true;
break;
case 'a':
case 'A':
case VK_LEFT:
ball.isMoveLeft = true;
break;
case 'd':
case 'D':
case VK_RIGHT:
ball.isMoveRight = true;
break;
case VK_ESCAPE:
running = false;
break;
}
}
if (msg.message == WM_KEYUP) // 松开按键处理
{
switch (msg.vkcode)
{
case 'w':
case 'W':
case VK_UP:
ball.isMoveUp = false;
break;
case 's':
case 'S':
case VK_DOWN:
ball.isMoveDown = false;
break;
case 'a':
case 'A':
case VK_LEFT:
ball.isMoveLeft = false;
break;
case 'd':
case 'D':
case VK_RIGHT:
ball.isMoveRight = false;
break;
}
}
}
// 斜向移动:计算不同方向(包括同时)按下时的速度增量
//if (ball.isMoveUp)
// ball.y -= ball.dy;
//if (ball.isMoveDown)
// ball.y += ball.dy;
//if (ball.isMoveLeft)
// ball.x -= ball.dx;
//if (ball.isMoveRight)
// ball.x += ball.dx;
// 斜向移动优化
int directX = ball.isMoveRight - ball.isMoveLeft;
int directY = ball.isMoveDown - ball.isMoveUp;
double directXY = sqrt(directX * directX + directY * directY);
if (directXY != 0)
{
double factorX = directX / directXY; //计算X、Y方向的标准化分量
double factorY = directY / directXY;
ball.x += (int)ball.dx * factorX; //小球坐标 = 方向增速 * 方向的标准化分量
ball.y += (int)ball.dy * factorY;
}
// 边缘检测
if (ball.y - ball.r <= 0) // 上
ball.y = ball.r;
if (ball.y + ball.r >= WIN_HEIGHT) // 下
ball.y = WIN_HEIGHT - ball.r - 1;
if (ball.x - ball.r <= 0) // 左
ball.x = ball.r;
if (ball.x + ball.r >= WIN_WIDTH) // 右
ball.x = WIN_WIDTH - ball.r - 1;
// 绘图
cleardevice(); // 清除屏幕
setfillcolor(ball.color); // 设置填充颜色
solidcircle(ball.x, ball.y, ball.r); // 绘制无边框填充圆;
FlushBatchDraw();
// 帧延时
DWORD endTime = GetTickCount(); // 记录循环结束时间
DWORD elapsedTime = endTime - beginTime; // 计算循环耗时
if (elapsedTime < 1000 / 60) // 按每秒60帧进行补时
Sleep(1000 / 60 - elapsedTime);
}
EndBatchDraw();
closegraph();
return 0;
}
设置窗口标题
HWND hWnd = GetHWnd(); // 获得窗口句柄
SetWindowText(hWnd, _T("植物大战僵尸")); // 使用 Windows API 修改窗口名称

浙公网安备 33010602011771号