推箱子大冒险(SDL/C)

这篇具有很好参考价值的文章主要介绍了推箱子大冒险(SDL/C)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

欢迎来到小K的SDL专栏第三小节,本节将为大家带来小项目~C语言SDL版坤坤推箱子详细讲解,这里也为大家上传了源码和图片资源,需要的自取看完以后,希望对你有所帮助

✨效果如下

2023-05-26-14-19-21推箱子



一、推箱子思路讲解

第一步,我们先用枚举把下图中的元素表示出来,分别为空地、墙、目的地、箱子、玩家

enum MyEnum { SPACE, WALL, DEST, BOX, PLAYER };

推箱子大冒险(SDL/C)


第二步我们就需要自己定义一个地图来使用,我这里写的推箱子就三关,所以定义了一个三页的二维数组

//定义一个地图
	int map[3][ROW][COL] =
	{
		{
			{0,0,0,0,0,0,0,0,0,0},
			{0,0,0,1,1,1,0,0,0,0},
			{0,0,0,1,2,1,0,0,0,0},
			{0,0,0,1,3,1,1,1,1,0},
			{0,1,1,1,0,3,0,2,1,0},
			{0,1,2,3,4,0,1,1,1,0},
			{0,1,1,1,1,3,1,0,0,0},
			{0,0,0,0,1,2,1,0,0,0},
			{0,0,0,0,1,1,1,0,0,0},
			{0,0,0,0,0,0,0,0,0,0}
		},
		{
			{0,0,0,0,0,0,0,0,0,0},
			{0,0,1,1,0,0,1,1,0,0},
			{0,1,2,0,1,1,0,2,1,0},
			{1,0,0,0,0,0,0,0,0,1},
			{1,0,0,3,4,0,3,0,0,1},
			{0,1,0,0,0,3,0,0,1,0},
			{0,0,1,0,3,0,0,1,0,0},
			{0,0,0,1,2,2,1,0,0,0},
			{0,0,0,0,1,1,0,0,0,0},
			{0,0,0,0,0,0,0,0,0,0}
		},
		{
			{1,1,1,1,0,0,1,1,1,1},
			{1,2,0,1,0,0,1,0,2,1},
			{1,0,0,1,0,0,1,0,0,1},
			{1,0,0,1,0,0,1,0,0,1},
			{1,0,0,1,0,0,1,0,0,1},
			{1,0,3,1,1,1,1,3,0,1},
			{1,0,0,3,4,0,3,0,0,1},
			{1,0,0,0,0,0,0,0,0,1},
			{1,2,0,0,0,0,0,0,2,1},
			{1,1,1,1,1,1,1,1,1,1}
		}
	};

第三步我们就需要一个推箱子的逻辑思维,比方说,前面是空地要怎么操作,前面是箱子又要怎么办?不要着急,和我先打两个半球~

⭐既然是推箱子,那我们肯定要知道谁推箱子,所以第一小步就是找人,这就好办了,我们直接遍历地图,无非只有两种情况,要么是人站在空地上,由于空地为0,所以只需要判断人,要么是人站在目的地上

//玩家的当前的下标
	int r = -1;
	int c = -1;
	//找到玩家的下标
	for (int i = 0; i < ROW; i++)
	{
		for (int k = 0; k < COL; k++)
		{
			if (map[i][k] == PLAYER || map[i][k] == DEST + PLAYER)
			{
				r = i;
				c = k;
				goto endLoop;
			}
		}
	}
endLoop:;

⭐第二小步就是推箱子的具体逻辑了,这里我们以上为例

