基于EasyX和Raylib的推箱子

基于 EasyX

// 根据《C和C++游戏趣味编程》第九章 推箱子 写出

#include <graphics.h>
#include <conio.h> // _kbhit()
#include <stdio.h>
#include <stdlib.h>

// 玩家位置
struct Player
{
    int i;
    int j;
};

// 全局变量

// 空白区域 empty       e
// 墙壁     wall        w
// 箱子     box         b
// 空白目标 target      t
// 完成目标 achieved    a
// 游戏角色 player      p
char blocks[8][8] = {
    { 'w', 'w', 'w', 'w', 'w', 'w', 'w', 'w' },
    { 'w', 'w', 'w', 't', 'b', 'e', 'e', 'w' },
    { 'w', 'e', 'e', 'e', 'e', 'e', 'e', 'w' },
    { 'w', 'e', 'e', 'e', 'e', 'e', 'e', 'w' },
    { 'w', 'e', 'e', 'e', 'e', 'e', 'e', 'w' },
    { 'w', 'e', 'e', 'p', 'a', 'e', 'e', 'w' },
    { 'w', 'e', 'e', 'e', 'w', 'w', 'w', 'w' },
    { 'w', 'w', 'w', 'w', 'w', 'w', 'w', 'w' },
};

#define BLOCK_SIZE 60
#define HEIGHT 8
#define WIDTH 8
#define GRAY RGB(150, 150, 150)
bool window_should_close = false;
#define SCORE_BOARD_HEIGHT 40

Player player;

int targetNum;
int achievedNum;

#define LEVEL_TOTALNUM 5 // 一共多少关卡
int currentLevelNum = 0; // 当前玩到第几关

char levels[LEVEL_TOTALNUM][8][9] = {
    {"wwwwwwww","wwwtbeew","weeeeeew","weeeeeew",
    "weeeeeew","wepbteew","weeewwww","wwwwwwww"}, // 第1关
    {"wwwwwwww","wwweewww","wpetbwww","weeebeww",
    "wewteeww","weeeeeww","weepwwww","wwwwwwww"}, // 第2关
    {"wwwwwwww","wwpeewww","weeweeww","webabeww",
    "weeteeww","wwetewww","wwwwwwww","wwwwwwww"}, // 第3关
    {"wwwwwwww","wwwwwwww","weeeewww","weeettew",
    "webbbpew","weewetww","wwwwwwww","wwwwwwww"}, // 第4关
    {"wwwwwwww","wwwwwwww","wwteewww","weewebpw",
    "weewewew","weaeebtw","weeeewww","wwwwwwww"}  // 第5关
};

void startup()
{
    initgraph(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE + SCORE_BOARD_HEIGHT, SHOWCONSOLE);
    setbkcolor(RGB(150, 150, 150));
    BeginBatchDraw();

    targetNum = 0;
    achievedNum = 0;
    for (int i = 0; i < HEIGHT; i++)
    {
        for (int j = 0; j < WIDTH; j++)
        {
            blocks[i][j] = levels[currentLevelNum][i][j];

            if (blocks[i][j] == 'p')
            {
                player.i = i;
                player.j = j;
                blocks[i][j] = 'e';
            }
            if (blocks[i][j] == 't' || blocks[i][j] == 'a')
            {
                targetNum++;
            }
        }
    }
}

