unity3d - 我们如何在不使用 unity 的内置物理库的情况下检查 gameObject 和 linerenderer 是否发生碰撞?
问题描述
我们有一种方法可以检测炮弹是否与线条渲染的火鸡物体发生碰撞。基本上,我们有方法在渲染的线条中获取火鸡的所有线条。然后我们检查炮弹中心到线的距离是否小于炮弹的半径。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class canonTrajectory : MonoBehaviour
{
GameObject[] turkeyList = new GameObject[5];
GameObject turkeys;
public static float rotationAngle;
float createdTime;
float speed = 150f;
float gravity = -200.0f;
public GameObject turkey;
static int NUM_PARTICLES = 26;
Vector3[] m_position = new Vector3[NUM_PARTICLES];
LineRenderer lineRenderer;
void Start()
{
turkeys = GameObject.Find("Turkeys");
for (int i = 0; i<5; i++)
{
turkeyList[i] = turkeys.transform.GetChild(i).gameObject;
}
}
// Update is called once per frame
void FixedUpdate()
{
float directionx = Mathf.Cos(-rotationAngle*2.0f*Mathf.PI/360.0f);
float directiony = Mathf.Sin(-rotationAngle * 2.0f * Mathf.PI / 360.0f);
Debug.Log(-rotationAngle * 2.0f * Mathf.PI / 360.0f);
float directionVectorLength = Mathf.Pow(Mathf.Pow(directionx, 2) + Mathf.Pow(directiony, 2), (0.5f));
transform.Translate(-5 * directionx, 5 * directiony , 0.0f);
if (transform.position.x < -300)
Destroy(gameObject);
if (transform.position.y < -77)
Destroy(gameObject);
CheckForTouchingTurkey();
}
public bool CheckForTouchingTurkey()
{
for (int i = 0; i < turkeyList.Length; i++)
{
Vector2 [] temporaryTurkeyLines = turkeyList[i].gameObject.GetComponent<MoveTurkey>().GetSlopeAndIntercept();
for (int j = 0; j < temporaryTurkeyLines.Length;j++)
{
float distance = Mathf.Abs(transform.position.x * temporaryTurkeyLines[i].x -transform.position.y + temporaryTurkeyLines[i].y) / Mathf.Sqrt(1 + Mathf.Pow(temporaryTurkeyLines[i].x, 2.0f));
Debug.Log("distance between ball and turkey is:" + distance);
if (distance < 2.5f)
{
turkeyList[i].gameObject.GetComponent<MoveTurkey>().UpdateMPosition(-20f);
Destroy(gameObject);
}
}
}
return false;
}
}
土耳其运动脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveTurkey : MonoBehaviour
{
LineRenderer lineRenderer;
static int NUM_PARTICLES = 26;
float fTimeStep;
Vector3[] m_position = new Vector3[NUM_PARTICLES];
Vector3[] m_acceleration = new Vector3[NUM_PARTICLES];
Vector3[] m_oldPosition = new Vector3[NUM_PARTICLES];
Vector2[] slopeAndIntercept = new Vector2[NUM_PARTICLES - 1];
public Transform fireball;
float gravity = -9.8f;
// Start is called before the first frame update
public void UpdateMPosition(float x)
{
for (int i = 0; i < m_position.Length; i++)
m_position[i].x +=x;
}
public Vector2[] GetSlopeAndIntercept()
{
return slopeAndIntercept;
}
void Start()
{
fTimeStep = 0.5f;
lineRenderer = gameObject.GetComponent<LineRenderer>();
lineRenderer.GetPositions(m_position);
for (int i = 0; i < m_acceleration.Length; i++)
{
m_acceleration[i] = new Vector3(0.0f, gravity, 0.0f);
}
}
// Verlet integration step void ParticleSystem::
void Verlet()
{
for (int i = 0; i < NUM_PARTICLES; i++)
{
m_position[i] = 2 * m_position[i] - m_oldPosition[i] + m_acceleration[i] * fTimeStep * fTimeStep;
m_oldPosition[i] = m_position[i];
}
}
public void FindLinesOfTurkey()
{
for (int i = 0; i < slopeAndIntercept.Length; i++)
{
float slope = (m_position[i + 1].y - m_position[i].y) / (m_position[i + 1].x - m_position[i].x);
float intercept = m_position[i].y - slope * m_position[i].x;
slopeAndIntercept[i].x = slope;
slopeAndIntercept[i].y = intercept;
}
}
// Update is called once per frame
void Update()
{
//Codes for when the Turkey do the random jump
int rn_generator = Random.Range(0, 2000);
if (rn_generator < 5 && m_position[17].y<=-255f)
{
for (int i = 0; i < m_acceleration.Length; i++)
m_acceleration[i].y = 6.0f; //m_acceleration[i].y;
}
if(m_position[13].y> 90.0f && m_acceleration[13].y>0.0f)
for (int i = 0; i < m_acceleration.Length; i++)
m_acceleration[i].y = -9.8f; //m_acceleration[i].y;
//call verlet
Verlet();
FindLinesOfTurkey();
//check proper orientation of the Turkey( turned left or right)
if (m_position[4].x < m_position[13].x && m_acceleration[25].x >= 0)
{
Vector3 sumOfPoints = new Vector3();
Vector3 sumOfPointsOld = new Vector3();
int numberOfPointsAdded = 0;
Vector3 centerOfTurkey = new Vector3();
Vector3 centerOfTurkeyOld = new Vector3();
for (int i = 8; i < m_position.Length; i++)
{
sumOfPoints.x += m_position[i].x;
sumOfPointsOld.x += m_oldPosition[i].x;
numberOfPointsAdded++;
}
centerOfTurkey.x = sumOfPoints.x / numberOfPointsAdded;
centerOfTurkeyOld.x = sumOfPointsOld.x / numberOfPointsAdded;
for (int i = 0; i < m_position.Length; i++)
{
m_position[i].x = (centerOfTurkey.x + centerOfTurkey.x - m_position[i].x);
m_oldPosition[i].x = (centerOfTurkeyOld.x + centerOfTurkeyOld.x - m_oldPosition[i].x);
}
}
else if (m_position[4].x > m_position[13].x && m_acceleration[25].x < 0)
{
Vector3 sumOfPoints = new Vector3();
Vector3 sumOfPointsOld = new Vector3();
int numberOfPointsAdded = 0;
Vector3 centerOfTurkey = new Vector3();
Vector3 centerOfTurkeyOld = new Vector3();
for (int i = 8; i < m_position.Length; i++)
{
sumOfPoints.x += m_position[i].x;
sumOfPointsOld.x += m_oldPosition[i].x;
numberOfPointsAdded++;
}
centerOfTurkey.x = sumOfPoints.x / numberOfPointsAdded;
centerOfTurkeyOld.x = sumOfPointsOld.x / numberOfPointsAdded;
for (int i = 0; i < m_position.Length; i++)
{
m_position[i].x = (centerOfTurkey.x + centerOfTurkey.x - m_position[i].x);
m_oldPosition[i].x = (centerOfTurkeyOld.x + centerOfTurkeyOld.x - m_oldPosition[i].x);
}
}
else
Debug.Log("Nothing");
//if the turkey is on the ground , remove gravity
if (m_position[17].y <= -255 && m_position[22].y <= -255)
{
float rdGenerator = Random.Range(0.0f, 1.0f);
if (rdGenerator > 0.5f)
{
for (int i = 0; i < m_acceleration.Length; i++)
{
if (m_acceleration[25].x == 0)
m_acceleration[i].x = 3.0f;
m_acceleration[i].y = 0.0f;
}
}
else
{
for (int i = 0; i < m_acceleration.Length; i++)
{
if (m_acceleration[25].x == 0)
m_acceleration[i].x = -3.0f;
m_acceleration[i].y = 0.0f;
}
}
}
// change direction of turkey when they hit the wall or the mountain
if (m_position[13].x >= 280)
{
for (int i = 0; i < m_acceleration.Length; i++)
m_acceleration[i].x = -2.0f;
}
if (m_position[4].x <= -90)
{
for (int i = 0; i < m_acceleration.Length; i++)
m_acceleration[i].x = 2.0f;
}
//draw the turkey
lineRenderer.SetPositions(m_position);
}
}
但是代码不起作用。炮弹穿过火鸡,就好像它们不在那里一样。
解决方案
您可以检查与每只火鸡中心的距离,将火鸡 + 炮弹的半径考虑在内。
Vector2 ballPos = cannonball.transform.position;
float turkeyRadius = 0.5f; // we'll assume it has a circle as a hitbox/collider
float cannonBallRadius = 0.1f; // same for the cannonball
// We want the added radius squared, because we wanna compare with sqrMagnitude later.
float minDifToCollide = Mathf.Pow(cannonBallRadius + turkeyRadius, 2);
foreach (var turkey in allTurkeys) {
Vector2 turkeyPos = turkey.GetCenter();
// .sqrMagnitude is more performant than .magnitude, so we use that.
float dif = (turkeyPos - ballPos).sqrMagnitude;
// Check for collision.
if (dif <= minDifToCollide) { CollideWith(turkey); }
}
您可以将这段代码添加到您的火鸡中,以便可视化它们的半径:
public float Radius;
void OnDrawGizmos() {
Gizmos.color = Color.teal;
Gizmos.DrawWireSphere(transform.position, Radius);
}
推荐阅读
- php - example.com/wp-login.php 将我重定向到 example.com/example.com/wp-admin
- python - 将输入读入嵌套列表
- python - 基于另一个类python / django的启动增加一个类的变量
- sql - 使用 OVER 子句和 PARTITION BY 子句与计数器计算运行总计
- javascript - Office 任务窗格 window.open() -> 文档关闭时浏览器弹出窗口关闭
- javascript - Echarts.js:如何以编程方式激活画笔选择
- javascript - 循环遍历对象中的嵌套数组
- c# - MergeSort() 实现返回初始未排序数组
- html - 如何防止 2 列表格中的表格文本将其下方的单元格推到另一侧?
- angular6 - 如何检查innerformgroup状态即时角反应形式