玩家前面是箱子 玩家前面是空地
箱子的前面是空地或者目的地 前面空地+PLAYER,本来人站的地方减去PLAYER
⭐1,把箱子移动到前面 ⭐2,把箱子从原来的位置删掉 ⭐3.把玩家移动到箱子原来的位置⭐4,把玩家从原来的位置删掉
case SDLK_w:
			//如果玩家的前面是空地
			if (map[r - 1][c] == SPACE || map[r - 1][c] == DEST)
			{
				map[r - 1][c] += PLAYER;
				map[r][c] -= PLAYER;
			}
			//如果玩家的前面是箱子
			else if (map[r - 1][c] == BOX || map[r - 1][c] == BOX + DEST)
			{
				//如果箱子的前面是空地或者目的地
				if (map[r - 2][c] == SPACE || map[r - 2][c] == DEST)
				{
					//1,把箱子移动到前面
					map[r - 2][c] += BOX;
					//2,把箱子从原来的位置删掉
					map[r - 1][c] -= BOX;
					//3,把玩家移动到箱子原来的位置
					map[r - 1][c] += PLAYER;
					//4,把玩家从原来的位置删掉
					map[r][c] -= PLAYER;
				}
			}
			break;

完整的推箱子逻辑代码

//推箱子
void pushBox(int map[][COL], int key)
{
	//玩家的当前的下标
	int r = -1;
	int c = -1;
	//找到玩家的下标
	for (int i = 0; i < ROW; i++)
	{
		for (int k = 0; k < COL; k++)
		{
			if (map[i][k] == PLAYER || map[i][k] == DEST + PLAYER)
			{
				r = i;
				c = k;
				goto endLoop;
			}
		}
	}
endLoop:;

	switch (key)
	{
		case SDLK_w:
			//如果玩家的前面是空地
			if (map[r - 1][c] == SPACE || map[r - 1][c] == DEST)
			{
				map[r - 1][c] += PLAYER;
				map[r][c] -= PLAYER;
			}
			//如果玩家的前面是箱子
			else if (map[r - 1][c] == BOX || map[r - 1][c] == BOX + DEST)
			{
				//如果箱子的前面是空地或者目的地
				if (map[r - 2][c] == SPACE || map[r - 2][c] == DEST)
				{
					//1,把箱子移动到前面
					map[r - 2][c] += BOX;
					//2,把箱子从原来的位置删掉
					map[r - 1][c] -= BOX;
					//3,把玩家移动到箱子原来的位置
					map[r - 1][c] += PLAYER;
					//4,把玩家从原来的位置删掉
					map[r][c] -= PLAYER;
				}
			}
			break;
		case SDLK_s:
			if (map[r + 1][c] == SPACE || map[r + 1][c] == DEST)
			{
				map[r + 1][c] += PLAYER;
				map[r][c] -= PLAYER;
			}
			else if (map[r + 1][c] == BOX || map[r + 1][c] == BOX + DEST)
			{
				if (map[r + 2][c] == SPACE || map[r + 2][c] == DEST)
				{
					map[r + 2][c] += BOX;
					map[r + 1][c] -= BOX;
					map[r + 1][c] += PLAYER;
					map[r][c] -= PLAYER;
				}
			}
			break;
		case SDLK_a:
			if (map[r][c - 1] == SPACE || map[r][c - 1] == DEST)
			{
				map[r][c - 1] += PLAYER;
				map[r][c] -= PLAYER;
			}
			else if (map[r][c - 1] == BOX || map[r][c - 1] == BOX + DEST)
			{
				if (map[r][c - 2] == SPACE || map[r][c - 2] == DEST)
				{
					map[r][c - 2] += BOX;
					map[r][c - 1] -= BOX;
					map[r][c - 1] += PLAYER;
					map[r][c] -= PLAYER;
				}
			}
			break;
		case SDLK_d:
			if (map[r][c + 1] == SPACE || map[r][c + 1] == DEST)
			{
				map[r][c + 1] += PLAYER;
				map[r][c] -= PLAYER;
			}
			else if (map[r][c + 1] == BOX || map[r][c + 1] == BOX + DEST)
			{
				if (map[r][c + 2] == SPACE || map[r][c + 2] == DEST)
				{
					map[r][c + 2] += BOX;
					map[r][c + 1] -= BOX;
					map[r][c + 1] += PLAYER;
					map[r][c] -= PLAYER;
				}
			}
			break;
	}

}


第四步也是最后一步,我们还需要判断一下过关没有,这个好判断,我们直接遍历整个地图,看看还有没有箱子

