Unity星露谷物语风格钓鱼小游戏脚本问题:鱼与钩子异常
问题与修复方案
问题概述
我正在制作一款类似《星露谷物语》(Stardew Valley)钓鱼机制的小游戏,设置了两个空对象作为边界,用于限制鱼和钩子在矩形区域内。运行脚本时遇到两个问题:
- 鱼并非从预设初始位置开始移动,而是直接从底部边界生成并向上移动
- 钩子固定在底部边界,用户点击鼠标时完全没有移动反应
原代码
using System.Collections; using System.Collections.Generic; using UnityEngine; public class FishingMiniGame : MonoBehaviour { //Make the Egg move [Header("Fishing Area")] [SerializeField] Transform topBounds; [SerializeField] Transform bottomBounds; [Header("Fish Settings")] [SerializeField] Transform Fish; [SerializeField] float smoothMotion = 3f; [SerializeField] float fishTimeRandomizer = 3f; float fishPosition; float fishSpeed; float fishTimer; float fishTargetPosition; [Header("Hook Settinds")] [SerializeField] Transform Hook; [SerializeField] float HookSize = .18f; [SerializeField] float HookSpeed = .1f; [SerializeField] float HookGravity = .05f; float hookPosition; float hookPullVelocity; private void FixedUpdate() { MoveFish(); MoveHook(); } private void MoveHook() { if(Input.GetMouseButtonDown(0)) { //increase our pull velocity hookPullVelocity += HookSpeed * Time.deltaTime; //raises out hook } hookPullVelocity -= HookGravity * Time.deltaTime; hookPosition += hookPullVelocity; hookPosition = Mathf.Clamp(hookPosition, 0, 1); //keep the jook withon bounds Hook.position = Vector3.Lerp(bottomBounds.position, topBounds.position, hookPosition); } private void MoveFish() { //based on timer, pick random position //move fish to that position smoothly fishTimer -= Time.deltaTime; if(fishTimer < 0) { //pick a new target position //reset timer fishTimer = Random.value * fishTimeRandomizer; fishTargetPosition = Random.value; } fishPosition = Mathf.SmoothDamp(fishPosition, fishTargetPosition, ref fishSpeed, smoothMotion); Fish.position = Vector3.Lerp(bottomBounds, topBounds, fishPosition); } }
问题分析与修复
1. 鱼的初始位置异常问题
- 原因:
fishTimer未初始化,脚本启动后默认值为0,会立刻触发随机目标位置逻辑,导致鱼直接从底部(fishPosition初始为0)开始移动Vector3.Lerp参数错误:传入了bottomBounds(Transform组件)而非bottomBounds.position(世界坐标),虽Unity会隐式转换,但写法不规范
- 修复:
- 添加
Start()方法初始化鱼的初始状态,让鱼先停在中间位置,再开始随机移动 - 修正
Vector3.Lerp的参数为位置坐标
- 添加
2. 钩子无响应问题
- 原因:
HookSpeed数值过小:0.1 * Time.deltaTime(约0.002)的增量远小于重力减量(0.05 * Time.deltaTime约0.001),点击产生的速度变化可忽略Input.GetMouseButtonDown(0)在FixedUpdate中易漏检:FixedUpdate更新频率与Update不同,单次点击可能错过执行时机
- 修复:
- 调大
HookSpeed至合适数值(比如5),让点击的速度增量明显超过重力 - 改用
Input.GetMouseButton(0)检测按住状态,确保持续输入时钩子能持续获得速度 - 将输入检测移至
Update()方法,避免漏检(Update每帧执行,更适合处理输入)
- 调大
修复后的代码
using System.Collections; using System.Collections.Generic; using UnityEngine; public class FishingMiniGame : MonoBehaviour { [Header("Fishing Area")] [SerializeField] Transform topBounds; [SerializeField] Transform bottomBounds; [Header("Fish Settings")] [SerializeField] Transform Fish; [SerializeField] float smoothMotion = 3f; [SerializeField] float fishTimeRandomizer = 3f; float fishPosition; float fishSpeed; float fishTimer; float fishTargetPosition; [Header("Hook Settings")] // 修正拼写错误 [SerializeField] Transform Hook; [SerializeField] float HookSize = .18f; [SerializeField] float HookSpeed = 5f; // 调大速度值 [SerializeField] float HookGravity = .05f; float hookPosition; float hookPullVelocity; private bool isPulling; // 传递输入状态 private void Start() { // 初始化鱼的初始位置和计时器 float midY = (bottomBounds.position.y + topBounds.position.y) / 2f; fishPosition = (midY - bottomBounds.position.y) / (topBounds.position.y - bottomBounds.position.y); fishTargetPosition = fishPosition; fishTimer = Random.value * fishTimeRandomizer; // 初始化钩子位置 hookPosition = 0; Hook.position = bottomBounds.position; } private void Update() { // 在Update中处理输入,避免漏检 isPulling = Input.GetMouseButton(0); } private void FixedUpdate() { MoveFish(); MoveHook(); } private void MoveHook() { if(isPulling) { // 按住时持续增加拉力速度 hookPullVelocity += HookSpeed * Time.deltaTime; } hookPullVelocity -= HookGravity * Time.deltaTime; // 限制速度,避免钩子移动过快 hookPullVelocity = Mathf.Clamp(hookPullVelocity, -2f, 2f); hookPosition += hookPullVelocity; hookPosition = Mathf.Clamp(hookPosition, 0, 1); Hook.position = Vector3.Lerp(bottomBounds.position, topBounds.position, hookPosition); } private void MoveFish() { fishTimer -= Time.deltaTime; if(fishTimer < 0) { fishTimer = Random.value * fishTimeRandomizer; fishTargetPosition = Random.value; } fishPosition = Mathf.SmoothDamp(fishPosition, fishTargetPosition, ref fishSpeed, smoothMotion); // 修正Lerp参数为位置坐标 Fish.position = Vector3.Lerp(bottomBounds.position, topBounds.position, fishPosition); } }
额外优化点
- 修正了原代码中
Hook Settinds的拼写错误为Hook Settings - 添加了速度限制,防止钩子因持续点击导致速度过大
- 将输入逻辑移至
Update(),确保输入检测更可靠
内容的提问来源于stack exchange,提问作者MarcusLee
相关产品推荐
相关产品推荐