void show()
{
    cleardevice();

    for (int i = 0; i < HEIGHT; i++)
    {
        for (int j = 0; j < WIDTH; j++)
        {
            if (blocks[i][j] == 'e') // empty
            {
                setfillcolor(RGB(150, 150, 150));
                setlinecolor(RGB(150, 150, 150));
                fillrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE);
            }
            else if (blocks[i][j] == 'w') // wall
            {
                setfillcolor(RGB(150, 0, 0));
                setlinecolor(RGB(150, 150, 150));
                fillrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE);
            }
            else if (blocks[i][j] == 'b') // box
            {
                setfillcolor(RGB(255, 255, 0));
                setlinecolor(RGB(150, 150, 150));
                fillrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE);
            }
            else if (blocks[i][j] == 't') // target
            {
                setfillcolor(RGB(250, 250, 250));
                fillrectangle((j + 0.3) * BLOCK_SIZE, (i + 0.3) * BLOCK_SIZE, (j + 0.7) * BLOCK_SIZE, (i + 0.7) * BLOCK_SIZE);
            }
            else if (blocks[i][j] == 'a') // achieved
            {
                setlinecolor(RGB(150, 150, 150));
                setfillcolor(RGB(255, 255, 0));
                fillrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE);
                setfillcolor(RGB(250, 250, 250, 250));
                fillrectangle((j + 0.3) * BLOCK_SIZE, (i + 0.3) * BLOCK_SIZE, (j + 0.7) * BLOCK_SIZE, (i + 0.7) * BLOCK_SIZE);
            }
        }
    }

    // 绘制玩家
    {
        // 红色圆脸
        int i = player.i;
        int j = player.j;
        setfillcolor(RGB(255, 0, 0));
        fillcircle((j + 0.5) * BLOCK_SIZE, (i + 0.5) * BLOCK_SIZE, 0.4 * BLOCK_SIZE);
        
        // 两个黑色眼睛
        setfillcolor(RGB(80, 80, 80));
        setlinecolor(RGB(80, 80, 80));
        fillcircle((j + 0.3) * BLOCK_SIZE, (i + 0.45) * BLOCK_SIZE, 0.08 * BLOCK_SIZE);
        fillcircle((j + 0.7) * BLOCK_SIZE, (i + 0.45) * BLOCK_SIZE, 0.08 * BLOCK_SIZE);
        
        // 嘴巴
        setlinestyle(PS_SOLID, 3);
        line((j + 0.35) * BLOCK_SIZE, (i + 0.7) * BLOCK_SIZE, (j + 0.65) * BLOCK_SIZE, (i + 0.7) * BLOCK_SIZE);
        setlinestyle(PS_SOLID, 1);
    }

    // 绘制关卡信息
    {
        char txt[50] = { 0 };
        sprintf(txt, "第%d关", currentLevelNum + 1);
        settextcolor(RGB(0,255,100)); // 设置字体颜色
        settextstyle(30, 0, _T("Consolas")); // 设置字体大小、样式
        outtextxy(120, HEIGHT * BLOCK_SIZE + 10, txt);
    }

    if (achievedNum == targetNum) // 如完成目标个数==目标个数
    {
        setbkmode(TRANSPARENT); // 透明显示文字
        settextcolor(RGB(0,255,100)); // 设置字体颜色
        TCHAR str[20];  // 定义字符数组
        if (currentLevelNum < LEVEL_TOTALNUM - 1) // 还有未完成的关卡可以玩
        {           
            settextstyle(50, 0, _T("Consolas")); // 设置字体大小、样式
            _stprintf(str, _T("开始第%d关"),currentLevelNum+2); // 提示开始第几关游戏
            outtextxy(120, 160, str); // 显示游戏胜利文字
            outtextxy(10, 250, _T("按空格键重玩当前关")); // 显示提示文字
        }
        else // 所有关卡都完成了
        {
            settextstyle(80, 0, _T("Consolas")); // 设置字体大小、样式
            outtextxy(80,200,_T("You win")); // 显示游戏胜利文字
        }       
        FlushBatchDraw(); // 开始批量绘制
        Sleep(2500); // 提示信息显示暂停
    }
    FlushBatchDraw();
}

bool WindowShouldClose()
{
    ExMessage m;
    //getmessage(&m, EX_MOUSE | EX_KEY);

    peekmessage(&m);

    switch (m.message)
    {
    case WM_KEYDOWN:
        switch (m.vkcode)
        {
        case VK_ESCAPE:
            window_should_close = true;
            break;
        }
        break;
    case WM_CLOSE:
        //window_should_close = true;
        break;
    case WM_DESTROY:
        //window_should_close = true;
        break;
    }

    return window_should_close;
}

