实战中的问题

一、人物为什么没有动画情况下是张开双臂的状态

答案:建模时要绑定骨骼,四肢要明确反映出来,具体到底是头躯干还是腿,默认使用T字模型。

image-20250513192539849

二、速通新InputSystem

1.InputSystem是什么

绑定—》按下—》开始、触发、结束三个事件

image-20250513195720758

2.Action参数

image-20250513195825416

3.输入动作设置

image-20250513195925764

image-20250513200037698

4. 相互作用设置

image-20250513200141829 image-20250513200222174

5.值加工设置

image-20250513200317383

image-20250513200339248image-20250513200410300


6.按键绑定

image-20250513200602173 image-20250513200741059

7.InputAction类使用

(1)启用输入检测

委托变量.Enable();

image-20250513200949511

(2)操作监听

三个基本事件

image-20250513201123303

监听函数

使用CallbackContext获取信息

CallbackContext context参数包含了触发动作的所有信息。你可以使用这个上下文来访问更多细节,例如:

  • context.ReadValue<float>(): 获取输入值(例如,对于键盘按键或手柄按钮)。
  • context.control: 获取触发该动作的输入控件。
  • context.interaction: 获取当前交互类型(例如,是否为按下、释放等)。
  • context.phase: 获取当前事件阶段(例如,Started、Performed、Canceled等)。
image-20250513201600648 image-20250513201712410

8.InputSystem Packages设置

image-20250513203412847

三.=>是什么意思

=>是C# 6.0引入的表达式体成员语法,它允许将方法体简写为一个表达式。

1
protected virtual void Awake() => CacheAction();

等价于

1
2
3
4
protected virtual void Awake()
{
CacheAction();
}

四、?.用法

判断实例在不在,在才能执行(点出来)

1
2
3
4
5
6
  m_moveEvent?.Enable();//判断m_movezEvent在不在,在就执行

//等价
if(m_moveEvent!=null){
aaa.Enable();
}

五、自引用泛型抽象类 Entity<T>

CRTP(Curiously Recurring Template Pattern)是一种利用模板继承实现 静态多态(Static Polymorphism) 的设计模式。通过基类模板以派生类作为模板参数,CRTP 允许在编译期实现多态行为,避免虚函数开销,同时提供灵活的类型操作。以下通过代码和底层原理全面解析其实现和应用。

1
2
3
4
5
6
7
8
9
10
public abstract class Entity : MonoBehaviour
{

}

public abstract class Entity<T> : Entity where T:Entity<T>
{

}

  • 自引用泛型约束

    1
    where T : Entity<T>

    是关键,它强制要求:

    • T 必须是 Entity<T> 的子类(或自身)。
    • 例如:Human 类继承自 Entity<Human>,此时 T 被约束为 Human
  • 设计目的:

    • 类型安全:在基类中可以直接使用 T 类型,而无需强制类型转换。
    • 自引用支持:允许在基类中实现需要返回子类类型的方法(如克隆、工厂模式)。
    • 扩展性:为具体实体类提供类型安全的通用逻辑。

例子:

1
2
3
4
5
6
7
8
public class Human : Entity<Human>
{
// 可以通过T直接引用自身类型
public T GetClone() {
Human clone = new Human();
return (T)clone; // 无需强制转换,因为T被约束为Human
}
}
image-20250513215940133

六、通过反射动态创建泛型类型实例

1
(EntityState<T>)System.Activator.CreateInstance(System.Type.GetType(typeName));
  1. Type.GetType(typeName)
    • 根据字符串 typeName 获取类型信息。
    • typeName 必须是完整的类型名称(包括命名空间),例如:
      • 非泛型类型:"MyNamespace.MyClass"
      • 泛型类型:"MyNamespace.EntityState1[[System.String, mscorlib]]”`(需转义)
  2. Activator.CreateInstance(Type)
    • 动态创建指定类型的实例。
    • 如果类型不存在或无法实例化(如抽象类),会抛出 ArgumentNullExceptionMissingMethodException 等异常。
  3. 强制转换 (EntityState<T>)
    • 假设 typeName 对应的类型是 EntityState<T> 或其派生类。
    • 如果类型不兼容,会抛出 InvalidCastException

疑惑:为什么要用反射动态创建泛型类型实例

答:泛型参数 T 在编译时未知,需根据运行时逻辑确定。这样可以避免每个T重复代码。

七、线性过度平滑

从死区外的范围重新映射到0到1之间,实现了在离开死区后的线性平滑过渡,从而避免输入值的突然跳跃。

  • 数学映射过程 :(要映射的值-死区值)/(1-死区值)
  1. 输入值在死区内value ≤ deadzone):
    • 计算结果为负数(如 value=0.1, deadzone=0.2(0.1-0.2)/0.8 = -0.125)。
    • 实际使用时通常截断为0,表示忽略死区内的微小输入。
  2. 输入值在死区外value > deadzone):
    • 将原始输入范围 [deadzone, 1] 线性映射到 [0, 1]
    • 示例
      • deadzone=0.2value=0.3(0.3-0.2)/0.8 = 0.125
      • value=1(1-0.2)/0.8 = 1
1
2
axis.x = Mathf.Abs(axis.x) > deadzone ? RemapToDeadzone(axis.x,deadzone) : 0;
protected float RemapToDeadzone(float value, float deadzone) => (value - deadzone) / (1 - deadzone);