欢迎光临散文网 会员登陆 & 注册

Unity老游戏复刻计划之《雪人兄弟》(1)

2022-10-14 14:56 作者:皮皮关做游戏  | 我要投稿

未接触过游戏开发但又对其感兴趣的朋友,只需添加如下联系方式(注明B站),便可体验一次激动人心的游戏开发过程——提出需求、思考原理、实现功能、定位bug、设计关卡、更换美术资源......麻雀虽小五脏俱全。更能获取海量游戏开发资料:




(本文作者Khalil)

嗨大家好,我是游戏开发新人Khalil。

今天带给大家的,是一个经典系列——《雪人兄弟》:


不好意思图放错了,应该是这个:


为没玩儿过这款游戏的同学简单介绍一下这个游戏:

《雪人兄弟》是一款东亚企划(Toaplan,已于1994年破产。但主要员工后阿里成立了专做STG的CAVE——代表作就是《首领蜂》系列)于1990年开发的街机平台动作游戏,1991年由东亚企划移植推出任天堂FC版。

今年刚推出的《雪人兄弟特别版》


对绝大部分国内玩家来说,对这游戏的印象应该都是FC移植版。游戏的玩法和FC版《泡泡龙》很像,每关只有1屏的场景,全灭敌人后进入到下一关,且每关都很短。

这次我想要制作的是第十关,也就是第一个boss关。如图:


以前玩的时候贼喜欢这一关。一方面这是最简单的一个boss,另一方面还可以跳到boss身后刷分,无论boss还是杂兵都完全伤害不到站在boss身后的玩家(那会儿就知道刷刷刷了)。

首先是素材。通过皮皮关老师们的推荐,我找到了一个提供很多老游戏素材的网站:

www.spriters-resource.com

素材找到后,它们并非精灵图,而是长这样:


所以还得自己去将其修改为精灵图。用ps的话通过非常简单的操作就可以将素材变为合适的精灵图,不过这里我图方便没有下ps,而是用了一个很好使的网页版简易ps:

ps.gaoding.com

将图片素材准备好后,导入项目中,好像就可以正式开搞了。。。吗?


桥豆麻袋!

成步堂的声音


图片是有了,但是动画还需要自己制作呀。

所以我决定先把动画做了再继续写脚本。

先把导入的精灵图切分。由上面的图可以看到,每张小图的上方都标明了这几个连续图的动作,比如 站立(idle),行走(walk),跳跃(jump),还有人物的登场动画等等。

这就好办了,很快我就把几乎所有的动画用unity制作完成了。具体来说就是创建anim文件,然后将想要制作的动作的图片按顺序插入里面,完事儿。

动画制作完成后,先将背景放入场景中。对每一层地板和墙壁上都加上一个空物体,它们具有碰撞体和刚体,支撑玩家和怪物们的移动。

游戏场景铺设完成后,接下来就可以开始制作游戏角色了。为了简单起见,现在先只制作单人的游戏角色——Nick。对照原版游戏可以很快记录下角色的各种状态:

  1. 移动;

  2. 跳跃;

  3. 发射子弹;

  4. 推动和踢走雪球;

  5. 死亡;

  6. 从下方通过跳跃顶起雪球;

  7. 站在雪球上踢走雪球(按下攻击键),或者被滚动中的雪球撞到,可以跟随雪球移动,在跟随雪球移动的期间为无敌状态;

  8. 在跟随雪球移动的期间按下跳跃键,即可脱离雪球,并进入一段时间的无敌状态。

先从前四种状态说起。

人物的移动和跳跃非常简单。以下面的步骤为例:

  1. 创建玩家控制器和玩家角色脚本,在控制器中使用Input获取玩家按键信息,然后在角色脚本中编写move方法,由fixedupdate调用,通过获取到的按键信息来改变人物的刚体速度,使其能移动和跳跃。

  2. 当然接着就要使用Animator来控制动画的播放。必须说明的是,由于老游戏都是一帧一帧制作出来的,动画非常难以和原版一模一样,只能说尽量接近。当速度大于0.1时,就从初始的idle动作转换到walk(行走)动作;当速度小于0.1也就是停止移动时,转换会idle动作;按下跳跃键时,就从walk和idle动作切换到播放跳跃动作,跳跃动作播放结束之后需要转换到滞空动作,当玩家接触到地面时,再回到idle动作。这些动画器的逻辑基本上是通用的,敌人的动画器也基本上是这样一个逻辑;

  3. 在fixedupdate中还要调用检测角色是否在地面的CheckGround方法,只有角色在地面上,才可以跳跃,限制角色的跳跃次数;

  4. 角色滞空时,左右移动的速度要进行限制,免得角色过于灵活。所以在Fixedupte中判断角色是否在地面,如果不在地面上那么移动速度要减半;

  5. 关于角色的朝向,需要在update中调用一个Filp(转向)方法,如果获取到的按键是朝右移动,那么transform.localScale,改为(-1,1,1),将角色图的x轴翻转,从而让角色面向右。

这种类型的游戏,玩家基本上都可以从地面的下方直接跳跃到上方,就像这样:


