如何修复 Unity 中的痉挛和错误实例化
How to fix spasming and buggy instantiation in Unity
我正在用 C# 在 Unity 中创建一个基本台球游戏,我想做的是如果母球在移动,球杆就会消失,一旦它再次静止,它就会重新出现在球杆所在的位置母球位于。到目前为止,这是我的代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class stickDeplacement : MonoBehaviour
{
public bool bIsOnTheMove = false;
Vector3 lastPos;
public GameObject Stick;
void Start()
{
}
void Update()
{
var stick = Instantiate(Stick, gameObject.transform.position, gameObject.transform.rotation);
if (this.transform.position != lastPos)
{
Destroy(stick);
Debug.Log("Is moving");
}
else
{
Debug.Log("Is not moving");
}
lastPos = this.transform.position;
}
}
但实际情况是,球和棍子从一开始(当我打开并玩游戏时)就会痉挛并出现故障。我在这里遗漏了什么吗?
这是极其低效和危险的!
为什么 每一帧 实例化一根棍子只是为了最终在同一帧中摧毁它?如果球是静止的,您希望每帧都生成一根额外的棍子?
与其一直实例化和销毁它,不如保留 one 并仅(取消)激活它。
在您的情况下,您可以在一行中完成此操作
bIsOnTheMove = transform.position == lastPos;
stick.SetActive(!bIsOnTheMove);
另外,我很怀疑您是否希望棍子具有与滚球相同的旋转!当然这会很尴尬
您肯定不是只是想复制球的方向。我会例如尝试确定 table 边缘到当前球位置的最近点(遍历墙壁碰撞器并使用 Collider.ClosestPoint
)并让棍子面向从该边缘点到球位置的方向(+可能是 X 方向的偏移,所以默认情况下摇杆略微倾斜。
最后,您无论如何都不想在每一帧都指定该旋转,因为您以后很可能希望您的用户能够旋转该摇杆。您只想在球静止时应用此一次。
例如
// The stick is not a prefab anymore but simply always exists in the scene!
[SerializeField] private Transform stick;
[SerializeField] private Vector3 eulerOffset;
[SerializeField] private Collider[] wallColliders;
public bool bIsOnTheMove;
private Vector3 lastPos;
private void Start()
{
lastPos = transform.position;
}
private void Update()
{
// is the ball currently moving?
var isMoving = transform.position == lastPos;
last Post = transform.position;
// Did this state change since the last frame?
if(bIsOnTheMove == isMoving) return;
bIsOnTheMove = isMoving;
// (de)activate the stick accordingly
stick.gameObject.SetActive(!isMoving);
// Do this ONCE when ball becomes stanionary
if(!isMoving)
{
var ballPosition = transform.position;
// among the wall colliders find which one is closest to the ball
Vector3 closestPoint;
var smallestDistance = float.PositiveInifinity;
foreach(var wall in wallColliders)
{
var edgePoint = wall.ClosestPoint(ballPosition);
var distane = (edgePoint - ballPosition).sqrMagnitude;
if(distance < smallestDistance)
{
closestPoint = point;
smallestDistance = distance;
}
}
// then make the stick look towards the ball from that edge
var direction = ballPosition - closestPoint;
var rotation = Quaternion.LookRotation(direction);
// optional add the offset
rotation *= Quaternion.Euler(eulerOffset);
stick.rotation = rotation;
}
}
我正在用 C# 在 Unity 中创建一个基本台球游戏,我想做的是如果母球在移动,球杆就会消失,一旦它再次静止,它就会重新出现在球杆所在的位置母球位于。到目前为止,这是我的代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class stickDeplacement : MonoBehaviour
{
public bool bIsOnTheMove = false;
Vector3 lastPos;
public GameObject Stick;
void Start()
{
}
void Update()
{
var stick = Instantiate(Stick, gameObject.transform.position, gameObject.transform.rotation);
if (this.transform.position != lastPos)
{
Destroy(stick);
Debug.Log("Is moving");
}
else
{
Debug.Log("Is not moving");
}
lastPos = this.transform.position;
}
}
但实际情况是,球和棍子从一开始(当我打开并玩游戏时)就会痉挛并出现故障。我在这里遗漏了什么吗?
这是极其低效和危险的!
为什么 每一帧 实例化一根棍子只是为了最终在同一帧中摧毁它?如果球是静止的,您希望每帧都生成一根额外的棍子?
与其一直实例化和销毁它,不如保留 one 并仅(取消)激活它。
在您的情况下,您可以在一行中完成此操作
bIsOnTheMove = transform.position == lastPos; stick.SetActive(!bIsOnTheMove);
另外,我很怀疑您是否希望棍子具有与滚球相同的旋转!当然这会很尴尬
您肯定不是只是想复制球的方向。我会例如尝试确定 table 边缘到当前球位置的最近点(遍历墙壁碰撞器并使用
Collider.ClosestPoint
)并让棍子面向从该边缘点到球位置的方向(+可能是 X 方向的偏移,所以默认情况下摇杆略微倾斜。最后,您无论如何都不想在每一帧都指定该旋转,因为您以后很可能希望您的用户能够旋转该摇杆。您只想在球静止时应用此一次。
例如
// The stick is not a prefab anymore but simply always exists in the scene!
[SerializeField] private Transform stick;
[SerializeField] private Vector3 eulerOffset;
[SerializeField] private Collider[] wallColliders;
public bool bIsOnTheMove;
private Vector3 lastPos;
private void Start()
{
lastPos = transform.position;
}
private void Update()
{
// is the ball currently moving?
var isMoving = transform.position == lastPos;
last Post = transform.position;
// Did this state change since the last frame?
if(bIsOnTheMove == isMoving) return;
bIsOnTheMove = isMoving;
// (de)activate the stick accordingly
stick.gameObject.SetActive(!isMoving);
// Do this ONCE when ball becomes stanionary
if(!isMoving)
{
var ballPosition = transform.position;
// among the wall colliders find which one is closest to the ball
Vector3 closestPoint;
var smallestDistance = float.PositiveInifinity;
foreach(var wall in wallColliders)
{
var edgePoint = wall.ClosestPoint(ballPosition);
var distane = (edgePoint - ballPosition).sqrMagnitude;
if(distance < smallestDistance)
{
closestPoint = point;
smallestDistance = distance;
}
}
// then make the stick look towards the ball from that edge
var direction = ballPosition - closestPoint;
var rotation = Quaternion.LookRotation(direction);
// optional add the offset
rotation *= Quaternion.Euler(eulerOffset);
stick.rotation = rotation;
}
}