0%

Unity莉丽冒险世界

莉丽冒险世界

简介

项目知识点概况:

  • 通过有限状态机实现了人物的动作切换,采用Input System操作玩家。怪物也采用状态机,设计简单的WayPoint类规划巡逻点。
  • 数据存储为二进制,Json,PlayerPrefs三种形式,Serializable游戏数据对象GameData,便于存取。
  • 人物动画为Setlnteger等触发方式,效果融合平滑。实现loading,存档,暂定等UI界面并搭Animation突出效果,用一些协程做效果延迟处理,熟悉特效制作方式。
  • 使用物理系统计算出人物向量速度,设计多种机关障碍物,泳池沼泽,检查点,传送点,导轨台,跳跃台,旗杆等关卡元素,使用碰撞器触发器和一些3D数学计算。
  • 使用常见单例和观察者设计模式,注重逻辑解耦。

由于用了状态机,项目庞大,不能向上个文档那样逐步详解了,只能写个各板块功能的概况,额外写一点项目中遇到的知识难点。

项目地址: 传送门, 演示视频在DEMO文件夹下。

设计文档

这部分概述了代码各分块的功能和说明:

核心代码是entity和playstate部分

设计重点就是维护一个有限状态机,PlayerState包含N多状态,玩家一个时刻只能是处于一个状态,方便管理。而除了状态,切换状态也同样重要,例如player.states.Change<IdlePlayerState>();

经常使用这个Change。

其余的PlayerStateManager等都是围绕这个状态机来实现的,方便管理用。

这个游戏的核心就是通过合理的架构维护状态机,然后修正玩家的状态,其中最主要的就是垂直和水平两个速度,各种手感都是维护这两个变量而呈现出来的。

1.1. Entity

Entity是一个抽象类,比如Player和Enemy,你要是扩展新的也是可以的。主要处理移动和碰撞,提供一些基础属性和方法

1.2. EntityEvents

EntityEvents类定义了由Entity组件触发的所有事件。基础的几个

1
2
3
4
public UnityEvent OnGroundEnter;
public UnityEvent OnGroundExit;
public UnityEvent OnRailsEnter;
public UnityEvent OnRailsExit;

1.3. EntityHitbox

挂在人物身上的,主要是对他人造成伤害或破坏,还允许实体通过反弹来施加伤害以对命中事件做出反应;施加一些力是游戏操作更加丝滑真实。

1.4. EntityState

所有状态的基类。主要是PlayerState和EnemyState继承的,然后搭配相关的StateManager使用,可以实现更多复杂的状态,以下代码强调子类必须实现这几个接口。

1
2
3
4
protected abstract void OnEnter(T entity);
protected abstract void OnExit(T entity);
protected abstract void OnStep(T entity);
public abstract void OnContact(T entity, Collider other);

1.5. EntityStateManager

跟上面是搭配使用的,主要是管理状态的,然后可以切换。动画状态机基本就是这个的可视化,这样理解更加直观一些。

1.6. EntityStateManagerEvents

核心就这三个事件

1
2
3
public UnityEvent onChange;
public UnityEvent<Type> onEnter;
public UnityEvent<Type> onExit;

比如onChange就被PlayerAnimator监听去了,这也就是为什么切换状态的时候人物总是能做对动画,同理怪物的也是。

1.7. EntityStateManagerListener

维护一个states状态组,当状态进入或者退出的时候,你关心的这个states就可以做一些操作了,这个用在了人物攻击的时候。

1
2
3
4
5
6
7
protected virtual void OnEnter(Type state)
{
if (states.Contains(state.Name))
{
onEnter.Invoke();
}
}

1.8. EntityStats

是一个Scriptable脚本记录了所有的状态值,好处是完全可以开放给策划配置,或者说搞一个excel读进来,不过这不是本例子的实现方式。

1.9. EntityStatsManager

搭配上面使用的

1.10. EntityVolumeEffector

主要是后期的泥浆Mud用这个,可以很好的处理玩家的缓动速度

1
2
3
4
5
6
7
8
9
10
11
12
protected virtual void OnTriggerEnter(Collider other)
{
if (other.TryGetComponent(out Entity entity))
{
entity.velocity *= velocityConversion;
entity.accelerationMultiplier = accelerationMultiplier;
entity.topSpeedMultiplier = topSpeedMultiplier;
entity.decelerationMultiplier = decelerationMultiplier;
entity.turningDragMultiplier = turningDragMultiplier;
entity.gravityMultiplier = gravityMultiplier;
}
}

1.11. PlayerInputManager

这个主要是读取了配置好的操作表,然后专注于写相应逻辑

1
2
3
4
5
6
7
8
9
10
protected InputAction m_movement;
m_movement = actions["Movement"];

public virtual Vector3 GetMovementDirection()
{
if (Time.time < m_movementDirectionUnlockTime) return Vector3.zero;

var value = m_movement.ReadValue<Vector2>();
return GetAxisWithCrossDeadZone(value);
}

1.12. 玩家各个状态

在playstate里,直白的命名了,用来给状态机来调用。

项目涉及

  1. 有限状态机
    1. 一个时刻只处于一个状态
    2. 切换条件判定
  2. 输入系统
    1. Input System
  3. 序列化存储
    1. 二进制
    2. json
    3. PlayerPrefs
  4. UGUI
    1. 基础设计
    2. UI动画
    3. 基础优化
    4. 核心组件
  5. 动画切换
    1. 切换方式
    2. 切换阀值
    3. 优化点
  6. 物理计算
    1. 碰撞和触发
    2. 3D计算
    3. 刚体
  7. 设计模式
    1. 单例模式
    2. 观察者模式
  8. 特效制作
    1. 简单实用
    2. 优化点
    3. UIPraticle
  9. 协程
    1. 基本原理
    2. 线程区别
    3. 应用场景
  10. 怪物巡逻
    1. 点序列检测计算
    2. 怪物状态机
  11. 摄像机控制
    1. 插件使用
    2. 穿墙设置