//判断是否过关
bool passLevel(int map[][COL])
{
	for (int i = 0; i < ROW; i++)
	{
		for (int k = 0; k < COL; k++)
		{
			if (map[i][k] == BOX)
			{
				return false;
			}
		}
	}
	return true;
}

二、加SDL绘图代码

第一步我们先搭建一下我们的绘图框架,具体的可以看我的SDL专栏第二小节

int main(int argc,char* argv[])
{
	//初始化
	if (SDL_Init(SDL_INIT_VIDEO) != 0)
	{
		SDL_Log("Init failed%s\n", SDL_GetError());
		return -1;
	}
	//创建窗口
	SDL_Window* window = SDL_CreateWindow("pushBox", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 640, SDL_WINDOW_SHOWN);
	if (!window)
	{
		SDL_Log("create window failed!%s\n", SDL_GetError());
		return -1;
	}
	//创建渲染器
	SDL_Renderer* render = SDL_CreateRenderer(window, -1, 0);
	if (!render)
	{
		SDL_Log("create Renderer failed!%s\n", SDL_GetError());
		return -1;
	}
	/*****************************/
	//接下来的操作//
	/*****************************/
	//销毁窗口
	SDL_DestroyWindow(window);
	//销毁渲染器
	SDL_DestroyRenderer(render);
	//清理并退出SDL库
	SDL_Quit();
	return 0;
}

第二步加载图片,可以看到这里准备的图片编号刚刚好就是0~6,一会在绘图上有大用,这里也有大用,这里我们直接创建一个数组,然后用SDL_snprintf在一个for循环中直接把七张图片显示加载出来
推箱子大冒险(SDL/C)

//加载图片
	SDL_Texture* tex[7];
	char fillname[50] = { 0 };
	for (int i = 0; i < 7; i++)
	{
		SDL_snprintf(fillname, 50, "./assets/images/%d.bmp", i);
		tex[i] = loadTexture(render, fillname);
	}
	
SDL_Texture* loadTexture(SDL_Renderer* ren, const char* fillname)
{
	SDL_Surface* sfc = SDL_LoadBMP(fillname);
	if (!sfc)
	{
		SDL_Log("loadBMP failed!%s\n", SDL_GetError());
		return NULL;
	}
	SDL_Texture* tex = SDL_CreateTextureFromSurface(ren, sfc);
	if (!tex)
	{
		SDL_Log("Texture failed!%s\n", SDL_GetError());
		SDL_FreeSurface(sfc);
		return NULL;
	}
	SDL_FreeSurface(sfc);
	return tex;
}

最后一步绘制图案,注意这里有一个小坑,二维数组横向是Y,纵向是X,而绘图窗口横向是X,纵向是Y,所以绘图的时候要刚好反一下,如下图
推箱子大冒险(SDL/C)

//绘制界面
void drawMap(SDL_Renderer* render, int map[][COL], SDL_Texture** texs)
{
	for (int r = 0; r < ROW; r++)
	{
		for (int c = 0; c < COL; c++)
		{
			SDL_Rect dstRect = { c * 64 ,r * 64,64,64 };
			SDL_RenderCopy(render, texs[map[r][c]], NULL, &dstRect);
		}
	}
}

三、完整代码

#include<conio.h>
#include<SDL.h>
#include<iostream>
#include<cstdio>
using namespace std;

#define ROW 10
#define COL 10

enum MyEnum { SPACE, WALL, DEST, BOX, PLAYER };

//提前声明
void pushBox(int map[][COL], int key);
bool passLevel(int map[][COL]);
SDL_Texture* loadTexture(SDL_Renderer* ren, const char* fillname);
void drawMap(SDL_Renderer* render, int map[][COL], SDL_Texture** texs);

