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

Unity中Transform无法实时更新射击位置问题求助

问题解决思路与代码修改

1. 射击位置不实时更新的原因及修复

你当前的代码直接在ScriptableObject(SO)中存储projectileSpawnPoint的Transform引用,若这个引用关联的是预制体而非场景中实例化的玩家对象,就会导致取到固定初始位置而非玩家实时位置。正确的做法是每次激活技能时,从传入的玩家parent对象中动态获取发射点:

  • 移除SO中的public Transform projectileSpawnPoint,改为通过名称/标签从玩家身上查找发射点
  • 每次调用Activate时,获取玩家身上最新的发射点位置与旋转

2. 子弹碰撞销毁的问题修复

你在Activate方法内部定义的OnCollisionEnter不会生效——这个方法是MonoBehaviour的回调,只有挂载在GameObject上的脚本才能触发。需要给子弹预制体单独添加处理碰撞的脚本:

修改后的Shoot脚本

using UnityEngine.InputSystem;
using UnityEngine;

namespace EO.ARPGInput
{
    [CreateAssetMenu]
    public class Shoot : Ability
    {
        public GameObject projectilePrefab;
        public float bulletSpeed = 10f;
        public float bulletLife = 3f;
        public string spawnPointName = "ProjectileSpawnPoint"; // 玩家身上发射点的名称

        public override void Activate(GameObject parent)
        {
            // 从玩家身上获取实时的发射点Transform
            Transform spawnPoint = parent.transform.Find(spawnPointName);
            if (spawnPoint == null)
            {
                Debug.LogError($"玩家{parent.name}上未找到名为{spawnPointName}的发射点!");
                return;
            }

            // 实例化子弹,使用发射点当前的位置和旋转
            GameObject projectile = Instantiate(projectilePrefab, spawnPoint.position, spawnPoint.rotation);
            
            // 设置子弹飞行速度
            Rigidbody rb = projectile.GetComponent<Rigidbody>();
            if (rb != null)
            {
                rb.velocity = spawnPoint.forward * bulletSpeed;
            }
            else
            {
                Debug.LogError("子弹预制体缺少Rigidbody组件!");
            }

            // 初始化子弹的生命周期
            projectile.GetComponent<Projectile>().Initialize(bulletLife);
        }
    }
}

子弹碰撞处理脚本(Projectile.cs)

将此脚本挂载到子弹预制体上:

using UnityEngine;

public class Projectile : MonoBehaviour
{
    private float _lifeTime;

    public void Initialize(float lifeTime)
    {
        _lifeTime = lifeTime;
        // 设置自动销毁时间
        Destroy(gameObject, _lifeTime);
    }

    private void OnCollisionEnter(Collision collision)
    {
        // 碰撞到任何物体时立即销毁子弹
        Destroy(gameObject);
        
        // 若需要处理伤害逻辑,可在此添加,例如:
        // Health targetHealth = collision.gameObject.GetComponent<Health>();
        // if (targetHealth != null) targetHealth.TakeDamage(10);
    }
}

3. 关于Update函数的疑问

ScriptableObject本身没有Update方法,你的场景也不需要用Update:

  • 射击逻辑只在技能激活时执行一次,不需要实时更新
  • 子弹的运动由Rigidbody物理驱动,无需Update干预
  • 碰撞与自动销毁逻辑已在子弹的专属脚本中处理

额外注意事项

  • 确保玩家对象身上存在名为ProjectileSpawnPoint的Transform(可根据实际修改名称)
  • 子弹预制体必须添加Rigidbody和碰撞体组件(如Sphere Collider),并开启碰撞检测
  • 若需避免子弹与玩家自身碰撞,可在碰撞体设置中忽略玩家所在的图层

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 07:36:18