基于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();
}
Greatness is never a given, it must be earned.