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
相关产品推荐
相关产品推荐

