I'm creating a basic pool game in Unity with C#, what im trying to do is that if the cue ball is moving, the stick will disappear, and once it becomes stationary again, it will reappear to where the cue ball is located. This is my code so far:
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;
}
}
But what happens is that the ball, along with the stick, will just spasm and be buggy right from the start (when I open and play the game). Am I missing something here?
CodePudding user response:
This is extremely inefficient and dangerous!
Why instantiate a stick every frame just to eventually already destroy it in that very same frame? And if the ball is stationary you want an additional stick to be spawned every frame?
Instead of all the time instantiating and destroying it at all you should rather keep one stick and only (de)activate it.
In your case you could do this in a single line
bIsOnTheMove = transform.position == lastPos; stick.SetActive(!bIsOnTheMove);
Also I doubt a lot you would like the stick to have the same rotation as a rolling ball! Of course this will behave awkward
Most certainly you do not simply want to clone the ball's orientation. I would e.g. try to determine the closest point of the table edge to the current ball's position (iterate through the wall colliders and use
Collider.ClosestPoint
) and let the stick face the direction from that edge point towars the ball position ( maybe an offset in X so the stick is slightly inclined by default).And finally you anyway do not want to assign that rotation every frame, since you most probably later want your users to be able to rotate that stick. You only want to apply this once when the ball becomes stationary.
Something like e.g.
// 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;
}
}