实现这种效果很简单。Unity中有一个2d平台效果器,在地面上添加这个效果器,玩家就可以从下方直接跳跃到上方,不会被碰撞体阻拦,并且跳跃到上方后,上方的地面也能正确的“托住”玩家。

角色的移动制作完成后,就要着手制作子弹和玩家发射子弹的功能:

  1. 首先需要赋予子弹刚体和碰撞体,将其制作成一个预制体。鉴于它的形状有点特殊,所以这里可以用多边形碰撞体,非常好使。

  2. 仔细观察游戏中的子弹,发现它会在存活期间不断在蓝红两种颜色间切换,形成闪烁的效果。将两种颜色的子弹做成动画循环播放即可;

  3. 在角色的面前方创建一个子物体FirePoint,让子弹从FirePoint的位置发射出来;

  4. 创建Bullet脚本控制子弹的移动,在update中改变它的位置即可:transform.position += transform.right * speed * Time.deltaTime;,大多数“子弹”都可以用类似这样的方法移动。一般来说子弹都只会向玩家面向的方向直线运动,制作子弹预制体时,都会将其类型设置为Kinematic,但是Nick的子弹是会往下掉落的,所以还是让其保持Dynamic类型,然后在碰撞体中勾选触发器,在脚本中每当触发器触发,则子弹消失;

  5. 在控制器中添加开火键的按键检测,检测到开火键按下则调用在角色脚本中编写的Fire方法。Fire方法很简单,就是在FirePoint的位置通过Instantiate将子弹预制体弹出,并通过开火的cd来限制玩家一段时间内攻击的次数即可。由于子弹的图片也是左右有所不同,所以需要在fire方法中判断玩家面向的方向,如果玩家面朝左,则子弹的右方就变为子弹的左方,也就是子弹会朝左发射。

接下来就需要制作Boss和它的小弟们。这个Boss本身没法攻击(除非玩家自己跳到它的身上),它攻击的手段就是发射自己的小弟,玩家碰到则会死亡。

在仔细观察之后,我发现Boss只会在最底下的地面上和它头上的地面上移动,并且只有下述重复行为:

  1. 刚开始,当Boss在最底层的地面上时,它会进行比较矮的跳跃,重复三次;

  2. 在这三次跳跃结束后,它会做一次非常高的跳跃,跳跃到它头上的高台上,并且在跳跃期间发射自己的Son对玩家进行攻击;

  3. Boss在跳到高台上时,会停顿一段时间,然后会进行一次跳跃,并最终落到底层的地面上。如此往复;

  4. 我发现在原版游戏中Boss每次大的跳跃都会让其往前前进一点点距离,应该是为了压缩玩家的行动空间,但是这样不利于测试,在制作和测试阶段我不打算加上这一效果。

看清规律后,制作它的AI就相对简单很多。

  1. 首先使用enum记录Boss的状态:(1)在地面上三次小跳(2)在地面上大跳(3)在高台上静止(4)从高台上往下跳。

  2. 在update种通过switch控制状态的切换,通过切换状态时设定上次状态转换的时间以及转换的CD,如果时间比上次状态转换的时间加上CD秒数还要多,那么就切换状态;和限制子弹发射频率的逻辑类似;

  3. 编写状态中要调用的方法(要实现的动作),其实就是制作三种不同类型的跳跃方法罢了(小跳,大跳,和向下大跳),也可以只写一种,然后不同状态下传入不同的参数,形成不同的跳跃方式,但是我为了方法间分离得更加清晰就分为了三种。

  4. 编写攻击方法,也就是发射小弟的方法,我最开始打算将攻击和大跳写在一起,因为在大跳的时候Boss也会同时进行攻击,但是这种写法不太好控制小弟的发射位置和频率,所以后面使用了一个简单粗暴的方法:动画帧事件。在大跳跃动作开始时(我写了小跳跃和大跳跃两种方法,具体原因后面会讲到),调用一次攻击方法(与玩家发射子弹的方法类似,且更加简单),在快要结束的一帧,再调用一次攻击方法,如果想要发射更多的小弟,再添加更多的动画帧事件即可,基于测试图个方便,我就只写了一次发射两个小弟。

  5. 设定Boss的血量(我设定为1000),如果Boss碰到滚动中的雪球,则血量下降200点,碰到玩家的子弹则下降1点。血量等于或低于0时Boss死亡,播放死亡动画,使用动画帧事件,在Boss死亡动画播放结束时,移除Boss。

为什么要写大跳和小跳两种跳跃?跳跃动画一般分为跳跃和滞空,直到检测到Boss接触到地面滞空才会结束,才算一次完整的跳跃。

在这次制作过程中,Boss的大跳,需要从地面垂直跳跃到高台上,这个效果使用2D平台效果器可以实现。然而怎么实现从高台上垂直跳跃下来呢?我使用了改变图层的方法,在Boss从上往下跳时,改变Boss的图层,在项目设置中设置高台与向下跳的Boss不能接触。

