c# - 如何将命中点改为十字准线?
问题描述
下面的脚本使用一个函数,而首先检查范围内是否有对象,如果有,则检查。
在按下鼠标键时,射弹正朝着该物体的枢轴点射击。我想让弹丸
- 总是能够开火(如果物体在范围内则无所谓)和
- 朝十字准线(屏幕中点)射击,而不是朝对象枢轴点射击。
我是编码新手,看不到要删除哪些代码以及要添加哪些代码。
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>());
}
}
解决方案
你的问题有点含糊,看起来你没有付出很多努力来理解代码并试图改变它。反正我会尽力的。
总是能够开火(如果物体在范围内则无所谓)`
可能只是设置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);
}
推荐阅读
- c++ - C ++无法将对齐的字符串存储在字符串变量中并打印它
- html - 在图像底部显示图像标题
- c++ - 计算平均值:蒙版图像与 ROI 的不同结果
- docker - 在 CircleCi 中的不同作业之间共享步骤的结果
- javascript - Javascript切换多个按钮
- python - 为什么 for 循环中的这种无效语法?
- java - 如何从 xml 文件中的 TextView 获取文本到自定义对话框中的 TexView?
- java - 排序火力基地
- x86-64 - 打破 ELF/Linux 上的堆栈/调用帧信息链?
- angular - ASP.NET Core MVC IFormFile 415 不支持的媒体类型