C/C++游戏项目:编译重温小霸王经典超级玛丽教程(附注释源码)

超级玛丽全名《超级马里奥兄弟》,是任天堂公司出品的著名横版过关游戏,超级玛丽游戏最早在红白机上推出,有多款后续作品。提到《超级玛丽》想必没有人不知道吧?这个系列已经是任天堂的招牌系列,那个大鼻子、头戴帽子、身穿背带工作服、还留着胡子的中年大叔应该算是国际巨星了吧。 

今天就带大家一步步去完成童年经典红白机游戏超级马里奥~

PS:要安装easyx图形库哦 #include<easyx.h>  

编译环境:Visual Studio2008

// 注:本游戏的每个算法思想都是由自己独立思考出来的,所以可能会有很
//        多不完善以及错误的地方,在此也希望大家能指出程序中的bug或错误。
//        游戏优点:使用了类和结构体,所以结构较为清晰明了。功能比较完全,包含图片和音乐。
//        游戏缺点:由于没有太多时间,所以只设置了一关游戏,而且游戏地图很小。

在此之前呢,和大家说明一下,展示所有代码会有些困难,所以我裁剪了主要的大部分代码,主要目的是让大家明白实现这个项目的逻辑思路,希望大家可以理解然后自行写出完整程序来~需要对照的话完整代码文章最下方获取哦

任何游戏的开始都是创建一个项目,并将准备好的素材资源放到同级目录下(素材及音乐可以在文章最下方领取)如图(这里就用上篇中国象棋实例):

 

头文件和宏定义如下:

#include <graphics.h>
#include <conio.h>
#include<math.h>
#include "MyTimer.h"               //一个保证精确延时的类。下载于easyx官网
#pragma comment(lib,"Winmm.lib")   //给游戏添加音乐要用到它

#define G 9.8                      //重力加速度
#define XSIZE 512                  //屏幕大小
#define YSIZE 384
#define X 64                       //主角起始位置
#define Y 192
#define W 32                       //主角的宽和高
#define H 32
#define STEP 4                     //主角走一步相距的像素个数
#define HIGH (2*role.w+1)          //主角跳跃的最大高度
 
#define	CMD_LEFT 1                 //方向键的宏定义
#define	CMD_RIGHT 2	
#define	CMD_UP 4
#define CMD_DOWN 8
#define CMD_SHOOT 16
#define CMD_ESC 32
int life;                          //全局变量,主角共有多少条生命
int score;                         //全局变量,主角获得的分数

结构体如下:

struct ROLE
{
	int id;
    int x;//横坐标
    int y;//纵坐标
    int w;//图片宽度
    int h;//图片高度
    int xleft;//水平运动的左界限 
    int xright;//水平运动的右界限
    int turn;//精灵的运动方向
    int jump;//精灵是否跳跃
    int iframe;//加载第几副精灵图,这样就能让精灵看上去动起来了
};
struct MAP        //储存地图的结构体
{
	int id;
	int x;
	int y;
};
struct BULLET      //子弹的结构体
{
	int x;
	int y;
	int turn;
	int iframe;
	int id;
};
struct COINT      //硬币的结构体
{
	int x;
	int y;
	double iframe;
};
struct ENEMY      //敌人的结构体
{
	int id;
	int x;
	int y;
	int turn;
	int iframe;
};

设置类如下:

