项目火星番茄交互系统

交互系统

一套可复用的交互组件:看到什么、能做什么、按下去发生什么,都由组件统一管。

进行中C++蓝图

为什么不做进角色里

一开始交互逻辑是写在 BP_Farmer 里的 —— 射线检测、找可交互物、显示提示、执行动作。 写到第四个可交互物的时候问题就来了:机器要交互、载具要交互、NPC 也要交互, 难道每个都往 BP_Farmer 里加分支?

于是抽成组件:谁装谁就能被交互。

UCLASS(ClassGroup=(Tomato), meta=(BlueprintSpawnableComponent))
class UInteractionManagerComponent : public UActorComponent
{
    GENERATED_BODY()

public:
    /** 每帧(或定时)从摄像机前方做一次检测,找最近的候选目标 */
    UFUNCTION(BlueprintCallable, Category="Interaction")
    void UpdateFocus();

    /** 执行当前聚焦目标的交互 */
    UFUNCTION(BlueprintCallable, Category="Interaction")
    void CommitInteraction();

    /** 当前聚焦目标,UI 层据此显示提示 */
    UPROPERTY(BlueprintReadOnly, Category="Interaction")
    TObjectPtr<AActor> FocusedActor;

protected:
    /** 检测距离 */
    UPROPERTY(EditDefaultsOnly, Category="Interaction")
    float TraceDistance = 350.f;

    /** 检测用的通道,用来把「能看的」和「能摸的」分开 */
    UPROPERTY(EditDefaultsOnly, Category="Interaction")
    TEnumAsByte<ECollisionChannel> TraceChannel;
};

关键在于 meta=(BlueprintSpawnableComponent) —— 挂上这个标记,组件才会出现在 蓝图的「添加组件」列表里,视觉层不需要为它写一行代码。

约定

任何想被交互的东西,实现一个统一的接口就行:

UINTERFACE(MinimalAPI, Blueprintable)
class UInteractable : public UInterface { GENERATED_BODY() };

class IInteractable
{
    GENERATED_BODY()
public:
    /** 聚焦时给玩家看的提示文字 */
    UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Interaction")
    FText GetInteractionPrompt() const;

    /** 真正执行 */
    UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Interaction")
    void Interact(AActor* Instigator);
};

BlueprintNativeEvent 是刻意的:C++ 给一个默认实现,蓝图可以覆盖。 箱子、机器、作物都用同一套接口,交互组件完全不需要知道对面是什么。

输入

玩家的输入走 Enhanced Input:

资产 作用
IA_LeftClick 主交互,短按执行 / 长按用于拖拽类操作
IMC_Default 默认输入映射上下文

IA_LeftClick 绑到 CommitInteraction(),「拖拽中」由组件内部的状态决定走哪条分支 —— 一个按键承担两种语义,玩家不会觉得别扭。

光标

WBP_CustomCursor 做了一套自绘光标,兼顾三件事:

  • 不同聚焦状态下形状变化(可交互 / 不可交互 / 拖拽中)
  • 鼠标位置不动时轻微呼吸,避免玩家把它忘了
  • 跟随暂停菜单一起显隐

目前的进展

  • UInteractionManagerComponent C++ 实现 + 蓝图继承
  • IInteractable 接口与蓝图覆盖
  • IA_LeftClick / IMC_Default 输入绑定
  • WBP_CustomCursor 自绘光标
  • 长按与短按的判定阈值调优
  • 拖拽物体时的物理反馈