void updateWithInput()
{
    if (kbhit() && (achievedNum < targetNum))
    {
        char input = getch();
        if (input == 'q')
        {
            window_should_close = true;
            return;
        }
        if (input =='  ') // 如果按下空格键,这一关重新开始
            startup(); 

        if (input == 'a' || input == 'd' || input == 's' || input == 'w')
        {
            int goal_i = player.i;
            int goal_j = player.j;
            int goalNext_i = goal_i;
            int goalNext_j = goal_j;
            if (input == 'a')
            {
                goal_j = player.j - 1;
                goalNext_j = goal_j - 1;
            }
            else if (input == 'd')
            {
                goal_j = player.j + 1;
                goalNext_j = goal_j + 1;
            }
            else if (input == 'w')
            {
                goal_i = player.i - 1;
                goalNext_i = goal_i - 1;
            }
            else if (input == 's')
            {
                goal_i = player.i + 1;
                goalNext_i = goal_i + 1;
            }

            if (blocks[goal_i][goal_j] == 'e' || blocks[goal_i][goal_j] == 't')
            {
                // 目标位置是 empty 或 target, 可以移动
                player.i = goal_i;
                player.j = goal_j;
            }
            else if (blocks[goal_i][goal_j] == 'b' && blocks[goalNext_i][goalNext_j] == 'e')
            {
                // 目标位置是 box, 再后面一个位置是 empty。可以推动箱子,并让玩家移动
                player.i = goal_i;
                player.j = goal_j;
                blocks[goal_i][goal_j] = 'e';
                blocks[goalNext_i][goalNext_j] = 'b';
            }
            else if (blocks[goal_i][goal_j] == 'b' && blocks[goalNext_i][goalNext_j] == 't')
            {
                // 目标位置是 box, 再后面一个位置是 target, 可以推动箱子, 并让玩家移动
                player.i = goal_i;
                player.j = goal_j;
                blocks[goal_i][goal_j] = 'e';
                blocks[goalNext_i][goalNext_j] = 'a';
            }
            else if (blocks[goal_i][goal_j] == 'a' && blocks[goalNext_i][goalNext_j] == 'e')
            {
                // 目标位置是 achieved, 再后面一个位置是 empty, 可以让玩家移动, 并推走箱子
                player.i = goal_i;
                player.j = goal_j;
                blocks[goal_i][goal_j] = 't';
                blocks[goalNext_i][goalNext_j] = 'b';
            }
            else if (blocks[goal_i][goal_j] == 'a' && blocks[goalNext_i][goalNext_j] == 't')
            {
                // 目标位置是 achieved, 再后面一个位置是 target, 可以让玩家移动, 并推走箱子
                player.i = goal_i;
                player.j = goal_j;
                blocks[goal_i][goal_j] = 't';
                blocks[goalNext_i][goalNext_j] = 'a';
            }
        }

        achievedNum = 0;
        for (int i = 0; i < HEIGHT; i++)
        {
            for (int j = 0; j < WIDTH; j++)
            {
                if (blocks[i][j] == 'a')
                {
                    achievedNum++;
                }
            }
        }

        // 当前关卡完成了
        if (achievedNum == targetNum)
        {
            show(); // 显示游戏胜利画面
            if (currentLevelNum < LEVEL_TOTALNUM - 1)
            {
                currentLevelNum++; // 进入下一关
                startup();
            }
        }
    }
}

void updateWithoutInput()
{

}

int main()
{
    startup();

    while (!window_should_close)
    {
        updateWithInput();
        updateWithoutInput();

        show();
    }

    closegraph();

    return 0;
}

基于 Raylib

// 根据《C和C++游戏趣味编程》第九章 推箱子 写出

#include "raylib.h"
#include <stdio.h>
#include <stdlib.h>
#include "raylib_helper.hpp"

// 玩家位置
struct Player
{
    int i;
    int j;
};

// 全局变量

// 空白区域 empty       e
// 墙壁     wall        w
// 箱子     box         b
// 空白目标 target      t
// 完成目标 achieved    a
// 游戏角色 player      p
char blocks[8][8] = {
    { 'w', 'w', 'w', 'w', 'w', 'w', 'w', 'w' },
    { 'w', 'w', 'w', 't', 'b', 'e', 'e', 'w' },
    { 'w', 'e', 'e', 'e', 'e', 'e', 'e', 'w' },
    { 'w', 'e', 'e', 'e', 'e', 'e', 'e', 'w' },
    { 'w', 'e', 'e', 'e', 'e', 'e', 'e', 'w' },
    { 'w', 'e', 'e', 'p', 'a', 'e', 'e', 'w' },
    { 'w', 'e', 'e', 'e', 'w', 'w', 'w', 'w' },
    { 'w', 'w', 'w', 'w', 'w', 'w', 'w', 'w' },
};

#define BLOCK_SIZE 60
#define HEIGHT 8
#define WIDTH 8
#define GRAY make_color(150, 150, 150)
bool window_should_close = false;
#define SCORE_BOARD_HEIGHT 60

Player player;

int targetNum;
int achievedNum;


#define LEVEL_TOTALNUM 5 // 一共多少关卡
int currentLevelNum = 0; // 当前玩到第几关

