首页 > 解决方案 > 如何将命中点改为十字准线?

问题描述

下面的脚本使用一个函数,而首先检查范围内是否有对象,如果有,则检查。
在按下鼠标键时,射弹正朝着该物体的枢轴点射击。我想让弹丸

  1. 总是能够开火(如果物体在范围内则无所谓)和
  2. 朝十字准线(屏幕中点)射击,而不是朝对象枢轴点射击。

我是编码新手,看不到要删除哪些代码以及要添加哪些代码。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEditor;
    using UnityEngine;
    using UnityEngine.Events;

    public struct ShootHit
    {
    public GameObject gameObject;
    public Vector3 point;
    }

    [System.Serializable]
    public class UnityEventShootHit : UnityEvent<ShootHit> { }

    [DisallowMultipleComponent, AddComponentMenu("(つ♥v♥)つ/Useables/Shoot")]
    public class ShootComponent : MonoBehaviour
    {
    [Header("Input")]
    [Tooltip("Data that determines the input of player actions")]
    [SerializeField] private InputProfile _inputProfile;
    // [SerializeField] private float _range = 100.0f;

    /* [Header("Sight Values")]
     [Tooltip("How far the the sight can reach")]
     public float sightRadius = 1f;
     [Range(0f, 360f)]
     public float fieldOfViewAngle = 100f;*/

    [Header("Charge-up")]
    [SerializeField] private float _chargeupTime = 0.5f;
    private bool _isChargingPrimary = false;
    private bool _isChargingSecondary = false;

    [Header("Aim Assist")]
    [SerializeField] private LayerMask _aimAssistLayerMask;

    public float aimAssistRadius = 30.0f;  // radius
    [Range(0.0f, 360.0f)]
    public float aimAssistMaxAngleToAssist = 45.0f;  // angle

    private ShootHit? _target;

    //publics
    public Transform shootOrigin;

    [Header("Events")]
    public UnityEventShootHit OnPrimaryFire;
    public UnityEvent OnPrimaryFireStart;
    public UnityEvent OnPrimaryFireStop;

    public UnityEventShootHit OnSecondaryFire;
    public UnityEvent OnSecondaryFireStart;
    public UnityEvent OnSecondaryFireStop;

    private void Start()
    {
        if (_inputProfile == null) Debug.LogError(gameObject.name + " does not 
        have a player input");
    }

     private void Update()
     {
         // Remove target if object is too far away
         if (_target.HasValue)
         {
            if (Vector3.Distance(_target.Value.gameObject.transform.position, 
         transform.position) > aimAssistRadius)
            {
                _target = null;
            }
         }

         if (_inputProfile.GetPrimaryFireButtonDown())
         {
            StopCoroutine(ChargeUpBeforeFireSecondary());

            if (!_isChargingPrimary)
            {
                StartCoroutine(ChargeUpBeforeFirePrimary());
            }
         }

         else if (_inputProfile.GetSecondaryFireButtonDown())
         {
            StopCoroutine(ChargeUpBeforeFirePrimary());

            if (!_isChargingSecondary)
            {
                StartCoroutine(ChargeUpBeforeFireSecondary());
            }
        }

         if (_inputProfile.GetPrimaryFireButton() || 
        _inputProfile.GetSecondaryFireButton())
        {
            if (!_target.HasValue) _target = GetObjectClosestToAim();

            if (_inputProfile.GetPrimaryFireButton())
            {
                OnPrimaryFire.Invoke(_target.Value);
            }
            if (_inputProfile.GetSecondaryFireButton())
            {
                OnSecondaryFire.Invoke(_target.Value);
            }

        }
        else
        {
            _target = null;
        }

        if (_inputProfile.GetPrimaryFireButtonUp())
            OnPrimaryFireStop.Invoke();
        if (_inputProfile.GetSecondaryFireButtonUp())
            OnSecondaryFireStop.Invoke();
    }

    /// <summary>
    /// Finds the object within range closest to the players forward-vector 
    using _aimAssistLayerMask.
    /// </summary>
    /// <returns>Returns object closest to aim if any object is found, else 
    returns null.</returns>
    ShootHit? GetObjectClosestToAim()
    {
        // Raycast
        RaycastHit hit;
        if (Physics.Raycast(shootOrigin.position, Camera.main.transform.forward, 
        out hit, aimAssistRadius, _aimAssistLayerMask))
        {
            if (hit.transform?.GetComponent<IShootTarget>() != null)
            {
                Debug.Log(hit.transform.name);

                return new ShootHit { gameObject = hit.transform.gameObject, 
    point = hit.point };
            }
        }

        float _closestDot = -2f;
        GameObject _closestDotObject = null;
        RaycastHit[] _hit = Physics.SphereCastAll(transform.position, 
        aimAssistRadius, transform.forward, 0, _aimAssistLayerMask, 
        QueryTriggerInteraction.Ignore);

        // Get best dot from all objects within range
        for (int i = 0; i < _hit.Length; i++)
        {
            if (_hit[i].transform.gameObject == this.gameObject || 
        _hit[i].transform.GetComponent<IShootTarget>() == null)
                continue;

            Vector3 _dif = _hit[i].transform.position - transform.position;

            float _newDot = Vector3.Dot(transform.forward.normalized, 
      _dif.normalized);
            if (_newDot > _closestDot)
            {
                _closestDot = _newDot;
                _closestDotObject = _hit[i].transform.gameObject;
            }
        }
        if (!_closestDotObject)
            return null;

        // Make sure there are no object in the way of our best-dot-object
        Collider[] colliders = _closestDotObject.GetComponents<Collider>();
        Vector3 point = colliders[0].ClosestPoint(shootOrigin.position);
        float distanceToPoint = Vector3.Distance(shootOrigin.position, point);
        // Get closest collider
        for (int i = 1; i < colliders.Length; i++)
        {
            Vector3 newPoint = colliders[i].ClosestPoint(shootOrigin.position);
            float newDistanceToPoint = Vector3.Distance(shootOrigin.position, 
        newPoint);
            if (distanceToPoint > newDistanceToPoint)
            {
                point = newPoint;
                distanceToPoint = newDistanceToPoint;
            }
        }
        RaycastHit _rayhit;
        if (Physics.Raycast(shootOrigin.position, point - transform.position, 
        out _rayhit, aimAssistRadius, _aimAssistLayerMask))
        {
            if (_rayhit.transform.gameObject != _closestDotObject)
            {
                return null;
            }
        }

        Vector3 _vecToClosest = _closestDotObject.transform.position - 
    transform.position;
        if (Vector3.Angle(transform.forward, _vecToClosest) <= 
    aimAssistMaxAngleToAssist)
         {
            return new ShootHit { gameObject = _closestDotObject, point = point 
 };
        }
        else
        {
            return null;
        }
    }

     IEnumerator ChargeUpBeforeFirePrimary()
    {
        _isChargingPrimary = true;
        yield return new WaitForSeconds(_chargeupTime);
        _isChargingPrimary = false;
        OnPrimaryFireStart.Invoke();
    }

    IEnumerator ChargeUpBeforeFireSecondary()
    {
        _isChargingSecondary = true;
        yield return new WaitForSeconds(_chargeupTime);
        _isChargingSecondary = false;
        OnSecondaryFireStart.Invoke();
    }


    #if UNITY_EDITOR
    private void OnDrawGizmosSelected()
    {
        if (!Application.isPlaying) return;

        Color oldColor = Gizmos.color;

        float halfFeildOfView = aimAssistMaxAngleToAssist * 0.5f;
        float coneDirection = -90f;

        Quaternion leftRayRotation = Quaternion.AngleAxis(-halfFeildOfView + coneDirection, Vector3.up);
        Quaternion rightRayRotation = Quaternion.AngleAxis(halfFeildOfView + coneDirection, Vector3.up);

        Vector3 leftRayDirection = leftRayRotation * transform.right * aimAssistRadius;
        Vector3 rightRayDirection = rightRayRotation * transform.right * aimAssistRadius;

        // Green Arc
        Handles.color = new Color(0f, 1f, 0f, 0.25f);
        Handles.DrawSolidArc(transform.position, Vector3.up, leftRayDirection, aimAssistMaxAngleToAssist, aimAssistRadius);

        Gizmos.color = oldColor;


    }
     #endif

}
`

这是附加到弹丸的代码

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(Rigidbody))]
public class ProjectileScript : MonoBehaviour
{

    public GameObject Explosion;

    public Transform Target;

    Rigidbody _rigidbody;

    public float speed = 1.0f;

    void Start()
    {
        _rigidbody = GetComponent<Rigidbody>();

    }

    void FixedUpdate()
    {
        // _rigidbody.AddForce((Target.position - transform.position).normalized, ForceMode.Impulse);
        Collider targetCollider = Target.GetComponent<Collider>();
        Vector3 targetDirection;
        if (targetCollider)
            targetDirection = targetCollider.ClosestPoint(transform.position) - transform.position;
        else
            targetDirection = Target.position - transform.position;

        _rigidbody.velocity = targetDirection.normalized * speed;
        if (Vector3.Distance(transform.position, Target.position) < 1.0f)
        {
            //make the explosion
            GameObject ThisExplosion = Instantiate(Explosion, gameObject.transform.position, gameObject.transform.rotation) as GameObject;

            //destory the projectile
            Destroy(gameObject);
        }
    }

    public void SetTarget(GameObject target)
    {
        this.Target = target.transform;
    }

    public void SetTarget(ShootHit hit) => SetTarget(hit.gameObject);

}

这个脚本是 Projectile Spawn 的方式和位置。它附在枪口上的空游戏对象上。

public class ProjectileSpawner : MonoBehaviour
{

    public GameObject projectileInsert;

        public GameObject projectileExtract;
        public float projectileSpeed = 1.0f;

        GameObject projectile;

        public void Insert(GameObject target)
        {
            if (projectile) return;

            projectile = Instantiate(projectileInsert, transform.position, Quaternion.identity);
            ProjectileScript projectileScript = projectile.GetComponent<ProjectileScript>();
            projectileScript.SetTarget(target);
            projectileScript.speed = projectileSpeed;

            // Physics.IgnoreCollision(projectile.GetComponent<Collider>(),
            // projectileSpawn.parent.GetComponent<Collider>()); 

        }

        public void Extract(GameObject target)
        {
            if (projectile) return;

            projectile = Instantiate(projectileExtract, target.transform.position, Quaternion.identity);
            ProjectileScript projectileScript = projectile.GetComponent<ProjectileScript>();
            projectileScript.SetTarget(gameObject);
            projectileScript.speed = projectileSpeed;

            // Physics.IgnoreCollision(projectile.GetComponent<Collider>(),
            // projectileSpawn.parent.GetComponent<Collider>()); 

        }


    }

标签: c#unity3d

解决方案


你的问题有点含糊,看起来你没有付出很多努力来理解代码并试图改变它。反正我会尽力的。


总是能够开火(如果物体在范围内则无所谓)`

可能只是设置aimAssistRadius = 0;或完全删除检查

if (Vector3.Distance(_target.Value.gameObject.transform.position, transform.position) > aimAssistRadius)
{ 
    _target = null; 
}

朝十字准线(屏幕中点)射击,而不是朝对象枢轴点射击。

您发布的脚本(可能不是您的)似乎具有做您不想做的事情的全部目的:瞄准辅助。删除它可能会改变很多事情,但最简单的方法是ProjectileScript._rigidbody.velocity在弹丸实例化的那一刻简单地设置。不幸的是,您没有提供发生这种情况的代码。

我没有看到您在哪一刻与UnityEvents 中的一个ShootComponent互动,但可能是在其中一个 ...?ProjectileScript

但总的来说,它可能看起来像

public class ProjectileScript : MonoBehaviour
{
     public float speed = 1.0f;

    private RigidBody _rigidbody;

    private void Awake()
    {
        _rigidbody = GetComponent<RigidBody>();
    }

    public void SetDirection(Vector3 direction)
    {
        _rigidbody.velocity = direction.normalized * speed;
    }
}

无论你在哪里实例化射弹

var projectile = instantiatedObject.GetComponent<ProjectileScript>();
var direction = Camera.main.transform.forward;
projectile.SetDirection(direction);

如您所见,您将不得不

if (Vector3.Distance(transform.position, Target.position) < 1.0f)
{
    //make the explosion
    GameObject ThisExplosion = Instantiate(Explosion, gameObject.transform.position, gameObject.transform.rotation) as GameObject;

    //destory the projectile
    Destroy(gameObject);
}

发生在其他地方,因为代码将不再基于目标......我可能会使用OnCollisionEnter类似的东西

private void OnCollisionEnter(Collision collision)
{ 
    // maybe only collide with a certain tag
    if(collision.gameObject.tag != "Target") return;

    //make the explosion
    GameObject ThisExplosion = Instantiate(Explosion, gameObject.transform.position, gameObject.transform.rotation) as GameObject;

    //destory the projectile
    Destroy(gameObject);
}

推荐阅读