class game        //整个游戏只设置了这一个类
{
private:
	ROLE role;
	MAP map[350];
	BULLET bullet[20];
	COINT coint[50];
	ENEMY enemy[20];
	IMAGE img_mapsky,img_p,img_map,img_ani,img_mapbk,img_home;
	int xmapsky;           //背景天空的起始横坐标
	int xmap;              //地图的起始坐标
	double v0;             //精灵跳跃的初速度             
	double h;              //精灵跳跃的高度
	double t;              //精灵跳跃的时间
	int ibullet;           //第几颗子弹
	int xbullet;           //子弹的x坐标
	int ybullet;           //子弹的y坐标
	int get_bullet;        //是否获得武器,0表示没有获得,1表示已获得
	POINT icoint;          //储存硬币的坐标
	POINT bomb[20];        //储存哪些地方爆炸了的坐标
	POINT temp;            //临时坐标。储存哪些地方爆炸了的坐标
	double score_frame;    //下面3个double型的变量用于控制各自图片的帧,以实现动画的效果。如画面中的流水
	double bomb_frame;
	double mapbk_frame;
	int win;               //玩家是否过关
	int pause;             //玩家是否按Esc(暂停键)
public:
	game();
	~game();
	void start();          //处理游戏开始的界面,和按暂停键后的界面
	void init();           //初始化各项变量
	void move();           //控制主角移动
	void show();           //显示画面
	int isdie();           //判断主角是否已死
	int  GetCommand();	   // 获取控制命令。参阅easyx
	void left();           //主角向左运动
	void right();          //主角向右运动
	void up();             //主角跳跃
	void init_shoot();     //初始化发射子弹
	void fall();	       //主角自由落体或者向上跳跃
	int is_l_touch(int id);//主角的左边是否碰到墙或敌人,以及敌人是否碰到陆地的左边界
	int is_r_touch(int id);//主角的右边是否碰到墙或敌人,以及敌人是否碰到陆地的右边界
	int is_t_touch();      //主角的头是否碰到墙
	int is_b_touch(int id);//主角是否踩到敌人。
	int is_touch();        //主角是否吃到金币
	int is_land(ENEMY e);  //敌人是否站在陆地上
	void getbullet();      //获取子弹
	void shoot();          //发射子弹
	int eat(BULLET b);     //子弹是否打到敌人或者墙壁
	void end();            //处理游戏结束
};
game::game()
{
	initgraph(XSIZE,YSIZE);
}
game::~game()
{
	closegraph();
}

编译开始游戏界面如下:

void game::start()
{
	if(pause==1)//如果按了暂停键
	{
		BeginBatchDraw();
		int points[8]={XSIZE/2-45,YSIZE/3,XSIZE/2+45,YSIZE/3,XSIZE/2+45,YSIZE/3+90,XSIZE/2-45,YSIZE/3+90};
		setfillstyle(GREEN);
		fillpoly(4, points);
		setbkmode(TRANSPARENT);
		setfont(20,0,"黑体");
    	RECT r2={XSIZE/2-45,YSIZE/3,XSIZE/2+45,YSIZE/3+30};rectangle(XSIZE/2-45,YSIZE/3,XSIZE/2+45,YSIZE/3+30);
    	drawtext("回到游戏", &r2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
    	RECT r3={XSIZE/2-45,YSIZE/3+30,XSIZE/2+45,YSIZE/3+60};rectangle(XSIZE/2-45,YSIZE/3+30,XSIZE/2+45,YSIZE/3+60);
        drawtext("重新开始", &r3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	    RECT r4={XSIZE/2-45,YSIZE/3+60,XSIZE/2+45,YSIZE/3+90};rectangle(XSIZE/2-45,YSIZE/3+60,XSIZE/2+45,YSIZE/3+90);
    	drawtext(" 主 菜 单 ", &r4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
		FlushBatchDraw();

	    MOUSEMSG m;
    	while(true)
    	{
			BeginBatchDraw();
    		m=GetMouseMsg();
    		switch(m.uMsg)
            {
			case WM_LBUTTONDOWN:
				EndBatchDraw();
				if(m.x>XSIZE/2-45&&m.x<XSIZE/2+45&&m.y>YSIZE/3&&m.y<YSIZE/3+30)
    	     	    return;
    			else if(m.x>XSIZE/2-45&&m.x<XSIZE/2+45&&m.y>YSIZE/3+30&&m.y<YSIZE/3+60)
    			{
					mciSendString("close all", NULL, 0, NULL);	
    				pause=0;
					score=0;
    				return;
     			}
    			else if(m.x>XSIZE/2-45&&m.x<XSIZE/2+45&&m.y>YSIZE/3+60&&m.y<YSIZE/3+90)
				{
					mciSendString("close all", NULL, 0, NULL);	
					pause=0;
					score=0;
					life=0;
					cleardevice();
    				break;
				}
    			else
    				break;
			case WM_MOUSEMOVE:
				RECT r;
				int i;
				for(i=0;i<3;i++)
				{
				    if(m.x>XSIZE/2-45&&m.x<XSIZE/2+45&&m.y>YSIZE/3+i*30&&m.y<YSIZE/3+30+i*30)
				    {
					    r.left=XSIZE/2-45;
					    r.top=YSIZE/3+i*30;
  • 23
    点赞
  • 113
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值