作者共發了7篇帖子。 內容轉換:不轉換▼
 
點擊 回復
339 6
【程序】Invader Windows版
一派護法 十九級
1樓 發表于:2016-2-8 12:40



一派護法 十九級
2樓 發表于:2016-2-8 12:42
【C++代码】
【Invader.h】
#define _BV(n) (1 << (n))

#define COL_BLACK RGB(0, 0, 0)
#define COL_CYAN RGB(0, 0xff, 0xff)
#define COL_GREEN RGB(0, 0xff, 0)
#define COL_RED RGB(0xff, 0, 0)
#define COL_WHITE RGB(0xff, 0xff, 0xff)
#define COL_YELLOW RGB(0xff, 0xff, 0)

#define F_GAMEOVER _BV(0)

#define IDT_TIMER1 101

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT iTimerID, DWORD dwTime);
void gameover(void);
void invaders_move(void);
void keyboard_handler(WPARAM wParam);
void laser_move(void);
void next_group(void);
void putimg(HDC hdc, RECT *rcPaint, int x, int y, COLORREF color, LPCSTR imgstr);
void putstr(HDC hdc, int x, int y, LPCSTR str);
void restart(void);
void update(void);
void update_fighter(void);
void update_gameover(void);
void update_invader_hit(void);
void update_invaders(void);
void update_laser(void);
void update_score(void);
void wnd_paint(void);
一派護法 十九級
3樓 發表于:2016-2-8 12:42
【Invader.cpp】
#include <stdio.h>
#include <Windows.h>
#include "Invader.h"

static unsigned char charset[16 * 8] = {
    /* invader(0) */
    0x00, 0x00, 0x00, 0x43, 0x5f, 0x5f, 0x5f, 0x7f,
    0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x20, 0x3f, 0x00,

    /* invader(1) */
    0x00, 0x0f, 0x7f, 0xff, 0xcf, 0xcf, 0xcf, 0xff,
    0xff, 0xe0, 0xff, 0xff, 0xc0, 0xc0, 0xc0, 0x00,

    /* invader(2) */
    0x00, 0xf0, 0xfe, 0xff, 0xf3, 0xf3, 0xf3, 0xff,
    0xff, 0x07, 0xff, 0xff, 0x03, 0x03, 0x03, 0x00,

    /* invader(3) */
    0x00, 0x00, 0x00, 0xc2, 0xfa, 0xfa, 0xfa, 0xfe,
    0xf8, 0xf8, 0xf8, 0xf8, 0x00, 0x04, 0xfc, 0x00,

    /* fighter(0) */
    0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
    0x01, 0x43, 0x47, 0x4f, 0x5f, 0x7f, 0x7f, 0x00,

    /* fighter(1) */
    0x18, 0x7e, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xff,
    0xff, 0xff, 0xe7, 0xe7, 0xe7, 0xe7, 0xff, 0x00,

    /* fighter(2) */
    0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0xc2, 0xe2, 0xf2, 0xfa, 0xfe, 0xfe, 0x00,

    /* laser */
    0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00
};
/* invader:"abcd", fighter:"efg", laser:"h" */

HWND hWnd;
struct INVADER
{
    int fighter_x; // 自机的坐标
    int laser_x, laser_y; // 等离子炮弹的坐标
    int invaders_x, invaders_y; // 外星人群的坐标
    int invaders_direction; // 外星人群的移动方向
    int laserwait; // 等离子炮弹的剩余充电时间
    int movewait; // 为0时外星人群前进一步
    int movewait0; // movewait的初始值(消灭30只敌人后减少)
    int invaders_line; // 外星人群的行数
    int score; // 当前得分
    int high; // 最高得分
    int point; // 得分的增加量(奖金的单价)
    char invaders_str[32 * 6]; // 将外星人群的状态显示为字符串的变量
    int flags; // 游戏状态
} invader;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // 窗口的背景为黑色
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    wcex.hInstance = hInstance;
    wcex.lpfnWndProc = WndProc;
    wcex.lpszClassName = "WC_Invader";
    wcex.lpszMenuName = NULL;
    wcex.style = NULL;
    RegisterClassEx(&wcex);

    // 根据客户区大小计算窗口大小
    DWORD style = WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
    RECT rect;
    rect.left = rect.top = 0;
    rect.right = 323;
    rect.bottom = 227;
    AdjustWindowRect(&rect, style, NULL);

    HWND hWnd = CreateWindow(wcex.lpszClassName, "Invader", style, CW_USEDEFAULT, 0, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, hInstance, NULL);
    if (!hWnd)
        return 1;
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        ::hWnd = hWnd;
        restart();
        break;
    case WM_DESTROY:
        KillTimer(hWnd, IDT_TIMER1);
        PostQuitMessage(0);
        break;
    case WM_KEYDOWN:
        keyboard_handler(wParam);
        break;
    case WM_PAINT:
        wnd_paint();
        break;
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return FALSE;
}

void CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT iTimerID, DWORD dwTime)
{
    if (invader.laserwait != 0)
        invader.laserwait--; // 等离子炮的充电时间保证了每次只能发射一粒炮弹
    invaders_move();
    laser_move();
}

void gameover(void)
{
    KillTimer(hWnd, IDT_TIMER1);
    invader.flags |= F_GAMEOVER;
    update_gameover();
}

void invaders_move(void)
{
    if (invader.movewait != 0)
    {
        invader.movewait--;
        return;
    }
    invader.movewait = invader.movewait0;
    if (invader.invaders_x + invader.invaders_direction > 14 || invader.invaders_x + invader.invaders_direction < 0)
    {
        if (invader.invaders_y + invader.invaders_line == 13)
        {
            gameover();
            return;
        }
        invader.invaders_direction = -invader.invaders_direction;
        invader.invaders_y++;
    }
    else
        invader.invaders_x += invader.invaders_direction;
    update_invaders();
}

void keyboard_handler(WPARAM wParam)
{
    switch (wParam)
    {
    case 0x0d:
        // enter
        if (invader.flags & F_GAMEOVER)
        {
            invader.flags &= ~F_GAMEOVER;
            restart();
            update();
        }
        break;
    case 0x20:
    case 0x26:
        // space
        if (invader.laserwait == 0)
        {
            invader.laserwait = 15;
            invader.laser_x = invader.fighter_x + 1;
            invader.laser_y = 13;
        }
        break;
    case 0x25:
    case 0x64:
        // left
        if (invader.fighter_x > 0)
        {
            invader.fighter_x--;
            update_fighter();
        }
        break;
    case 0x27:
    case 0x66:
        // right
        if (invader.fighter_x < 37)
        {
            invader.fighter_x++;
            update_fighter();
        }
    }
}

void laser_move(void)
{
    if (invader.laser_y <= 0)
        return; // 如果invader.laser_y已经降至0, 则不执行任何操作

    invader.laser_y--;
    update_laser();
    if (invader.laser_y == 0)
    {
        // 当invader.laser_y降至0的瞬间
        invader.point -= 10;
        if (invader.point <= 0)
            invader.point = 1;
    }
    if (invader.invaders_x < invader.laser_x && invader.laser_x < invader.invaders_x + 25 && invader.invaders_y <= invader.laser_y && invader.laser_y < invader.invaders_y + invader.invaders_line)
    {
        int pos = (invader.laser_y - invader.invaders_y) * 32 + invader.laser_x - invader.invaders_x;
        if (invader.invaders_str[pos] != ' ')
        {
            // 击中
            invader.score += invader.point;
            invader.point++;
            if (invader.high < invader.score)
                invader.high = invader.score;
            update_score();
            while (pos >= 0 && invader.invaders_str[pos] != ' ')
                pos--; // pos的最小值为-1
           
            memset(&invader.invaders_str[pos + 1], ' ', 4);
            update_invader_hit();
           
            while (invader.invaders_line > 0)
            {
                for (pos = (invader.invaders_line - 1) * 32; invader.invaders_str[pos] != '\0'; pos++)
                {
                    if (invader.invaders_str[pos] != ' ')
                    {
                        // 有存活的情况下
                        invader.laser_y = 0;
                        return;
                    }
                }
                invader.invaders_line--;
            }

            // 全部消灭的情况下
            invader.movewait0 -= invader.movewait0 / 3; // 加速
            next_group();
            update_invaders();
        }
    }
}

void next_group(void)
{
    static char invader_str0[32] = " abcd abcd abcd abcd abcd ";
    invader.invaders_x = 7;
    invader.invaders_y = 1;
    invader.invaders_line = 6;
    invader.laser_y = 0;
    invader.movewait = invader.movewait0;
    invader.invaders_direction = 1;

    int i, j;
    for (i = 0; i < invader.invaders_line; i++)
    {
        for (j = 0; j < 27; j++)
            invader.invaders_str[i * 32 + j] = invader_str0[j];
    }
}

void putimg(HDC hdc, RECT *rcPaint, int x, int y, COLORREF color, LPCSTR imgstr)
{
    x *= 8;
    y *= 16;

    int i, j;
    int x0, y0;
    while (*imgstr != '\0')
    {
        if (x > rcPaint->right)
            return;
        if (*imgstr >= 'a' && *imgstr <= 'h')
        {
            int pos = 16 * (*imgstr - 'a');
            for (i = 0; i < 16; i++)
            {
                if ((y0 = y + i) > rcPaint->bottom)
                    break;
                if (y0 < rcPaint->top)
                    continue;
                for (j = 0; j < 8; j++)
                {
                    if ((x0 = x + j) > rcPaint->right)
                        break;
                    if (x0 < rcPaint->left)
                        continue;
                    if (charset[pos + i] & _BV(7 - j))
                        SetPixel(hdc, x0, y0, color);
                }
            }
        }
        imgstr++;
        x += 8;
    }
}