int main(int argc,char* argv[])
{
	//初始化
	if (SDL_Init(SDL_INIT_VIDEO) != 0)
	{
		SDL_Log("Init failed%s\n", SDL_GetError());
		return -1;
	}
	//创建窗口
	SDL_Window* window = SDL_CreateWindow("pushBox", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 640, SDL_WINDOW_SHOWN);
	if (!window)
	{
		SDL_Log("create window failed!%s\n", SDL_GetError());
		return -1;
	}
	//创建渲染器
	SDL_Renderer* render = SDL_CreateRenderer(window, -1, 0);
	if (!render)
	{
		SDL_Log("create Renderer failed!%s\n", SDL_GetError());
		return -1;
	}
	//加载图片
	SDL_Texture* tex[7];
	char fillname[50] = { 0 };
	for (int i = 0; i < 7; i++)
	{
		SDL_snprintf(fillname, 50, "./assets/images/%d.bmp", i);
		tex[i] = loadTexture(render, fillname);
	}

	//定义一个地图
	int map[3][ROW][COL] =
	{
		{
			{0,0,0,0,0,0,0,0,0,0},
			{0,0,0,1,1,1,0,0,0,0},
			{0,0,0,1,2,1,0,0,0,0},
			{0,0,0,1,3,1,1,1,1,0},
			{0,1,1,1,0,3,0,2,1,0},
			{0,1,2,3,4,0,1,1,1,0},
			{0,1,1,1,1,3,1,0,0,0},
			{0,0,0,0,1,2,1,0,0,0},
			{0,0,0,0,1,1,1,0,0,0},
			{0,0,0,0,0,0,0,0,0,0}
		},
		{
			{0,0,0,0,0,0,0,0,0,0},
			{0,0,1,1,0,0,1,1,0,0},
			{0,1,2,0,1,1,0,2,1,0},
			{1,0,0,0,0,0,0,0,0,1},
			{1,0,0,3,4,0,3,0,0,1},
			{0,1,0,0,0,3,0,0,1,0},
			{0,0,1,0,3,0,0,1,0,0},
			{0,0,0,1,2,2,1,0,0,0},
			{0,0,0,0,1,1,0,0,0,0},
			{0,0,0,0,0,0,0,0,0,0}
		},
		{
			{1,1,1,1,0,0,1,1,1,1},
			{1,2,0,1,0,0,1,0,2,1},
			{1,0,0,1,0,0,1,0,0,1},
			{1,0,0,1,0,0,1,0,0,1},
			{1,0,0,1,0,0,1,0,0,1},
			{1,0,3,1,1,1,1,3,0,1},
			{1,0,0,3,4,0,3,0,0,1},
			{1,0,0,0,0,0,0,0,0,1},
			{1,2,0,0,0,0,0,0,2,1},
			{1,1,1,1,1,1,1,1,1,1}
		}
	};
	//当前所在关卡
	int level = 0;
	SDL_bool isDown = SDL_FALSE;
	while (!isDown)
	{
		drawMap(render, map[level], tex);
		SDL_RenderPresent(render);
		if (passLevel(map[level]))
		{
			level++;
			if (level >= 3)
			{
				std::cout << "game over,你通过了所有关卡~" << endl;
				level = 0;
				break;
			}
			std::cout << "恭喜你,通过了第" << level - 1 << "关!" << endl;
		}
		SDL_Event ev = { 0 };
		if (SDL_PollEvent(&ev))
		{
			if (SDL_QUIT == ev.type)
			{
				isDown = SDL_TRUE;
			}
			else if (ev.type == SDL_KEYDOWN)
			{
				pushBox(map[level], ev.key.keysym.sym);
			}
		}
	}

	//销毁窗口
	SDL_DestroyWindow(window);
	//销毁渲染器
	SDL_DestroyRenderer(render);
	//清理并退出SDL库
	SDL_Quit();
	return 0;
}


//绘制界面
void drawMap(SDL_Renderer* render, int map[][COL], SDL_Texture** texs)
{
	for (int r = 0; r < ROW; r++)
	{
		for (int c = 0; c < COL; c++)
		{
			SDL_Rect dstRect = { c * 64 ,r * 64,64,64 };
			SDL_RenderCopy(render, texs[map[r][c]], NULL, &dstRect);
		}
	}
}

