[Unity] 战斗系统学习 6:构建 TPS 框架 2

本文介绍了在Unity中构建第三人称射击(TPS)游戏框架的过程,探讨了Port与BBParameter的使用,强调了组件接口的优化和解耦,通过实例解释了如何将冲刺、禁止玩家输入、速度覆盖等功能进行分离和重构,以减少连线并提高代码可读性。此外,还讨论了自定义节点与公有函数的选择,并分享了在LatentActionNode中处理Break的技巧。
摘要由CSDN通过智能技术生成

1. Port 与 BBParameter

我一开始就是公开组件接口,那个时候是因为我还只会用 AddValueInput,不会用 BBParameter
但是后来我发现 BBParameter 很简单之后,我就想在每个地方都用上 BBParameter 了,因为我希望连线尽可能少
但是后面我又发现其实直接用接口的话,他会设置默认的 self 传进来,这样其实对于有默认值的接口,也不用连很多线
那么把这个接口暴露出来的意义就是,让人知道明确知道有这么一个东西需要连,一眼看过去就知道,而不需要点开这个节点看需要什么黑板值
而黑板值用在一些具体细节的布置上,比如我摄像机的偏移为多少,角色速度调到多少,很多时候这些都是一个死的东西,不需要连线,也不需要黑板上有值,给个字面值就可以了的这种

但是由于 FlowCanvas 只会对多 Component 接口的第一个接口设置默认的 self,这就强迫设计者一个函数只能用一个组件
某种程度上也算是强迫解耦了?

1.1 冲刺 v6

在这里插入图片描述

例如原来我会把禁止玩家输入和速度覆盖放在一起,然后用两个组件,然后这两个组件都是黑板值,现在我把组件接口暴露出来,然后解耦了禁止输入和速度覆盖

2. 自定义节点与公有函数

一开始我想什么都用自定义节点
但是我发现了单一组件原则之后,对比自定义节点与公有函数,它们都是处理一个组件内的事情,那为什么不直接在组件里面写函数呢?
组件内写函数反而方便在 FlowScript 中组合
只有对于那些真的很基础的节点才需要自定义节点,比如我想要给 wait 添加一个时间缩放啥的,不得不新建一个带缩放因子变量的节点

2.1 冲刺 v7

在这里插入图片描述

比如我原来会把速度覆盖与计时放在一起,现在想想确实没必要,新建一个这样的节点浪费工作量

3. LatentActionNode 的 Break

LatentActionNode 的 Break 会直接触发 Finish

3.1 瞄准 v4

在这里插入图片描述

我原来是想在协程结束之后把瞄准图标 SetActive(false)
但是 Break 会直接触发协程的 FinishFinish 又会触发 SetActive(false),因此这就相当于我要显示图标的同时把他 SetActive(true) SetActive(false),这就很迷惑

在这里插入图片描述

所以干脆不要这个 SetActive 了,直接一直为 true

4. 运动模式

4.1 瞄准 v5

后面我又觉得其实没有必要特意把一个 CanvasGroup 连出来
于是瞄准变成这样

在这里插入图片描述

在这里我使用了第二个 set style 然后我还注意到所有的功能都是迫不得已一个组件的
然后接下来我又发现 locomotion 的计算也需要改变,因为我的基本运动是人物会朝着摄像机方向+输入方向的,持枪的时候人物应该始终朝着前面,所以人物移动应该是朝着摄像机的前方向和右方向的
这就要求我再在一个地方注意更改
这样我就想到,为什么我不给一个组件做一个模式改变的函数呢?模式改变所需要的参数,模式改变具体要用的函数,感觉也不需要在运行时用到,暴露出来也没有意义

4.2 瞄准 v6

于是修改之后就变成这样

在这里插入图片描述

看上去就很简洁

4.3 Locomotion v4

Assets/MeowFramework/TPSCharacter/Scripts/TPSCharacterLocomotionController.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 16/03/2022 16:53
// 最后一次修改于: 10/04/2022 22:09
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------

using System.Collections;
using System.ComponentModel;
using Cinemachine;
using MeowFramework.Core;
using Sirenix.OdinInspector;
using UnityEngine;

namespace MeowFramework.TPSCharacter
{
   
	/// <summary>
	/// 第三人称运动控制器
	/// </summary>
    public class TPSCharacterLocomotionController : SerializedMonoBehaviour
    {
   
	    // 常量
	    
	    /// <summary>
	    /// 微量
	    /// </summary>
	    private const float Threshold = 0.01f;
	    
	    // 组件相关

	    /// <summary>
	    /// 角色控制器
	    /// </summary>
	    [BoxGroup("Component")]
	    [Required]
	    [Tooltip("角色控制器")]
	    public CharacterController CharacterCtr;

	    /// <summary>
	    /// ACT 输入控制器
	    /// </summary>
	    [BoxGroup("Component")]
	    [Required]
	    [Tooltip("ACT 输入控制器")]
	    public TPSCharacterInputController ACTInput;
	    
	    /// <summary>
	    /// 摄像机跟随点
	    /// </summary>
	    [BoxGroup("Component")]
	    [Required]
	    [Tooltip("摄像机跟随点")]
	    public GameObject CMCameraFollowTarget;

	    /// <summary>
	    /// 主摄像机
	    /// </summary>
	    [BoxGroup("Component")]
	    [Sirenix.OdinInspector.ReadOnly]
	    [Tooltip("主摄像机")]
	    public Camera MainCamera;
	    
