//-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;
}