//推箱子
void pushBox(int map[][COL], int key)
{
	//玩家的当前的下标
	int r = -1;
	int c = -1;
	//找到玩家的下标
	for (int i = 0; i < ROW; i++)
	{
		for (int k = 0; k < COL; k++)
		{
			if (map[i][k] == PLAYER || map[i][k] == DEST + PLAYER)
			{
				r = i;
				c = k;
				goto endLoop;
			}
		}
	}
endLoop:;

	switch (key)
	{
		case SDLK_w:
			//如果玩家的前面是空地
			if (map[r - 1][c] == SPACE || map[r - 1][c] == DEST)
			{
				map[r - 1][c] += PLAYER;
				map[r][c] -= PLAYER;
			}
			//如果玩家的前面是箱子
			else if (map[r - 1][c] == BOX || map[r - 1][c] == BOX + DEST)
			{
				//如果箱子的前面是空地或者目的地
				if (map[r - 2][c] == SPACE || map[r - 2][c] == DEST)
				{
					//1,把箱子移动到前面
					map[r - 2][c] += BOX;
					//2,把箱子从原来的位置删掉
					map[r - 1][c] -= BOX;
					//3,把玩家移动到箱子原来的位置
					map[r - 1][c] += PLAYER;
					//4,把玩家从原来的位置删掉
					map[r][c] -= PLAYER;
				}
			}
			break;
		case SDLK_s:
			if (map[r + 1][c] == SPACE || map[r + 1][c] == DEST)
			{
				map[r + 1][c] += PLAYER;
				map[r][c] -= PLAYER;
			}
			else if (map[r + 1][c] == BOX || map[r + 1][c] == BOX + DEST)
			{
				if (map[r + 2][c] == SPACE || map[r + 2][c] == DEST)
				{
					map[r + 2][c] += BOX;
					map[r + 1][c] -= BOX;
					map[r + 1][c] += PLAYER;
					map[r][c] -= PLAYER;
				}
			}
			break;
		case SDLK_a:
			if (map[r][c - 1] == SPACE || map[r][c - 1] == DEST)
			{
				map[r][c - 1] += PLAYER;
				map[r][c] -= PLAYER;
			}
			else if (map[r][c - 1] == BOX || map[r][c - 1] == BOX + DEST)
			{
				if (map[r][c - 2] == SPACE || map[r][c - 2] == DEST)
				{
					map[r][c - 2] += BOX;
					map[r][c - 1] -= BOX;
					map[r][c - 1] += PLAYER;
					map[r][c] -= PLAYER;
				}
			}
			break;
		case SDLK_d:
			if (map[r][c + 1] == SPACE || map[r][c + 1] == DEST)
			{
				map[r][c + 1] += PLAYER;
				map[r][c] -= PLAYER;
			}
			else if (map[r][c + 1] == BOX || map[r][c + 1] == BOX + DEST)
			{
				if (map[r][c + 2] == SPACE || map[r][c + 2] == DEST)
				{
					map[r][c + 2] += BOX;
					map[r][c + 1] -= BOX;
					map[r][c + 1] += PLAYER;
					map[r][c] -= PLAYER;
				}
			}
			break;
	}

}

//判断是否过关
bool passLevel(int map[][COL])
{
	for (int i = 0; i < ROW; i++)
	{
		for (int k = 0; k < COL; k++)
		{
			if (map[i][k] == BOX)
			{
				return false;
			}
		}
	}
	return true;
}

//加载图片
SDL_Texture* loadTexture(SDL_Renderer* ren, const char* fillname)
{
	SDL_Surface* sfc = SDL_LoadBMP(fillname);
	if (!sfc)
	{
		SDL_Log("loadBMP failed!%s\n", SDL_GetError());
		return NULL;
	}
	SDL_Texture* tex = SDL_CreateTextureFromSurface(ren, sfc);
	if (!tex)
	{
		SDL_Log("Texture failed!%s\n", SDL_GetError());
		SDL_FreeSurface(sfc);
		return NULL;
	}
	SDL_FreeSurface(sfc);
	return tex;
}

四、总结

