抽时间终于是过完了roguelike的一个项目,相比于前面的single move,这里牵扯了很多核心概念,像gamemanager,time/frame,move等。当然C#的stack也有很多,像函数的模板,携程等。这里主要对该项目的具体代码逻辑,时间设置的安排,以及涉及到的C#的新语法做一总结。

代码主逻辑

player每次移动到exit到下一关,移动会消耗food,food为0时game over。过程中会遇到敌人(碰到会消耗food),以及路障Wall,路障通常会很多,可以通过消耗turn(and food)来破坏。grid也会出现food来补充food。

项目模块

  • BoardManager 生成随机地图和item
  • GameManager* 使用单例模式管理不同scence间的信息传递(food)以及控制主流程
  • MovingObject 可移动物体的泛类
  • Loader 给摄像机的script,用于生成gamemanager
  • Wall 由于墙破坏要更改sprite

BoardManager

由于Random.range涉及到大量min-max,设置Count类来统一管理。具体分布如下:

我们需要设置各种列表:

public GameObject[] floorTiles;
public GameObject[] foodTiles;
public GameObject[] wallTiles;
public GameObject[] outerWallTiles;
public GameObject[] enemyTiles;

列表具体需要从prefabs导入。主要先单独设立item生成区grid(List Vector),使用Instantiate来生成sprite。先铺地板和外墙,再随机在grid中生成路障和food,敌人(每次randomPosition完后remove掉位置放置生成同一区域)。

GameManager

使用static来进行单例模式instance,使用内置函数DontDestoryOnLoad来放置scence消失时的破坏.之后调用boardManager来绘制grid。但在这之前需要有一个关卡介绍,使用Canvas上渲染Image和text。这里也要使用doingSetup变量来防止在set时被update执行。在setActivity了image和更改了text,画面停留时间使用Invoke函数来调用hideCanvas来控制。这里还储存了enemy的列表,boardManager此时生成了enemy,enemy在生成时script的start里将该类加入到该列表。最后在update中,当玩家和敌人都未移动时,即可调用enemymove移动。同时需要设置一个turndelay(0.1s)来在playerturn和enemymove间切换。

每个moveObject都有一个moveTime,代表了一个移动的移动时间。但是调用移动函数moveTowards的maxDelta设为deltaTime/move。每次move后有一个回合等待延时turnDelay.

值得一提的是,OnCantMove是针对不同prefabs的互动,他在判断AttemptMove后调用。因为rigid两物体碰撞不能直接用trigger判断状态,故只能用hit到的物体强转成规定物体然后调用hit物体的函数(player调用wall的walldmg,enemy调用player的playerDmg)。

C# techstack

  • <\T>(T test) where T:parent : where规定了模板T必须继承自parent
  • invoke() 调用一个iterable类型的函数,其可以在delay一个timer后再调用该函数

My Game design

当然搞了那么多教程,最后肯定要亲手把这些碎片拼成一个自己的demo。

大体流程

最后我举个大体的例子,来说下”拼图”的实现。

从不会到会,当然少不了”抄”。我参考的是我最喜欢的GBA游戏MEGAMAN EXE2,大体流程如下demo

大体是双人竞技的棋类对战游戏,双方各执一子可在自己的3*3领域自由移动(当然有短暂移动延时),双方互相使用技能伤害对方同时躲避对方技能,HP为0方战败。

涉及到的几个点:

  1. tilemap构建2 3\3的地图,当然后续应该会扩大成4*4或取消grid化
  2. 人物的移动流畅度,涉及到延时以及rigidbody的移动机制
  3. 发射技能,涉及到特效以及判定机制
  4. 变化属性,这里还没有想好怎么搞

到这里就可以落实到各个实践了,也就结束了。如果你想深入了解此游戏,请继续观看,不然您就可以去着手考虑您的设计方案了。

设计细节

我取消了exe的卡牌机制(当然它是很coool的功能只是我还没法实现),加入了crosscode的元素变更和技能点机制。

属性参考的是crosscode的机制,玩家会随timer获得skill point,每个属性下可以通过消耗技能点发动技能(1/3/5)。技能类型大致分为强攻与AOE(火系为主),防守与控制(冰系为主),改变地形和放置物品(土系为主),强化自身如加速/隐身/增快point timer(风系为主)。当然尽量保证每个属性的功能性均衡。

crosscode中有一种机制叫过载,指的是当你长时间使用元素时会进入惩罚状态。我也希望引入过载机制来限制玩家别老执着于一个模式。即一个模式有一个limit timer。

题外话,提到过载(override),这是我非常喜欢的一个词。过载机制在太多游戏得以实现,crosscode的防止单一使用;空洞骑士的允许你突破槽安装符文,但受伤翻倍;EXE6的双重兽化来允许你突破兽化次数但结束后会掉血,总之就是一种给与你短时间突破上限能力但会导致你后续不断受到惩罚的机制(刀尖上舔血),可以用这种来提高游戏的玩家梯度。我还想额外提一个相近词:超载,这是一种去除惩罚机制的过载,典型的例子就是流星洛克人3的噪音变身,鼓励你不断使用无属性且攻击距离很短的剑拳式技能(因为他们相比于带属性的范围性AOE毫无优点可言),噪音率看上去是一个负面的东西(其实界面不断模糊让你以为不断危险),但其实是一个完全没有副作用的变身机制,当你使用剑拳式技能伤害到200时,你会得到进化,更改一段时间内所有的卡牌质量(你可以理解为一种超高回报,它不同于普通的强化的持久性h,超高回报会让你一段时间内大幅强化自身且不仅限于数据更显与外观,让玩家产生高潮),这是一种鼓励使用但短期回报很少,但积累一定量后会得到超高回报的机制。

OK,这里给出属性所有的设计细节:

  1. base:每种属性都有其特有的特点,可以不断变化(变身时间有cd)
  2. 每个属性不鼓励一直使用,为此每个属性有timer,过度使用会过载
  3. extension: 考虑可以使用不同属性组合的combo,如火+风,这就要求技能可以被以某种形式存储
  4. 考虑引入超载,即存在属性相克,每次相克会积累。当积累一定程度后可以进入超高回报状态(进化)

最后,我们还缺少一个核心机制,就是space time。确实属性间的博弈,技能的累计和躲避,累计combo和进化机制可以让玩家们充分体验在棋盘中自由移动躲避技能,累计大招的快感,但毫无疑问这会导致玩家一直等待point放技能导致双方死锁,一段时间内双方都无所事事。为此我们需要给玩家一个在space time要做的事,而且需要牵制那些等大招流的玩法,为此EXE系列的射击机制无疑是完美的解决,但“射击”无疑与“战棋”概念完全不符,为此我们需要引入一个替代品。

Comments

2019-10-10

⬆︎TOP