如何将生命值更改为十字准线?

时间:2019-05-28 08:15:07

标签: c# unity3d

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

  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);

}

此脚本是弹丸生成的方式和位置。它连接到位于枪口上的空游戏对象。

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>()); 

        }


    }

2 个答案:

答案 0 :(得分:0)

您的问题有点含糊,看起来您在理解代码和尝试更改代码上付出了很多努力。无论如何,我会尽力而为。


  

始终能够发射(如果物体在射程范围内则无所谓)`

可能只需设置aimAssistRadius = 0;或完全删除支票

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

  

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

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

我看不到您的ShootComponentProjectileScript进行互动的那一刻,但可能是在其中的UnityEvent中...?

但是一般来说,它看起来可能只是

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);
}

答案 1 :(得分:0)

ProjectileSpawner中,添加一个LayerMask字段以过滤掉非归宿弹丸的无效碰撞(在检查器中设置)。您将在检查器中进行设置,以使非归位弹丸与所需层碰撞:

public LayerMask collisionLayers;

Insert中,找到从屏幕中心发出的光线,并将其和LayerMask用作SetTarget的参数:

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

    Ray centerRay = Camera.main.ScreenPointToRay(new Vector3(Screen.width/2, Screen.height/2, 0f));

    projectile = Instantiate(projectileInsert, transform.position, Quaternion.identity);
    ProjectileScript projectileScript = projectile.GetComponent<ProjectileScript>();
    projectileScript.SetTarget(centerRay, collisionLayers);
    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>()); 

}

然后在ProjectileScript中添加一个bool字段以记住弹丸是否驻留在gameObject上或它是否跟随着光线,请添加一个Ray字段以记住这样的光线,以及LayerMask字段以记住要与之碰撞的内容:

public bool isHoming;
public Ray TargetRay
public LayerMask collisionLayers;

然后,在public void SetTarget(GameObject target)中,将bool设置为true

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

并创建一个新的public void SetTarget(Ray shootRay)来记住RayLayerMask并将bool设置为false

public void SetTarget(Ray shootRay, LayerMask collisionLayers)
{
    this.TargetRay = shootRay;
    this.collisionLayers = collisionLayers;
    isHoming = false;
}   

此外,在ProjectileScript中,您将需要更改FixedUpdate方法来检查布尔值是否正确,如果是,则与以前相同。否则,沿射线移动并在射线传播太远时将其摧毁:

public float maxDistanceBeforeDestroy = 100f;

...

void FixedUpdate()
{
    if (isHoming) 
    {    
        // _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);
        }
    }
    else
    {
        _rigidbody.velocity = TargetRay.direction.normalized * speed;

        // Check if it has traveled too far

        if ((transform.position - TargetRay.origin).magnitude > maxDistanceBeforeDestroy ) 
        {
            Destroy(gameObject);
        }
    }
}

然后,添加一个OnCollisionEnter方法,如果弹头正在归位,该方法不会执行任何操作。但是,如果不是,它将检查碰撞是否与LayerMask相匹配,如果匹配,则将爆炸并摧毁弹丸:

void OnCollisionEnter(Collision other)
{
     if (isHoming) 
     {
         return;
     }

     if( && ((1<<other.gameObject.layer) & collisionLayers) != 0)
     {
         //make the explosion
        GameObject ThisExplosion = Instantiate(Explosion, 
                gameObject.transform.position, 
                gameObject.transform.rotation) as GameObject;

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