本节带来的推箱子小游戏不仅可以让你对数组等语法更加熟练,也会让你的图形库知识更上一层楼,本节就到这里啦~期待下一节和大家的相遇🌞文章来源地址https://www.toymoban.com/news/detail-462598.html

到了这里,关于推箱子大冒险(SDL/C)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 简单的推箱子游戏实战

    目录 项目分析  地图初始化 背景图片 游戏场景图片: 热键控制  按键设置 确定人物位置 实现人物移动(非箱子,目的地) 推箱子控制 游戏结束 最终代码 合法性判断: 墙:0,地板:1,箱子目的地:2,小人:3,箱子:4,箱子命中目标:5 但是一直执行循环块很占用CPU ,消耗很大很严重资源(使用

    2024年01月22日
    浏览(38)
  • c++推箱子小游戏

    上代码: 由于写游戏时间较长,更新较慢,请大佬们理解一下

    2024年02月09日
    浏览(39)
  • Java课程设计之推箱子

      推箱子游戏是一个比较古老的游戏,深受广大游戏爱好者的欢迎,它在带来乐趣的同时也能培养我们的反应力以及严谨的思维能力。   游戏规则是要求角色将地图中所有放置的箱子推到指定目标位置,只有合理安排移动次序和位置 ,才能顺利完成任务。   项目任务是用

    2024年02月08日
    浏览(41)
  • 使用Python语言写一个推箱子游戏

    本游戏旨在提供一个趣味性的益智游戏,玩家需要通过推动箱子到指定位置来过关。 玩家需要推动一个或多个箱子到指定位置,才能过关。 箱子只能向前推,不能拉回来。 箱子不允许被推到障碍物、墙壁或其他箱子上。 玩家可以通过 UNDO 按钮来撤回上一步操作,最多可以撤

    2024年02月05日
    浏览(51)
  • python小游戏——推箱子代码开源

    ♥️ 作者:小刘在这里 ♥️ 每天分享云计算网络运维课堂笔记,努力不一定有回报,但一定会有收获加油!一起努力,共赴美好人生! ♥️ 夕阳下,是最美的,绽放,愿所有的美好,再疫情结束后如约而至。 目录 一.效果呈现  二.主代码 三.cfg 四.README \\\'\\\'\\\'配置文件\\\'\\\'\\\' imp

    2024年02月02日
    浏览(45)
  • java版本实现推箱子小游戏

    推方块 游戏简介: 由 ↑,↓,←,→键来控制方向,点击空格键表示重玩当前关卡。 核心代码部分 :就是如何处理人的移动和人和箱子一起时的移动,这里需要对人要走的下一步和人推着箱子一起走的下一步进行判断分析,如果没有被阻挡就可以继续走下一步。(有兴趣

    2024年02月11日
    浏览(53)
  • C/C++项目实战-推箱子小游戏

    2024年02月08日
    浏览(52)
  • 【HTML小游戏】推箱子网页版(附完整源码)

    最近刚刚更新完了HTML,CSS的万字总结 ,有很多人已经学习完了文章,感觉反馈还不错,今天,用HTML,CSS,JS的知识编写了一个童年经典游戏 - 推箱子,供学习参考。 游戏主界面展示: 游戏界面展示: 经典的推箱子是一个非常古老游戏,甚至是80,90年代的回忆,目的是在训

    2024年02月04日
    浏览(52)
  • python毕设分享 python推箱子小游戏

    🔥 Hi,各位同学好呀,这里是L学长! 🥇今天向大家分享一个今年(2022)最新完成的毕业设计项目作品 python小游戏毕设 推箱子小游戏设计与实现 (源码) 🥇 学长根据实现的难度和等级对项目进行评分(最低0分,满分5分) 难度系数:3分 工作量:3分 创新点:4分 项目获取: htt

    2024年02月05日
    浏览(40)
  • Unity游戏源码分享-3d机器人推箱子游戏

    Unity游戏源码分享-3d机器人推箱子游戏 一个非常意思的3D游戏    工程地址:https://download.csdn.net/download/Highning0007/88098014

    2024年02月15日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包