You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity网球游戏项目中命令模式无法实现的问题求助

Unity命令模式实现问题:左箭头键无响应修复

问题概述

在Unity网球游戏项目中实现命令模式,已完成Command接口、LeftCommand/RightCommand命令类、Invoker调用类,以及关联Player的Character脚本,但按下左箭头键时角色毫无反应。

问题代码

Command.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface Command 
{
    void Execute();
}

RightCommand.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RightCommand : Command
{
    Vector3 position;
    float speed = 3f;

    public RightCommand(Vector3 vector)
    {
        position = vector;
    }

    public void Execute()
    {
        position.x -= speed * Time.deltaTime;
    }
}

LeftCommand.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LeftCommand : Command
{
    Vector3 position;
    float speed = 3f;

    public LeftCommand(Vector3 vector)
    {
        position = vector;
    }

    public void Execute()
    {
        position.x += speed * Time.deltaTime;
    }
}

Invoker.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Invoker 
{
    Stack<Command> mCommands;

    public Invoker()
    {
        mCommands = new Stack<Command>();
    }
    public void Execute(Command command)
    {
        if (command != null)
        {
            mCommands.Push(command);
            mCommands.Peek().Execute();
        }
    }
}

Character.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Character : MonoBehaviour
{
    public Leftmove left;
    float speed = 3f;
    float force = 10;
    bool hit;
    public Transform target;
    public Transform Tennisball;
    Animator animator;
    private Invoker minvoker;

    void Start()
    {
        minvoker = new Invoker();
        animator = GetComponent<Animator>();
    }

    void Update()
    {
        Vector3 position = transform.position;
        Vector3 positiont = target.position;

        if (Input.GetKeyDown(KeyCode.F))
        {
            hit = true;
        }
        else if (Input.GetKeyUp(KeyCode.F))
        {
            hit = false;
        }

        if (Input.GetKey(KeyCode.LeftArrow) && hit == false)
        {
            Command command = new LeftCommand(position);
            minvoker.Execute(command);
        }

        if (Input.GetKey(KeyCode.RightArrow) && hit == false)
        {
            position.x -= speed * Time.deltaTime;
        }

        if (Input.GetKey(KeyCode.UpArrow) && hit == false)
        {
            position.z -= speed * Time.deltaTime;
        }

        if (Input.GetKey(KeyCode.DownArrow) && hit == false)
        {
            position.z += speed * Time.deltaTime;
        }

        if ((hit == true) && (Input.GetKey(KeyCode.LeftArrow)))
        {
            positiont.x += speed * Time.deltaTime;
        }

        if ((hit == true) && (Input.GetKey(KeyCode.RightArrow)))
        {
            positiont.x -= speed * Time.deltaTime;
        }

        if ((hit == true) && (Input.GetKey(KeyCode.UpArrow)))
        {
            positiont.z -= speed * Time.deltaTime;
        }

        if ((hit == true) && (Input.GetKey(KeyCode.DownArrow)))
        {
            positiont.z += speed * Time.deltaTime;
        }

        transform.position = position;
        target.position = positiont;
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Tennis ball"))
        {
            Vector3 dir = target.position - transform.position;
            other.GetComponent<Rigidbody>().velocity = dir.normalized * force + new Vector3(0, 10, 0);
            Vector3 side = Tennisball.position - transform.position;
            if (side.x >= 0)
            {
                animator.Play("backhand play");
            }
            else
            {
                animator.Play("forehand play");
            }
        }
    }
}

问题原因与修复方案

核心问题:值类型传递导致修改无效

Vector3是值类型,创建LeftCommand时传入的position是transform.position的副本,命令中修改的只是这个副本,不会影响角色的实际位置。命令类需要直接持有角色的Transform引用,才能真正修改位置。

修改后的命令类

LeftCommand.cs

using UnityEngine;

public class LeftCommand : Command
{
    private Transform _transform;
    private float _speed = 3f;

    // 传入角色的Transform引用
    public LeftCommand(Transform characterTransform)
    {
        _transform = characterTransform;
    }

    public void Execute()
    {
        // 直接修改Transform的位置,根据原有逻辑调整方向
        Vector3 newPos = _transform.position;
        newPos.x += _speed * Time.deltaTime;
        _transform.position = newPos;
    }
}

RightCommand.cs

using UnityEngine;

public class RightCommand : Command
{
    private Transform _transform;
    private float _speed = 3f;

    public RightCommand(Transform characterTransform)
    {
        _transform = characterTransform;
    }

    public void Execute()
    {
        Vector3 newPos = _transform.position;
        newPos.x -= _speed * Time.deltaTime;
        _transform.position = newPos;
    }
}

修改Character.cs中的调用逻辑

在左箭头键触发时,传入角色自身的transform而非position:

if (Input.GetKey(KeyCode.LeftArrow) && hit == false)
{
    Command command = new LeftCommand(transform);
    minvoker.Execute(command);
}

额外优化建议

  • 避免重复创建命令实例:提前初始化左右命令对象,每次按键时复用,减少内存开销。
  • 统一速度参数:将速度值提取为可配置的公共变量,在Character或命令类中统一管理,避免硬编码。
  • 命令撤销逻辑:利用Invoker的栈结构添加Undo方法,弹出栈顶命令并执行反向操作(需为命令添加Undo接口)。

内容的提问来源于stack exchange,提问作者Dramus17

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 18:30:49