Unity中ProjectilePool自动发射及攻击失效问题求助
Unity投射物对象池问题解决方案
问题概述
进入Play模式时投射物自动发射,调整设置后又出现对象池无法激活、玩家攻击功能失效的问题。
核心问题根源
- 自动发射原因:对象池取出投射物后未从列表移除,同一实例被重复调用移动方法;且归还时未重置投射物的
moves状态,导致回到池后仍持续移动。 - 对象池失效原因:投射物初始化时未禁用,归还时未重置状态、未禁用GameObject,导致池中实例状态混乱;取出逻辑未移除列表元素,造成实例重复使用和列表膨胀。
分步修复方案
1. 修复对象池核心逻辑(ProjectilePooling.cs)
修正取出/归还逻辑,初始化时禁用投射物,确保实例状态正确:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ProjectilePooling : MonoBehaviour { [SerializeField] float poolLength; public GameObject projectilePrefab; private List<Projectile> projectilesInPool; public static ProjectilePooling Instance; private void Awake() { Instance = this; } void Start() { PoolInitialization(); } public Projectile GetProjectile(Vector3 pos, Quaternion rot) { // 池为空时临时补充实例,避免报错 if (projectilesInPool.Count == 0) { GameObject _projectile = Instantiate(projectilePrefab, transform.position, transform.rotation); Projectile proj = _projectile.GetComponent<Projectile>(); proj.gameObject.SetActive(false); projectilesInPool.Add(proj); } Projectile _projectile = projectilesInPool[0]; projectilesInPool.RemoveAt(0); // 从池中移除实例 _projectile.gameObject.SetActive(true); _projectile.transform.position = pos; _projectile.transform.rotation = rot; _projectile.ResetState(); // 重置投射物状态 return _projectile; } public void ReturnToPool(Projectile _projectile) { _projectile.gameObject.SetActive(false); _projectile.transform.position = transform.position; projectilesInPool.Add(_projectile); } void PoolInitialization() { projectilesInPool = new List<Projectile>(); for (int i = 0; i < poolLength; i++) { GameObject _projectile = Instantiate(projectilePrefab, transform.position, transform.rotation); Projectile proj = _projectile.GetComponent<Projectile>(); proj.gameObject.SetActive(false); // 初始化时禁用 projectilesInPool.Add(proj); } } }
2. 重置投射物状态(Projectile.cs)
添加状态重置方法,确保每次取出时都是初始状态:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Projectile : MonoBehaviour { private Vector3 firingPoint; [SerializeField] private float projectileSpeed; [SerializeField] private float maxProjectileDistance; private bool moves = false; void Start() { firingPoint = transform.position; } void Update() { if (moves) { MovingTheProjectile(); } } public void StartMovement() { moves = true; firingPoint = transform.position; // 记录当前发射位置 } void MovingTheProjectile() { if (Vector3.Distance(firingPoint, transform.position) > maxProjectileDistance) { ProjectilePooling.Instance.ReturnToPool(this); } else { transform.Translate(Vector3.forward * projectileSpeed * Time.deltaTime); } } public void ResetState() { moves = false; firingPoint = Vector3.zero; // 若有刚体组件,可添加rigidbody.velocity = Vector3.zero; } // 对象禁用时自动重置状态 private void OnDisable() { ResetState(); } }
3. 适配攻击逻辑(PlayerAttackPower.cs)
更新调用方法,确保与修复后的对象池兼容:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerAttackPower : MonoBehaviour { [SerializeField] Transform firingPoint; [SerializeField] float firingSpeed; public static PlayerAttackPower Instance; private float lastShootingTime = 0; void Awake() { Instance = this; } public void Shoot() { if (lastShootingTime + firingSpeed <= Time.time) { Projectile _projectile = ProjectilePooling.Instance.GetProjectile(firingPoint.position, firingPoint.rotation); _projectile.StartMovement(); lastShootingTime = Time.time; } } }
4. 清理玩家脚本(PlayerScript.cs)
移除无用的静态变量,简化攻击触发逻辑:
using Mirror; using UnityEngine; namespace QuickStart { public class PlayerScript : NetworkBehaviour { void Update() { if (!isLocalPlayer) { return; } float moveX = Input.GetAxis("Horizontal") * Time.deltaTime * 110.0f; float moveZ = Input.GetAxis("Vertical") * Time.deltaTime * 4f; transform.Rotate(0, moveX, 0); transform.Translate(0, 0, moveZ); InputShootingManager(); } void InputShootingManager() { if (Input.GetButton("Fire1")) { PlayerAttackPower.Instance.Shoot(); } } } }
关键修复总结
- 移除了冗余的
isActiveObj静态变量,避免状态干扰 - 对象池初始化时禁用所有投射物,保证初始状态正确
- 取出投射物时从列表移除,归还时添加回列表,确保对象池逻辑闭环
- 添加状态重置机制,彻底清除投射物的旧状态
- 优化方法和变量命名,提升代码可读性和维护性
内容的提问来源于stack exchange,提问作者Jesse Gober
相关产品推荐
相关产品推荐

