|
EnHancedInput插件
EnHancedInout插件增加了更加复杂的输入
实现了更多的输入功能
使用EnHancedInput插件
使用EnhancedInput插件需要再编辑器插件中打开
在项目设置里找到输入(Input) =>默认类(Default Classes) 设置为EnhancedInput
主要功能
输入操作(Input Actions)
是Enhanced Input系统和项目代码之间的通信桥梁。输入操作可以是角色的任何交互操作,例如跳跃、开门。输入操作还能表示用户的输入状态,例如按住按钮让角色从行走变为奔跑状态。输入操作与原始输入(raw input)是相互独立的;输入操作无需知道是什么触发了它,但它知道其当前状态,并且最多能将输入值反应在三个维度上(三个独立浮点型数值)。例如,"拾取道具"操作可能只需要一个开/关状态,用于指示用户是否希望角色捡起某个对象,而"行走"操作可能需要两个轴来描述角色行走时的方向和速度。
创建输入操作
创建输入操作
InputAction 编辑
输入操作说明
- Consume Input(输入穿透(是否影响更低优先级的输入))
- Trigger when Paused(游戏暂停状态下是否触发)
- Reserve All Mappings (输入不受高优先级的Mapping控制,需要先手动删除)
- Value Type(输入类型)
- Bool
- Float
- Vector2
- Vector3
- Triggers(输入触发器列表)
- Modifiers(输入修饰符列表)
输入操作使用
- Triggered:触发事件
- Started:开始事件(可能也会Triggered)
- OnGoing:处理中(需要Trigger列表有支持的Trigger)
- Cancel:取消(需要Trigger列表有支持的Trigger)
- Completed:完成 状态从Trigger->None
- Action Value:(输入值,和InputAction.ValueType对应)
- ElapsedTime:执行的时间
- Trigger Seconds:触发的时间
- Input Action:输入操作
输入映射上下文(Input Mapping Context)
负责将用户的输入映射成输入操作;它可以根据用户需求动态增减或调整优先级。你可以通过 增强输入本地玩家子系统(Enhanced Input Local Player Subsystem) 将一个或多个上下文应用到本地玩家身上,并调整它们的优先级,避免多个输入操作因为尝试读取同一输入而发生的冲突。一个常见情况是,某个按钮既可以用来打开场景中的门,又可以用来拾取背包中的道具。当角色靠近门时,你可以添加"开门"这个上下文。假如角色打开背包,你可以添加"选择道具"这个输入映射上下文,并且让它的优先级高于"开门"。这样,当角色站在门旁边时,仍然可以选择背包中的道具。当角色合上背包后,你可以删除"选择道具"上下文,让"开门"上下文生效。这样就能根据角色的环境来正确地解译用户的输入操作,不再需要在输入层面编写代码来区别对待开门和背包系统。
创建输入映射上下文
输入操作说明
- Mappings(映射列表)
- Input Action Asset(输入操作资产)
- TArray<FEnhancedActionKeyMapping> Mappings;(按键映射列表)
- FKey (按键绑定)
- Triggers(输入触发器,决定是否触发Input Action(输入操作))
- Modifiers(输入修饰符,将原始输入设备的值处理后发送到Triggers触发器)
- IsPlayerMappable(bool值,是否公开到玩家绑定的按键?)
- PlayerMappableOptions (上面的设置)
- Name (名字)
- Display Name (显示名字)
- Display Category (分类)
- Config
使用输入映射
触发器(Triggers)
输入触发器决定了用户输入后是否会激活输入操作(Input Actions)
创建自己的输入触发器
输入触发器的类型
- 显示(Explicit): 如果输入触发器成功,该类型将使输入成功。
- 隐式(Implicit):如果输入触发器和所有其他隐式类型输入触发器成功,该类型将使输入成功。
- 拦截器(Blocker):如果输入触发器成功,该类型将使输入失败。
输入触发器的状态
在处理用户输入后,触发器返回三种状态之一
- 无(None):触发器状态未满足,失败
- 进行中(OnGoing):部分满足,还在处理
- 已触发(Triggered):全部满足
常见的触发器
- 按下(Pressed)
- 按住(Down)
- 抬起(Release)
- 按住多少时间(Hold)
- Hold Time Threshold: 按住多久触发
- Is One Shot:只触发一次?
- Affected By Time Dilation:时间膨胀是否影响
- 每隔一段时间触发(Pluse)
- Trigger On Start:一开始就触发
- Interval:间隔
- Trigger Limit:最大次数
- Affected By Time Dilation:是否受时间膨胀影响
- Actuation Threshold
- 按住并抬起(HoldAndRelease)
- Hold Time Threshold:多久触发
- Affected By Time Dilation:是否受时间膨胀影响
- Actuation Threshold
- 按下并快速释放(Tap)
- Tap Release Time Threshold:按下抬起触发最长时间
- Affected By Time Dilation:是否受时间膨胀影响
- Actuation Threshold
- 其他触发器触发了触发此触发器(Chorded Action)
- Chord Action :其他触发器
- Actuation Threshold
- 用户自定义触发器(Others)
输入修饰(Modifiers)
调整来自用户设备的原始输入的值。在输入映射上下文中,每个输入操作的原始输入可以绑定的任意数量的修饰符。
顾名思义,就是用来改编输入设备获取的输入值,经过一层一层的处理后,传给Trigger
创建自己的输入修饰
常见的修饰符
- 死区(DeadZone):限制值的范围
- 计算:取 -1~1 之间的值 (如果小于LowerThreshold 则为0)
FMath::Min(1.f, (FMath::Max(0.f, FMath::Abs(AxisVal) - LowerThreshold) / (UpperThreshold - LowerThreshold))) * FMath::Sign(AxisVal);
- 最小阈值(Lower Threshold):低于这个值就为0 (需要比Up Threshold小)
- 最大阈值(Up Threshold):大于Lower Threshold 的值根据 值域映射到 [0~1]
- 类型(Type):计算类型
- Axial:每个维度单独计算
- Radial:合并一起计算
- 缩放(Scalar)
- Scalar:三维向量,每个维度的缩放比,bool类型不缩放
- 反向(Negate)
- 多帧平滑(Smooth)
FInputActionValue UInputModifierSmooth::ModifyRaw_Implementation(const UEnhancedPlayerInput* PlayerInput, FInputActionValue CurrentValue, float DeltaTime)
{
uint8 SampleCount = 1;//KeyState->SampleCountAccumulator; // TODO: Need access to axis sample count accumulator here.
// TODO: This could be fired multiple times if modifiers are badly set up, breaking sample count/deltatime updates.
if(AverageValue.GetMagnitudeSq() != 0.f)
{
TotalSampleTime += DeltaTime;
Samples += SampleCount;
}
if (DeltaTime < 0.25f)
{
if (Samples > 0 && TotalSampleTime > 0.0f)
{
// this is seconds/sample
const float AxisSamplingTime = TotalSampleTime / Samples;
check(AxisSamplingTime > 0.0f);
if (CurrentValue.GetMagnitudeSq() && SampleCount > 0)
{
ZeroTime = 0.0f;
if (AverageValue.GetMagnitudeSq())
{
// this isn&#39;t the first tick with non-zero mouse movement
if (DeltaTime < AxisSamplingTime * (SampleCount + 1))
{
// smooth mouse movement so samples/tick is constant
CurrentValue *= DeltaTime / (AxisSamplingTime * SampleCount);
SampleCount = 1;
}
}
AverageValue = CurrentValue * (1.f / SampleCount);
}
else
{
// no mouse movement received
if (ZeroTime < AxisSamplingTime)
{
// zero mouse movement is possibly because less than the mouse sampling interval has passed
CurrentValue = AverageValue.ConvertToType(CurrentValue) * (DeltaTime / AxisSamplingTime);
}
else
{
ClearSmoothedAxis();
}
ZeroTime += DeltaTime; // increment length of time we&#39;ve been at zero
}
}
}
else
{
// if we had an abnormally long frame, clear everything so it doesn&#39;t distort the results
ClearSmoothedAxis();
}
// TODO: FortPlayerInput clears the sample count accumulator here!
//KeyState->SampleCountAccumulator = 0;
return CurrentValue;
}
FInputActionValue UInputModifierResponseCurveExponential::ModifyRaw_Implementation(const UEnhancedPlayerInput* PlayerInput, FInputActionValue CurrentValue, float DeltaTime)
{
FVector ResponseValue = CurrentValue.Get<FVector>();
switch (CurrentValue.GetValueType())
{
case EInputActionValueType::Axis3D:
ResponseValue.Z = CurveExponent.Z != 1.f ? FMath::Sign(ResponseValue.Z) * FMath::Pow(FMath::Abs(ResponseValue.Z), CurveExponent.Z) : ResponseValue.Z;
//[[fallthrough]];
case EInputActionValueType::Axis2D:
ResponseValue.Y = CurveExponent.Y != 1.f ? FMath::Sign(ResponseValue.Y) * FMath::Pow(FMath::Abs(ResponseValue.Y), CurveExponent.Y) : ResponseValue.Y;
//[[fallthrough]];
case EInputActionValueType::Axis1D:
ResponseValue.X = CurveExponent.X != 1.f ? FMath::Sign(ResponseValue.X) * FMath::Pow(FMath::Abs(ResponseValue.X), CurveExponent.X) : ResponseValue.X;
break;
}
return ResponseValue;
};
- 用户曲线(User Defined)
- X曲线: X轴二维曲线资源
- Y曲线: Y轴二维曲线资源
- Z曲线: Z轴二维曲线资源
- 使用FOV 缩放(FOV Scaling)
- 缩放比例(FOVScale)
- 类型(FOVScaling Type)
const float FOVAngle = PC->PlayerCameraManager ? PC->PlayerCameraManager->GetFOVAngle() : 1.f;
float Scale = FOVScale;
const float kPlayerInput_BaseFOV = 80.0f;
const float BaseHalfFOV = kPlayerInput_BaseFOV * 0.5f;
const float HalfFOV = FOVAngle * 0.5f;
const float BaseTanHalfFOV = FMath::Tan(FMath::DegreesToRadians(BaseHalfFOV));
const float TanHalfFOV = FMath::Tan(FMath::DegreesToRadians(HalfFOV));
check(BaseTanHalfFOV > 0.0f);
Scale *= (TanHalfFOV / BaseTanHalfFOV);
return CurrentValue * Scale;
const float FOVAngle = PC->PlayerCameraManager ? PC->PlayerCameraManager->GetFOVAngle() : 1.f;
float Scale = FOVScale;
Scale *= FOVAngle;
return CurrentValue * Scale;
- 转到世界空间坐标 (WorldSpace)
- 简单的把输入改成了Unreal的世界坐标空间的值 (x,y,z)=>(z,x,y)
- 交换轴输入(SwizzleAxis)
- YXZ: (x,y,z)=>(y,x,z)
- ZYX: (x,y,z)=>(z,y,x)
- XZY: (x,y,z)=>(x,z,y)
- YZX: (x,y,z)=>(y,z,x)
- ZXY: (x,y,z)=>(z,x,y)
- 输入修饰集合(Collection)
- Modifiers:输入修饰集合
- Permit Value Type Modification:是否改变当前的输入(好像没啥软用)
- Other:用户自定义的输入修饰,由蓝图创建出来
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|