char levels[LEVEL_TOTALNUM][8][9] = {
    {"wwwwwwww","wwwtbeew","weeeeeew","weeeeeew",
    "weeeeeew","wepbteew","weeewwww","wwwwwwww"}, // 第1关
    {"wwwwwwww","wwweewww","wpetbwww","weeebeww",
    "wewteeww","weeeeeww","weepwwww","wwwwwwww"}, // 第2关
    {"wwwwwwww","wwpeewww","weeweeww","webabeww",
    "weeteeww","wwetewww","wwwwwwww","wwwwwwww"}, // 第3关
    {"wwwwwwww","wwwwwwww","weeeewww","weeettew",
    "webbbpew","weewetww","wwwwwwww","wwwwwwww"}, // 第4关
    {"wwwwwwww","wwwwwwww","wwteewww","weewebpw",
    "weewewew","weaeebtw","weeeewww","wwwwwwww"}  // 第5关
};


// 重置当前关卡的数据
void resetData()
{
    targetNum = 0;
    achievedNum = 0;
    for (int i = 0; i < HEIGHT; i++)
    {
        for (int j = 0; j < WIDTH; j++)
        {
            blocks[i][j] = levels[currentLevelNum][i][j];

            if (blocks[i][j] == 'p')
            {
                player.i = i;
                player.j = j;
                blocks[i][j] = 'e';
            }
            if (blocks[i][j] == 't' || blocks[i][j] == 'a')
            {
                targetNum++;
            }
        }
    }
}

void startup()
{
    resetData();
    InitWindow(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE + SCORE_BOARD_HEIGHT, "Push Box");
    SetTargetFPS(60);
}

void show()
{
    BeginDrawing();
    {
        ClearBackground(make_color(150, 150, 150, 255));

        for (int i = 0; i < HEIGHT; i++)
        {
            for (int j = 0; j < WIDTH; j++)
            {
                if (blocks[i][j] == 'e') // empty
                {
                    Color fill_color = make_color(150, 150, 150, 255);
                    DrawRectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, fill_color);
                }
                else if (blocks[i][j] == 'w') // wall
                {
                    DrawRectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, RED);
                    DrawRectangleLines(j * BLOCK_SIZE, i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, make_color(150, 150, 150, 255));
                }
                else if (blocks[i][j] == 'b') // box
                {
                    DrawRectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, YELLOW);
                }
                else if (blocks[i][j] == 't') // target
                {
                    DrawRectangle((j + 0.3) * BLOCK_SIZE, (i + 0.3) * BLOCK_SIZE, 0.4 * BLOCK_SIZE, 0.4 * BLOCK_SIZE, WHITE);
                }
                else if (blocks[i][j] == 'a') // achieved
                {
                    DrawRectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, YELLOW);
                    DrawRectangle((j + 0.3) * BLOCK_SIZE, (i + 0.3) * BLOCK_SIZE, 0.4 * BLOCK_SIZE, 0.4 * BLOCK_SIZE, WHITE);
                }

                // easyx 的 fillrectangle() 会自动绘制边框颜色, raylib 绘制矩形(内部填充)时则并不会绘制边框颜色。
                // DrawRectangleLines(j * BLOCK_SIZE, i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, make_color(200, 200, 200, 255));
            }
        }

        // 绘制玩家
        {
            // 红色圆脸
            int i = player.i;
            int j = player.j;
            DrawCircle((j + 0.5) * BLOCK_SIZE, (i + 0.5) * BLOCK_SIZE, 0.4 * BLOCK_SIZE, RED);
            
            // 两个黑色眼睛
            Color fill_color = make_color(80, 80, 80, 255);
            DrawCircle((j + 0.3) * BLOCK_SIZE, (i + 0.45) * BLOCK_SIZE, 0.08 * BLOCK_SIZE, fill_color);
            DrawCircle((j + 0.7) * BLOCK_SIZE, (i + 0.45) * BLOCK_SIZE, 0.08 * BLOCK_SIZE, fill_color);
            
            // 嘴巴
            //setlinestyle(PS_SOLID, 3);
            Vector2 startPos = make_vector((j + 0.35) * BLOCK_SIZE, (i + 0.7) * BLOCK_SIZE);
            Vector2 endPos = make_vector((j + 0.65) * BLOCK_SIZE, (i + 0.7) * BLOCK_SIZE);
            DrawLineEx(startPos, endPos, 3, fill_color);
        }

        // 绘制关卡信息
        {
            char txt[50] = { 0 };
            sprintf(txt, "level: %d", currentLevelNum + 1);
            DrawText(txt, 20, HEIGHT * BLOCK_SIZE + 10, 20, make_color(0, 255, 100, 255));
            DrawText("Keys: Space(replay current)  Esc(exit)", 20, HEIGHT * BLOCK_SIZE + 30, 20, make_color(0, 255, 100, 255));
        }

        // 如果胜利,则绘制胜利
        if (achievedNum == targetNum)
        {
            char str[50] = { 0 };
            if (currentLevelNum < LEVEL_TOTALNUM - 1) // 还有未完成的关卡可以玩
            {
                sprintf(str, "start level %d", currentLevelNum + 2);
                DrawText(str, 120, 160, 50, make_color(0, 255, 100, 255));
            }
            else
            {
                DrawText("You win", 80, 200, 80, make_color(0, 255, 255, 255));
            }
        }
    }
    EndDrawing();
}