void putstr(HDC hdc, int x, int y, LPCSTR str)
{
    TextOut(hdc, x * 8, y * 16, str, strlen(str));
}

void restart(void)
{
    invader.score = 0;
    invader.point = 1;
    invader.movewait0 = 20;
    invader.fighter_x = 18;
    next_group();
    SetTimer(hWnd, IDT_TIMER1, 40, TimerProc);
}

// 更新整个游戏画面
void update(void)
{
    RECT rect;
    GetClientRect(hWnd, &rect);
    InvalidateRect(hWnd, &rect, TRUE);
}

// 更新自机部分的画面
void update_fighter(void)
{
    // 擦除屏幕上y>=208的区域并重新绘制
    RECT rect;
    GetClientRect(hWnd, &rect);
    rect.top = 208;
    InvalidateRect(hWnd, &rect, TRUE);
}

// 更新GAME OVER文字
void update_gameover(void)
{
    RECT rect;
    rect.left = 120;
    rect.top = 96;
    rect.right = 264;
    rect.bottom = 112;
    InvalidateRect(hWnd, &rect, TRUE);
}

// 更新击中的外星人那一行画面
void update_invader_hit(void)
{
    RECT rect;
    GetClientRect(hWnd, &rect);
    rect.top = invader.laser_y * 16;
    rect.bottom = rect.top + 16;
    InvalidateRect(hWnd, &rect, FALSE);
}

// 更新显示全部外星人的那部分画面
void update_invaders(void)
{
    RECT rect;
    GetClientRect(hWnd, &rect);
    rect.top = 16;
    rect.bottom = 207;
    InvalidateRect(hWnd, &rect, FALSE);
}

// 更新等离子炮弹那部分画面
void update_laser(void)
{
    RECT rect;
    rect.left = invader.laser_x * 8;
    rect.top = invader.laser_y * 16;
    rect.right = rect.left + 8;
    rect.bottom = rect.top + 32;
    InvalidateRect(hWnd, &rect, FALSE);
}

// 更新显示得分信息的那部分画面
void update_score(void)
{
    RECT rect;
    GetClientRect(hWnd, &rect);
    rect.bottom = 16;
    InvalidateRect(hWnd, &rect, FALSE);
}

// 窗口绘制
void wnd_paint(void)
{
    RECT rect;
    GetClientRect(hWnd, &rect);
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);
    HDC hdcMem = CreateCompatibleDC(hdc);
    HBITMAP hbmpMem = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
    SelectObject(hdcMem, hbmpMem);
   
    // 绘制分数
    SetBkColor(hdcMem, COL_BLACK);
    if (ps.rcPaint.top <= 16)
    {
        char str[15];
        SetTextColor(hdcMem, COL_WHITE);
        sprintf_s(str, "HIGH:%08d", invader.high);
        putstr(hdcMem, 22, 0, str);
        sprintf_s(str, "SCORE:%08d", invader.score);
        putstr(hdcMem, 4, 0, str);
    }

    // 绘制外星人
    int i;
    for (i = 0; i < invader.invaders_line; i++)
    {
        putimg(hdcMem, &ps.rcPaint, invader.invaders_x, invader.invaders_y + i, COL_GREEN, invader.invaders_str + i * 32);
    }

    putimg(hdcMem, &ps.rcPaint, invader.fighter_x, 13, COL_CYAN, "efg"); // 绘制自机
    if (invader.laser_y > 0) // 确保炮弹不会出现在显示分数的那一栏
        putimg(hdcMem, &ps.rcPaint, invader.laser_x, invader.laser_y, COL_YELLOW, "h"); // 绘制炮弹

    // 绘制GAME OVER字样
    if (invader.flags & F_GAMEOVER)
    {
        SetTextColor(hdcMem, COL_RED);
        putstr(hdcMem, 15, 6, "GAME OVER");
    }

    BitBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, hdcMem, rect.left, rect.top, SRCCOPY);
    EndPaint(hWnd, &ps);
    DeleteDC(hdcMem);
    DeleteObject(hbmpMem);
}
一派護法 十九級
4樓 發表于:2016-2-8 12:51
一派護法 十九級
5樓 發表于:2016-2-8 12:56
纸娃娃系统版的invader.hrb大小为2335字节(2.28KB),然而编译出来的Windows版本却是67584字节(66.0KB),比纸娃娃系统本身还大。。。
一派護法 十九級
6樓 發表于:2016-2-8 13:43
一派護法 十九級
7樓 發表于:2016-2-8 13:59

回復帖子

內容:
用戶名: 您目前是匿名發表
驗證碼:
(快捷鍵:Ctrl+Enter)
 

本帖信息

點擊數:339 回複數:6
評論數: ?
作者:巨大八爪鱼
最後回復:巨大八爪鱼
最後回復時間:2016-2-8 13:59
 
©2010-2024 Arslanbar Ver2.0
除非另有聲明,本站採用創用CC姓名標示-相同方式分享 3.0 Unported許可協議進行許可。