//-mwindows -lgdi32
#include <windows.h>
#include <stdlib.h>
#include <time.h>
// 定义游戏窗口宽度
#define WIDTH 400
// 定义游戏窗口高度
#define HEIGHT 600
// 玩家飞机X坐标,初始水平居中
int playerX = WIDTH/2 - 15;
// 玩家飞机Y坐标,初始位于窗口下方
int playerY = HEIGHT - 80;
// 玩家飞机宽度
int playerW = 30;
// 玩家飞机高度
int playerH = 40;
// 定义最大子弹数量
#define MAX_BULLET 50
// 存储所有子弹的X坐标
int bulletX[MAX_BULLET];
// 存储所有子弹的Y坐标
int bulletY[MAX_BULLET];
// 子弹飞行速度
int bulletSpeed = 15;
// 定义最大敌机数量
#define MAX_ENEMY 8
// 存储所有敌机的X坐标
int enemyX[MAX_ENEMY];
// 存储所有敌机的Y坐标
int enemyY[MAX_ENEMY];
// 敌机宽度
int enemyW = 25;
// 敌机高度
int enemyH = 25;
// 敌机移动速度
int enemySpeed = 3;
// 游戏得分
int score = 0;
// 游戏结束标记,0=游戏中,1=游戏结束
int gameOver = 0;
// 内存绘图DC,用于双缓冲防止闪烁
HDC memDC;
// 内存位图,作为离屏画布
HBITMAP memBitmap;
// 游戏初始化函数
void GameInit()
{
// 分数清零
score = 0;
// 游戏状态设为进行中
gameOver = 0;
// 飞机X复位到中间
playerX = WIDTH/2 - 15;
// 飞机Y复位到下方
playerY = HEIGHT - 80;
// 遍历所有子弹,将其移出屏幕隐藏
for(int i=0; i<MAX_BULLET; i++) bulletY[i] = -100;
// 遍历所有敌机,随机生成位置
for(int i=0; i<MAX_ENEMY; i++)
{
enemyX[i] = rand()%(WIDTH-enemyW);
enemyY[i] = -rand()%500 - 50;
}
}
// 创建双缓冲画布
void CreateCanvas(HWND hWnd)
{
// 获取窗口DC
HDC hdc = GetDC(hWnd);
// 创建兼容内存DC
memDC = CreateCompatibleDC(hdc);
// 创建兼容位图作为画布
memBitmap = CreateCompatibleBitmap(hdc, WIDTH, HEIGHT);
// 将位图选入内存DC
SelectObject(memDC, memBitmap);
// 释放窗口DC
ReleaseDC(hWnd, hdc);
}
// 绘制玩家飞机
void DrawPlayer(HDC hdc)
{
// 创建青色画刷
HBRUSH body = CreateSolidBrush(RGB(0,255,255));
// 将画刷选入DC
SelectObject(hdc, body);
// 绘制椭圆形机身
Ellipse(hdc, playerX, playerY, playerX+playerW, playerY+playerH);
// 创建橙色画刷
HBRUSH wing = CreateSolidBrush(RGB(255,100,0));
// 将画刷选入DC
SelectObject(hdc, wing);
// 绘制左侧机翼
Rectangle(hdc, playerX-8, playerY+15, playerX, playerY+25);
// 绘制右侧机翼
Rectangle(hdc, playerX+30, playerY+15, playerX+38, playerY+25);
// 删除画刷释放资源
DeleteObject(body);
DeleteObject(wing);
}
// 绘制所有子弹
void DrawBullet(HDC hdc)
{
// 创建黄色画刷
HBRUSH b = CreateSolidBrush(RGB(255,255,0));
SelectObject(hdc, b);
// 遍历所有子弹
for(int i=0; i<MAX_BULLET; i++)
{
// 如果子弹在屏幕内则绘制
if(bulletY[i] > 0)
Rectangle(hdc, bulletX[i], bulletY[i], bulletX[i]+3, bulletY[i]+10);
}
// 删除画刷
DeleteObject(b);
}
// 绘制所有敌机
void DrawEnemy(HDC hdc)
{
// 创建红色画刷
HBRUSH e = CreateSolidBrush(RGB(255,0,0));
SelectObject(hdc, e);
// 遍历敌机并绘制
for(int i=0; i<MAX_ENEMY; i++)
{
Ellipse(hdc, enemyX[i], enemyY[i], enemyX[i]+enemyW, enemyY[i]+enemyH);
}
// 删除画刷
DeleteObject(e);
}
// 子弹移动逻辑
void BulletMove()
{
// 遍历所有子弹
for(int i=0; i<MAX_BULLET; i++)
{
// 子弹向上移动
if(bulletY[i] > 0) bulletY[i] -= bulletSpeed;
}
}
// 敌机移动逻辑
void EnemyMove()
{
// 遍历所有敌机
for(int i=0; i<MAX_ENEMY; i++)
{
// 敌机向下移动
enemyY[i] += enemySpeed;
// 敌机飞出屏幕底部则重新从上方出现
if(enemyY[i] > HEIGHT)
{
enemyX[i] = rand()%(WIDTH-enemyW);
enemyY[i] = -50;
}
}
}
// 鼠标发射子弹函数
void MouseFire()
{
// 游戏结束时不发射
if(gameOver) return;
// 寻找空闲子弹槽
for(int i=0; i<MAX_BULLET; i++)
{
if(bulletY[i] < 0)
{
// 设置子弹X在飞机中间
bulletX[i] = playerX + playerW/2 - 2;
// 设置子弹Y在飞机上方
bulletY[i] = playerY - 5;
break;
}
}
}
// 碰撞检测函数
void CheckHit()
{
// 检测子弹与敌机碰撞
for(int i=0; i<MAX_BULLET; i++)
{
// 跳过未使用的子弹
if(bulletY[i] < 0) continue;
for(int j=0; j<MAX_ENEMY; j++)
{
// 判断矩形相交
if(bulletX[i]+3 > enemyX[j] && bulletX[i] < enemyX[j]+enemyW &&
bulletY[i] < enemyY[j]+enemyH && bulletY[i]+10 > enemyY[j])
{
// 子弹隐藏
bulletY[i] = -100;
// 敌机重新生成
enemyX[j] = rand()%(WIDTH-enemyW);
enemyY[j] = -50;
// 分数+1
score++;
}
}
}
// 检测玩家与敌机碰撞
for(int j=0; j<MAX_ENEMY; j++)
{
if(playerX < enemyX[j]+enemyW && playerX+playerW > enemyX[j] &&
playerY < enemyY[j]+enemyH && playerY+playerH > enemyY[j])
{
// 游戏结束
gameOver = 1;
}
}
}
// 玩家飞机移动函数(无卡顿)
void MovePlayer()
{
// 游戏结束不处理移动
if(gameOver) return;
// 移动速度
int speed = 6;
// 上键按下
if(GetAsyncKeyState('W') & 0x8000) playerY -= speed;
// 下键按下
if(GetAsyncKeyState('S') & 0x8000) playerY += speed;
// 左键按下
if(GetAsyncKeyState('A') & 0x8000) playerX -= speed;
// 右键按下
if(GetAsyncKeyState('D')& 0x8000) playerX += speed;
// 边界限制:左边
if(playerX < 0) playerX = 0;
// 边界限制:右边
if(playerX > WIDTH - playerW) playerX = WIDTH - playerW;
// 边界限制:上边
if(playerY < 0) playerY = 0;
// 边界限制:下边
if(playerY > HEIGHT - playerH) playerY = HEIGHT - playerH;
}
// 窗口消息回调函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HFONT font;
switch(msg)
{
// 窗口创建消息
case WM_CREATE:
// 创建字体
font = CreateFont(20,0,0,0,FW_BOLD,0,0,0,0,0,0,0,0,"黑体");
// 创建画布
CreateCanvas(hWnd);
// 初始化游戏
GameInit();
// 设置定时器,25ms刷新一次
SetTimer(hWnd, 1, 25, NULL);
break;
// 定时器消息
case WM_TIMER:
// 实时移动飞机
MovePlayer();
if(!gameOver)
{
// 子弹移动
BulletMove();
// 敌机移动
EnemyMove();
// 碰撞检测
CheckHit();
}
// 刷新窗口
InvalidateRect(hWnd, NULL, FALSE);
break;
// 鼠标左键按下
case WM_LBUTTONDOWN:
// 调用发射子弹
MouseFire();
break;
// 窗口绘图消息
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// 创建黑色画刷
HBRUSH black = CreateSolidBrush(RGB(0,0,0));
SelectObject(memDC, black);
// 绘制黑色背景
Rectangle(memDC, 0,0, WIDTH,HEIGHT);
DeleteObject(black);
// 绘制飞机
DrawPlayer(memDC);
// 绘制子弹
DrawBullet(memDC);
// 绘制敌机
DrawEnemy(memDC);
// 设置字体
SelectObject(memDC, font);
// 设置文字颜色白色
SetTextColor(memDC, RGB(255,255,255));
// 设置文字背景透明
SetBkMode(memDC, TRANSPARENT);
char buf[50];
// 格式化分数字符串
wsprintf(buf, "得分:%d", score);
// 输出分数
TextOutA(memDC, 10,10, buf, lstrlen(buf));
// 如果游戏结束,显示文字
if(gameOver)
{
TextOutA(memDC, WIDTH/2-40, HEIGHT/2, "游戏结束", 8);
}
// 将内存画布复制到窗口
BitBlt(hdc,0,0,WIDTH,HEIGHT, memDC,0,0,SRCCOPY);
EndPaint(hWnd, &ps);
break;
}
// 键盘按键按下
case WM_KEYDOWN:
// 游戏结束后按任意键重新开始
if(gameOver) GameInit();
break;
// 窗口销毁
case WM_DESTROY:
// 关闭定时器
KillTimer(hWnd,1);
// 删除位图
DeleteObject(memBitmap);
// 删除内存DC
DeleteDC(memDC);
// 删除字体
DeleteObject(font);
// 退出程序
PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd,msg,wParam,lParam);
}
// 程序入口函数
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmd, int nShow)
{
// 设置随机数种子
srand((unsigned)time(NULL));
// 定义窗口类
WNDCLASSA wc = {0};
wc.lpfnWndProc = WndProc;
wc.hInstance = hInst;
wc.lpszClassName = "PlaneGame";
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
// 注册窗口类
RegisterClassA(&wc);
// 创建窗口
HWND hWnd = CreateWindowA(
"PlaneGame","方向键移动 + 鼠标左键射击",
WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX,
100,100, WIDTH+16, HEIGHT+38,
NULL,NULL,hInst,NULL
);
// 显示窗口
ShowWindow(hWnd,nShow);
// 更新窗口
UpdateWindow(hWnd);
// 消息循环
MSG msg;
while(GetMessage(&msg,0,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}