void updateWithoutInput()
{
    
}

void updateWithInput()
{
    // if (achievedNum >= targetNum)
    //    return;

    char input = GetCharPressed();
    if (input == ' ')
    {
        resetData();
    }

    if (input == 'a' || input == 's' || input == 'd' || input == 'w')
    {

        int goal_i = player.i;
        int goal_j = player.j;
        int goalNext_i = goal_i;
        int goalNext_j = goal_j;
        if (input == 'a')
        {
            goal_j = player.j - 1;
            goalNext_j = goal_j - 1;
        }
        else if (input == 'd')
        {
            goal_j = player.j + 1;
            goalNext_j = goal_j + 1;
        }
        else if (input == 'w')
        {
            goal_i = player.i - 1;
            goalNext_i = goal_i - 1;
        }
        else if (input == 's')
        {
            goal_i = player.i + 1;
            goalNext_i = goal_i + 1;
        }

        if (blocks[goal_i][goal_j] == 'e' || blocks[goal_i][goal_j] == 't')
        {
            // 目标位置是 empty 或 target, 可以移动
            player.i = goal_i;
            player.j = goal_j;
        }
        else if (blocks[goal_i][goal_j] == 'b' && blocks[goalNext_i][goalNext_j] == 'e')
        {
            // 目标位置是 box, 再后面一个位置是 empty。可以推动箱子,并让玩家移动
            player.i = goal_i;
            player.j = goal_j;
            blocks[goal_i][goal_j] = 'e';
            blocks[goalNext_i][goalNext_j] = 'b';
        }
        else if (blocks[goal_i][goal_j] == 'b' && blocks[goalNext_i][goalNext_j] == 't')
        {
            // 目标位置是 box, 再后面一个位置是 target, 可以推动箱子, 并让玩家移动
            player.i = goal_i;
            player.j = goal_j;
            blocks[goal_i][goal_j] = 'e';
            blocks[goalNext_i][goalNext_j] = 'a';
        }
        else if (blocks[goal_i][goal_j] == 'a' && blocks[goalNext_i][goalNext_j] == 'e')
        {
            // 目标位置是 achieved, 再后面一个位置是 empty, 可以让玩家移动, 并推走箱子
            player.i = goal_i;
            player.j = goal_j;
            blocks[goal_i][goal_j] = 't';
            blocks[goalNext_i][goalNext_j] = 'b';
        }
        else if (blocks[goal_i][goal_j] == 'a' && blocks[goalNext_i][goalNext_j] == 't')
        {
            // 目标位置是 achieved, 再后面一个位置是 target, 可以让玩家移动, 并推走箱子
            player.i = goal_i;
            player.j = goal_j;
            blocks[goal_i][goal_j] = 't';
            blocks[goalNext_i][goalNext_j] = 'a';
        }
    }

    achievedNum = 0;
    for (int i = 0; i < HEIGHT; i++)
    {
        for (int j = 0; j < WIDTH; j++)
        {
            if (blocks[i][j] == 'a')
            {
                achievedNum++;
            }
        }
    }

    // 当前关卡完成了
    if (achievedNum == targetNum)
    {
        static int frameCount = 0; // 用于等待3秒 (180 / 60 = 3)
        frameCount++;
        if (currentLevelNum < LEVEL_TOTALNUM - 1 && frameCount == 180)
        {
            currentLevelNum++; // 进入下一关
            frameCount = 0;
            resetData();
        }
    }
}

int main()
{
    startup();

    while (!WindowShouldClose())
    {
        show();
        updateWithInput();
        updateWithoutInput();
    }

    CloseWindow();
}
posted @ 2023-01-25 20:16  ChrisZZ  阅读(149)  评论(0编辑  收藏  举报