我的超级马里奥我做主会漂移掉头带刹车

你见过这样的超级马里奥吗?

跑着跑着突然停下来个帅气掉头,还自带刹车音效:

00:05

“踩”扁“板栗仔”(goomba)时直接“变酷”(得到一副墨镜):

这,就是一位油管博主用C++和SFML自己从头制作的红白机版超级马里奥。

C++不用介绍,SFML想必有很多人也熟悉,就是一个用来简化写小游戏或者多媒体应用程序的API,包括系统,窗口,图形,音频和网络五大模块。

除了常规的功能和操作,你可以加入任何自己喜欢的元素。

由于画面看起来实在太逼真,有人甚至提醒博主:小心“版权狂魔”任天堂来找你哦!

心动么?

你也可以自己做一个~

话不多说,来看教程。

手把手教你用C++打造超级马里奥

一共分为4大块。

1、基本控制

设置游戏窗口大小为x。

我们先自己绘制一个留胡子的小伙子——马里奥。

通过函数将它载入程序。

Mario::Mario():x(0.5f*SCREEN_WIDTH),y(0.5f*SCREEN_HEIGHT){texture.loadFromFile(Resources/Images/Mario.png);sprite.setTexture(texture);}voidMario::draw(sf::RenderWindowi_window){sprite.setPosition(round(x),round(y));i_window.draw(sprite);}得到这样的界面:

然后处理地图,由于地图的宽度不同,将它存储为数组向量。

typedefs::vectorstd::arrayCel1,SCREEN_HEIGHT/CELL_SIZEMap;sf::Texturemap_texture;map_texture.1oadFromFile(Resources/Images/Map.png);Mapmap(SCREEN_WIDTH/CELL_SIZE);Mariomario;for(unsignedshorta=θ;amap.size();a++){for(unsignedshortb=map[a].size()-2;bmap[a].size();b++){map[a][b]=Cell::Wa1l;{}

现在画面是这样的:

接着开始集中打造马里奥。

先让他能动起来,前进后退:

并且获得重力:

voidMario::update(){if(1==sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){x-=MARIO_SPEED;}elseif(1==sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){x+=MARIO_SPEED;}vertical_speed+=GRAVITY;y+=vertical_speed;}

有了,但得让马里奥落到地上。

那就获取一下马里奥的坐标,用下面这些公式检查与之相交的所有单元格:

成功:

但是不能让马里奥跑出地图:

voidMario::update(constMapi_map){if(1==sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){x=std::maxfloat(x-MARIO_SPEED,θ);}elseif(1==sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){x=std::minfloat(MARIO_SPEED+x,CELL_SIZE*(i_map.size()-1));}}接下来添加碰撞。

用二进制表示马里奥碰到的单元格,用一个地图碰撞函数检查并返回-这15种可能,然后使用位运算检查方向。

成功:

接下来,看看它能不能跳过这个墙。

显然不行……

搞起来,其中,为了使马里奥的跳跃高度和我们按住键盘的时长为正比,需要创建一个跳跃计时器变量。

if(1==sf::Keyboard::isKeyPressed(sf::Keyboard::Up)){if(θ==vertical_speedθmap_collision(x,1+y,Cell::Wa1l,i_map)){vertical_speed=MARIO_JUMP_SPEED;jump_timer=MARIO_JUMP_TIMER;}elseif(θjump_timer){vertical_speed=MARIO_JUMP_SPEED;jump_timer--;}else{vertical_speed=std::minfloat(GRAVITY+vertical_speed,MAX_VERTICAL_SPEED);}}

再来挑战一下:

完美。

最后,给它添加加速度和摩擦力,也就是我们在文章一开头看到的那种刹车特效。

if(1==sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){horizontal_speed=std::max(horizontal_speed-MARIO_ACCELERATION,-MARIO_WALK_SPEED);}elseif(1==sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){horizontal_speed=std::min(MARIO_ACCELERATION+horizontal_speed,MARIO_WALK_SPEED);}elseif(θhorizontal_speed){horizontal_speed-=MARIO_ACCELERATION;}elseif(θhorizontal_speed){horizontal_speed+=MARIO_ACCELERATION;}

至此,基本控制就完成了,进入地图绘制部分。

2、地图

将地图存为图片之前,需分为两部分,上部分存为砖块,下部分存为实体。

使用一个新函数将图像转为map。

Mapconvert_sketch(constsf::Imagei_map_sketch,Marioi_mario)修改drawback函数获得砖块像素颜色,绘制砖块。再画点云朵,基础地图就好了。

接下来就是挨个绘制剩余元素了。

if(sf::Color(,,85)==pixel)//Flagpole{sprite_x=12;if(sf::Color(,,85)==pixel_up){sprite_y=1}}成果如下:

什么?缺个城堡?作者表示:累了,随便吧……

接下来,使用下面这个公式,让界面跟着马里奥前进后退。

shortview_x=std::clampint(mario.get_x()+0.5f*(CELL_SIZE-SCREEN_WIDTH),θ,CELL_SIZE*n)

地图搞定,上板栗仔!

3、板栗仔

板栗仔的行动和马里奥相似,代码可以基本复制。不同的是一旦它们碰到东西就会改变方向。

如何让板栗仔出现?

当马里奥靠近它们时,更新地图。

voidGoomba::draw(unsigned1_view_x,sf::RenderWindowi_window){if(-CELL_SIZEround(y)round(x)static_castint(i_view_x)-CELL_SIZEround(x){sprite.setTexture(texture);sprite.setPosition(round(x),round(y));i_window.draw(sprite);}}

然后在这部分加上板栗仔和马里奥的的死亡函数,包括两个条件,一是当马里奥跳到板栗仔头上,板栗仔挂;二是当马里奥碰到板栗仔后,马里奥挂。

if(0==death_timer){vertical_speed=std::min(GRAVITY+vertical_speed,MAX_VERTICAL_SPEED);y+=vertical_speed;}elseif(1==death_timer){vertical_speed=MARIO_JUMP_SPEED;}death_timer=std::max(0,death_timer-1);经历过n个bug后,终于没问题。

到了最后一部分了。

4、优化

这部分主要就是做做代码优化,根据自己喜好改变一些原作风格什么的。

比如重新绘制一个马里奥,并分成三种状态:暂停、行走、跳跃以及die。

还有玩家突然切换前进方向时的俏皮动作:

写一个切换状态函数进行控制。

voidAnimation::update(){animation_iterator++;while(animation_iterator=animation_speed){animation_iterator-=animation_speed;current_frame=(1+current_frame)%total_frames;}}终于,全部搞定!!

怎么样?还挺成功吧?

过程其实也不乏挑战,有网友就表示:我以为很简单,直到我看到了代码。

而现在你是不是也对背后的作者产生了一丝好奇?

下面就来认识一下。

作者介绍

这位博主叫Kofybrek,今年6月刚刚成为一名YouTuber,目前已有粉丝。

他用C++做了很多小游戏:包括扫雷、俄罗斯方块、吃豆人等等。

也搞机器学习,比如教AI玩FlappyBird。




转载请注明:http://www.aierlanlan.com/rzgz/2273.html

  • 上一篇文章:
  •   
  • 下一篇文章: 没有了