C语言实训——经典小游戏马里奥开发day 1
卷轴式地图
一、关于卷轴式地图
在之前的开发尝试之中,我曾经使用的是地图移动但是马里奥保持在一个固定的点来实现马里奥的移动,但是我发现了几个问题:
1、跳跃不自然
由于马里奥本身没有x方向的位移,所以跳跃显得不自然,在使用了姿势切换后得到 了一点改进,但是看上去依旧像是直上直下式的跳跃,无法呈现出向前跳跃的抛物线
2、无法自由移动马里奥
因为是移动地图本身来移动实现移动马里奥,导致了马里奥不能自由的移动,只能保持一个固定的速度向前移动并跳上砖头,跳过柱子等
3、游戏模式单调
地图移动而马里奥不移动导致了游戏的单调,始终处于一个恒定的向前模式,并且后面不方便继续增加怪物,进入别的关卡的入口等元素的设置,局限性很大。
为了解决上面出现的问题,我决定使用卷轴式的地图渲染方式,卷轴是地图指的是地图以卷轴的形式展开,可视窗口一般大小固定不变,随着人物主角的移动而像展开卷轴一样的展开地图,现在常用的卷轴式地图算法是卡马克算法,但是因为我仍然是一个初学者,只能使用低效的渲染算法。
二、卷轴式地图算法部分
代码
#include <graphics.h>
#include <conio.h>
#include<Windows.h>
#include<bits/stdc++.h>
#include <iostream>
using namespace std;
class Maliao
{
public:
int x, y;//坐标
int high;//高度
int mx, my;//马里奥的长度和高度
IMAGE image[2];
}maliao;
class Zhuzi
{
public:
int x, y;
int high = 30;
int mx, my;
IMAGE image;
}zhuzi;
class Diman
{
public:
int dx, dy;
IMAGE image;
}dimian[3];
IMAGE beijing;
bool move_left = false, move_right = false;
void makeimage()
{
putimage(0, 0, &beijing);
putimage(dimian[0].dx, dimian[0].dy, &dimian[0].image);
putimage(dimian[1].dx, dimian[1].dy, &dimian[1].image);
putimage(dimian[2].dx, dimian[2].dy, &dimian[2].image);
putimage(maliao.x, maliao.y, &maliao.image[0]);
}
void keydown()
{
if (_kbhit())
{
char input = _getch();
if (input == 'd')
{
move_right = true;
maliao.x++;
if (maliao.x > 560)
maliao.x = 560;
}
if (input == 'a')
{
move_left = true;
maliao.x--;
}
}
}
void newimage()
{
if (move_right)
{
for (int i = 0; i < 3; i++)
{
dimian[i].dx--;
}
move_right = false;
}
if (move_left)
{
for (int i = 0; i < 3; i++)
{
dimian[i].dx++;
}
move_left = false;
}
for (int i = 0; i < 3; i++)
{
if (dimian[i].dx < -1320)
{
dimian[i].dx = 660;
}
if (dimian[i].dx > 1320)
{
dimian[i].dx = -660;
}
}
}
int main()
{
cout << "按任意键开始游戏" << endl;
_getch();
// 初始化
initgraph(660, 480);
loadimage(&beijing, _T("D:\\hhh\\背景.png"), 660, 480);
loadimage(&dimian[0].image, _T("D:\\hhh\\地面.jpg"), 660, 30);
loadimage(&dimian[1].image, _T("D:\\hhh\\地面.jpg"), 660, 30);
loadimage(&dimian[2].image, _T("D:\\hhh\\地面.jpg"), 660, 30);
loadimage(&maliao.image[0], _T("D:\\hhh\\mla2.jpg"), 50, 50);
loadimage(&maliao.image[1], _T("D:\\hhh\\mla1.jpg"), 50, 50);
loadimage(&zhuzi.image, _T("D:\\hhh\\柱子.jpg"), 50, zhuzi.high);
dimian[0].dx = 0; dimian[1].dx = 660, dimian[2].dx = -660;
dimian[0].dy = 450; dimian[1].dy = 450, dimian[2].dy = 450;
maliao.x = 300, maliao.y = 400;
while (1)
{
cleardevice();//清屏
makeimage();//放置图片
Sleep(20);//休眠
keydown();//按键交互
newimage();//更新图形
}
closegraph();
cout << "you lose" << endl;
}
上面的代码实现了马里奥在一个平地上进行向左和向右的移动,且地图的展开方式为卷轴式。
核心代码
void keydown()
{
if (_kbhit())
{
char input = _getch();
if (input == 'd')//玩家按下d键
{
move_right = true;//标记此时应该向右走
maliao.x++;//马里奥的横坐标向右增加一个像素
if (maliao.x > 560)//限制马里奥不能离开窗口范围
maliao.x = 560;
}
if (input == 'a')//玩家按下a键
{
move_left = true;//标记此时应该向左走
maliao.x--;//马里奥的横坐标向左增加一共像素
if(maliao.x<100)//限制马里奥不能离开窗口范围
maliao.x=100;
}
}
}
void newimage()
{
if (move_right)//此时马里奥正在向右走
{
for (int i = 0; i < 3; i++)
{
dimian[i].dx--;//与上面不同的是这里地图要反方向移动
}
move_right = false;//标记还原
}
if (move_left)//同上
{
for (int i = 0; i < 3; i++)
{
dimian[i].dx++;
}
move_left = false;
}
//卷轴式展开部分
for (int i = 0; i < 3; i++)
{
if (dimian[i].dx < -1320)
{
dimian[i].dx = 660;
}
if (dimian[i].dx > 1320)
{
dimian[i].dx = -660;
}
}
}
/*这里我们将地图分成三块,每一块都是和可视窗口一样大,标记为1,2,3,2在口,1在可视窗口左边窗口,我们称之为左窗口,同理剩下的那个在右窗口,当2动的时候,2会进入左或者右窗口,1和3会离开原本的窗口,根据2的移动方向,有一个会进入中间窗口,当1或3中的一个彻底离开原本窗口时,进入离他最远的窗口,例如向左移动时,初始为123,最后会变成231,此时3就变成了可视窗口中的内容了,这样我们就实现了地图的无限化*/
三、当前算法缺点
由于我们总是渲染了三个可视窗口大小的地图,就导致了对用户计算机要求的增高,后续开发美术材质高的游戏时应作出相应的优化。