学习Unity也有段时间了,准备做一款小demo来试试身手。设计思路是按照mmorpg游戏的模式设计一款拥有:战斗系统、武器系统、商店系统的小游戏。
视频地址
以下是项目代码UML图:
战斗系统:
建立了一个基类Icharactor后,主角和敌人之间交互的通用部分可以通过调用对方的Icharactor类来实现,各自独立拥有的方法可以放在各自的类中,其中用到的思路就是c#等面向对象语言的继承的思想,公有的方法放在公有的基类中,独立的方法放在子类,互不干扰。当主角攻击敌人时,会调用敌人父类的承受攻击(TakeDamage)的方法。
每个人物拥有各种状态,状态间的转换可以用状态机的思想,以下是我对状态机的理解:
敌人Soldier类拥有FsmSystem状态机进行状态管理
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
public class SoldierFsm : IEnemy
{
public GameObject enemy;
FsmEnemySystem fsmSystem;
private void Start()
{
InitFsm();
}
void InitFsm()
{
//创建FsmSystem类
fsmSystem = new FsmEnemySystem();
//实例化状态类
FsmEnemyState patrol = new EnemyPatrol(fsmSystem,this);
//添加转换条件和状态
patrol.AddTransition(EnemyTransition.InSight, EnemyStateID.Chase);
FsmEnemyState chase = new EnemyChase(fsmSystem, this);
chase.AddTransition(EnemyTransition.OutOfSight, EnemyStateID.Patrol);
chase.AddTransition(EnemyTransition.InAttackRange, EnemyStateID.Attack);
FsmEnemyState attack = new EnemyAttack(fsmSystem, this);
attack.AddTransition(EnemyTransition.OutAttackRange, EnemyStateID.Chase);
//添加各类状态进行管理
fsmSystem.AddState(patrol);
fsmSystem.AddState(chase);
fsmSystem.AddState(attack);
}
private void Update()
{
fsmSystem.Update(enemy);
}
}
具体状态间结构:
当建立了状态机之后,角色的各种状态单独建立了一个类来管理,如状态1,状态2,状态3,它们分别继承自FsmState,FsmState中DoBeforeEntering() DoAfterLeaving() Act()Reason()包含了在状态切换前后和状态持续进行中所需要做的方法,这样做可以保证有些该在Update中调用的方法可以在Act()中实现,该只执行一次的方法可以在DoBeforeEntering或者DoAfterLeaving中实现。
当FsmState中Reason()方法满足到另一个状态的条件时,角色转换状态,FsmSytem中PerformTranstion实现转换状态——>执行状态ID,然后当前ID的FsmState执行Reason()方法到另一个状态,实现状态转换。
武器系统:
出于童年对一款格斗游戏:热血英豪,以及一款至今都视为神作的:上古卷轴5,这2款游戏的喜爱,我在这个demo中加入了可丢弃可拾取的装备系统,每件武器都继承自武器基类Iweapon,Iweapon拥有武器属性类IweaponAttr。
商店系统:
商店系统通过一个InventoryManager管理,InventoryManager拥有商店和背包的基类(Inventory)类,此类可实现物品的存放和交换等功能,具体的UI实现通过slot类完成。
以上都是一些个人见解,如有论述错误,还请海涵。
在做完此demo后,我发现在Unity中具体实现某一种思路并不难,难的是在所有类实现以后,如何对这些类进行管理,以及类与类之间的耦合,调用关系如何更好的设计。这些问题简单的说就是设计模式上的问题吧,做完此demo让我对设计模式有了更深刻的了解,从今以后我也会更加努力的阅读相关书籍,书写更简洁明了的代码。
PS: 对于本demo,今天在阅读过部分设计模式后,类与类之间的关系耦合比较严重这种情况可以解决,那就是使用接口,面向对象中的“面向接口编程”,接口适用于相差较大但拥有共同方法和属性的个体,如demo中敌人和主角都拥有Attack、TakeDamage、Move方法,在使用了接口后,Attack(Enemy)可以改成Attack(Interface),这就体现了面向对象的思想,在类与类之间互动时,调用类不关心被调用类是如何实现此方法的,只关心被调用类实现了哪些接口,然后通过这些接口来调用方法。
目前需要修改大部分代码,重构一些类的方法,等实现后我再更新一篇新文章。。