但是!这样并没有完全解决问题,因为虽然Boss无法和高台接触了,但是地面检测还是可以检测到高台的碰撞体,所以在大跳的期间,CheckGround(地面检测)还是会检测到高台的碰撞体,导致滞空的状态并不会持续,而是会变为初始的idle状态。

所以我决定直接使用动画来解决这个问题,在大跳期间播放大跳动画,只有当动画播放完成时,才会转换会idle动画,大跳动画的持续时间我经过反复调整后,已经可以和Boss未接触到地面的时间基本一致,动画呈现的效果完全没有问题。

这样Boss的制作就完成了,接下来就是小弟的AI。和Boss差不多,在目前的阶段我认为它的AI制作起来还更简单,同样给其添加enum,记录它的状态,在仔细观察后,我认为它有四种状态:

  1. Born,等于其他角色的Idle动作,在Boss将它发射出来时,它是Born状态,是一个球状;

  2. Awake(苏醒状态),也就是小弟被发射到地面或平台上时,一个从球状转换为站立姿势的状态;

  3. 向左走;

  4. 向右走;

没错,小弟是没有静止状态的,只要在过了Awake状态后,地面或者平台上,它就会不停地走动,直到碰到地图最底下的左右两边的边界(接触到边界后就消失),所以我在地图底端的左右两端设定了两个DeadZone,只要接触到DeadZone,小弟就消失;接触到玩家子弹时,小弟也消失,并且在同一位置生成三分之一成品雪球。根据角色和Boss的脚本就能很轻松地完成小弟AI了。


最后是雪球的制作。

玩过原作的朋友都知道,怪物只要被玩家的子弹攻击到,就会变成一个“未完成的雪球”的形状,接着再对这个三分之一成品雪球发射子弹,它就会变得更完整,变为半成品,最后再攻击一次,它就会形成一个完整的雪球,玩家可以推动和站立在它上面,另外它其实只是看起来是圆的,其实玩家能接触到它的地方应该是方的 ,在前面两种状态下,玩家是接触不到雪球的,但是在雪球完全形成后,玩家就可以推动和踢走雪球。

在制作雪球AI时,我遇到了几个问题:

  • 雪球动画的切换不够丝滑,明明已经攻击雪球并使其状态变化了,或者雪球过了它的持续时间,已经开始融化,然而它的动画并没有按照我预想的样子来变化,总会慢那么一两帧;


  • 雪球的移动方式与原版游戏完全不同;

  • 雪球如何带着玩家角色进行移动?

先说前两个问题的解决方式:

雪球状态的切换,同样是使用enum和switch进行状态的控制(有三分之一雪球,半成品雪球,完整雪球,和特殊的、不由雪球自己控制的滚动中的雪球四种状态)。我还给雪球添加了int类型的hp,使用hp作为动画器切换动画的条件,使用OnTriggerEnter2D,当接触到玩家子弹时,雪球就会切换到下一状态并且hp+1,且当时间过了解冻时间时,雪球也会切换为上一个状态并且hp-1。之前用的是float类型,却发现怎么都做效果都不对,后面换为int类型就正常了。

雪球在三分之一雪球、半成品雪球这两种状态时,玩家是接触不到的,我一开始想用录制动画的方法,先关闭雪球的碰撞体,待雪球变为完整雪球时才开启。但是这样的话雪球就会从地图上掉落了,所以后面还是改用改变图层的方法。前面两种状态为一个图层,完整的雪球为另外一个图层,玩家只能接触到完整的雪球。


和老师商讨过后,发现在既有环境下雪球移动的复刻基本上是不可能的。


因为刚体难以实现原版游戏中雪球的移动方式。我想了想别的方法:要想玩家推动雪球并且速度要很慢,直接给雪球增加质量怎么样?

多次测试后我发现,雪球的质量设置为角色质量的三十倍就会很接近原版游戏中的效果。

不容易


接着,玩家踢动雪球时,雪球会高速滚动。然而由于刚体和碰撞体的存在,出来的效果和原版差别很大。比如原版雪球发出来的速度很快,滞空时掉落得却有点慢,并且它会几乎完全根据设定的路线进行高速且匀速的移动,就算碰到其他物体不会停止(由于路线的设定,所以基本上不会横着撞到墙壁或者是平台),会变换方向移动。

但物体引擎可不管这些有的没的,物体该咋动咋动,碰到东西就停,所以在不规定路线的情况下,雪球总会停止移动。


在这里我用了一种很笨的方法解决:把平台的两端和墙壁上(雪球有可能会撞到的地方),都添加上子物体(我叫它们反弹器),添加上刚体和碰撞器,碰撞器设置为触发器,在雪球脚本中使用OnTriggerEnter2D,每当滚动中的雪球接触到这些反弹器,它们就会向反方向移动,这样做了之后,雪球就基本上都会按照规定路线移动了。

第一篇就进行到这里,下一篇内容再和大家分享完善后的版本儿。

工程链接:https://pan.baidu.com/s/1c4ULDJ3Wvvqbb3mguDNCDw

提取码:snow


欢迎加入游戏开发群欢乐搅基:1082025059

Unity老游戏复刻计划之《雪人兄弟》(1)的评论 (共 条)

分享到微博请遵守国家法律