	    /// <summary>
	    /// 跟随主角的摄像机
	    /// </summary>
	    [BoxGroup("Component")]
	    [Sirenix.OdinInspector.ReadOnly]
	    [Tooltip("跟随主角的摄像机")]
	    public CinemachineVirtualCamera PlayerFollowCamera;
	    
	    // 模式
	    
	    /// <summary>
	    /// 行动模式
	    /// </summary>
	    [BoxGroup("Mode")]
	    [ShowInInspector]
	    [Sirenix.OdinInspector.ReadOnly]
	    [Description("行动模式")]
	    private TPSCharacterBehaviourMode mode;

	    /// <summary>
	    /// 切换模式的过渡时间
	    /// </summary>
	    [BoxGroup("Mode")]
	    [ShowInInspector]
	    [Description("切换模式的过渡时间")]
	    private float modeTransitionTime = 1f;

	    /// <summary>
	    /// 没有武器时摄像机的 FOV
	    /// </summary>
	    [BoxGroup("Mode")]
	    [ShowInInspector]
	    [Description("摄像机的目标 FOV")]
	    private float noWeaponFOV = 40f;
	    
	    /// <summary>
	    /// 持步枪时摄像机的 FOV
	    /// </summary>
	    [BoxGroup("Mode")]
	    [ShowInInspector]
	    [Description("摄像机的目标 FOV")]
	    private float rifleFOV = 30f;
	    
	    /// <summary>
	    /// 摄像机的 FOV 的平滑时间
	    /// </summary>
	    [BoxGroup("Mode")]
	    [ShowInInspector]
	    [Description("摄像机的目标 FOV 的平滑时间")]
	    private float fovSmoothTime = 0.2f;
        
	    /// <summary>
	    /// 没有武器时摄像机的侧向位置
	    /// </summary>
	    [BoxGroup("Mode")]
	    [ShowInInspector]
	    [Description("摄像机的目标侧向位置")]
	    private float noWeaponSide = 0.5f;

	    /// <summary>
	    /// 持步枪时摄像机的侧向位置
	    /// </summary>
	    [BoxGroup("Mode")]
	    [ShowInInspector]
	    [Description("摄像机的目标侧向位置")]
	    private float rifleSide = 1f;
	    
	    /// <summary>
	    /// 摄像机侧向位置的平滑时间
	    /// </summary>
	    [BoxGroup("Mode")]
	    [ShowInInspector]
	    [Description("摄像机侧向位置的平滑时间")]
	    private float cameraSideSmoothTime = 0.2f;
	    
	    // 运动相关
	    
	    /// <summary>
	    /// 可资产化水平速度
	    /// </summary>
	    [BoxGroup("Velocity")]
	    [Required]
	    [Tooltip("可资产化水平速度")]
	    public ScriptableVector3Variable HorizontalVelocity;

	    /// <summary>
	    /// 可资产化竖直速度
	    /// </summary>
	    [BoxGroup("Velocity")]
	    [Required]
	    [Tooltip("可资产化竖直速度")]
	    public ScriptableFloatVariable VerticalVelocity;

	    /// <summary>
	    /// 水平速度是否被覆盖了
	    /// </summary>
	    [BoxGroup("Velocity")]
	    [HorizontalGroup("Velocity/HorizontalVelocityOverride")]
	    [ShowInInspector]
	    [Sirenix.OdinInspector.ReadOnly]
	    [Tooltip("水平速度覆盖值")]
	    private bool isHorizontalVelocityOverrided;
	    
	    /// <summary>
	    /// 水平速度覆盖值
	    /// </summary>
	    [BoxGroup("Velocity")]
	    [HorizontalGroup("Velocity/HorizontalVelocityOverride")]
	    [ShowInInspector]
	    [Sirenix.OdinInspector.ReadOnly]
	    [Tooltip("水平速度覆盖值")]
	    private float horizontalVelocityOverride;

	    // 行走相关

	    /// <summary>
	    /// 移动速度
	    /// </summary>
	    [BoxGroup("Walk")]
	    [ShowInInspector]
	    [Tooltip("移动速度")]
	    private float walkSpeed = 7f;

	    /// <summary>
	    /// 玩家行走的过渡时间
	    /// </summary>
	    [BoxGroup("Walk")]
	    [ShowInInspector]
	    [Tooltip("玩家行走的过渡时间")]
	    private float walkSmoothTime = 0.2f;

	    /// <summary>
	    /// 玩家旋转的过渡时间
	    /// 如果这个值过大,由于使用了 SmoothDamp,会让镜头移动出现明显的粘滞感
	    /// </summary>
	    [BoxGroup("Walk")]
	    [ShowInInspector]
	    [Tooltip("玩家旋转的过渡时间")]
	    private float rotationSmoothTime = 0.1f;

	    // 物理相关
	    
	    /// <summary>
	    /// 重力系数
	    /// </summary>
	    [BoxGroup("Gravity")]
	    [ShowInInspector]
	    [Tooltip("重力系数")]
	    private float gravity = -9.8f;
	    
	    /// <summary>
	    /// 最大下落速度
	    /// </summary>
	    [BoxGroup("Gravity")]
	    [ShowInInspector]
	    [Tooltip("最大下落速度")]
	    private float terminalVelocity = 53f;
	    
	    // 落地相关

	    /// <summary>
	    /// 是否落地
	    /// </summary>
	    [BoxGroup("GroundCheck")]
	    [ShowInInspector]
	    [Sirenix
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值