Reputation: 11
I'm an extreme amateur with a very simple goal. Inside an OnGui i have a button. I want this button when pressed to move the gameObject it's attached to to move a distance to the right in a smooth motion. I've been successful in setting the distance i want to move to, but i cannot make the movement smooth to save my life.
private void OnGUI()
{
if (GUI.Button(new Rect(165, 300, 150, 350), "right"))
{
var pos = transform.position;
float rightMovement = pos.x + 0.5f;
Vector3 targetPosition = new Vector3(rightMovement, transform.position.y, transform.position.z);
while (Vector3.Distance(transform.position, targetPosition) > 0.1f)
{
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, targetPosition, step);
}
Debug.Log("Clicked rightMovement");
}
(Speed = 5f) This is what i felt like got me the closest to my goal. Currently it moves the distance, but just in a single frame. I also tried to use an IEnumerator that basically has the same code inside and just call said IEnumarator from inside the OnGui, but to no avail.
Upvotes: 0
Views: 451
Reputation: 90639
The main issue is this loop
while (Vector3.Distance(transform.position, targetPosition) > 0.1f)
{
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, targetPosition, step);
}
This moves your object in one single step because no frame is rendered meanwhile. The while
rather blocks the entire thread until it is done (which I this case is not that long) and then renders the frame when done.
Additionally as also mentioned in the comments OnGUI
is called multiple times per frame so it gets even worse.
As I also commented OnGUI
is kind of legacy and you shouldn't use it anymore except you know exactly how and what you are doing.
Rather use a UI.Button
in a Canvas
.
If I see it right you want to move while the button stays pressed.
Unfortunately there is no built-in Button for handling something like "while button stays pressed" so you'ld have to use the IPointerDownHandler
and IPointerUpHandler
interfaces.
Put this class on the UI.Button
object
public class MoveButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler
{
public enum Alignment
{
Global,
Local
}
// Configure here the movement step per second in all three axis
public Vector3 moveStep;
// Here reference the object that shall be move by this button
public Transform targetObject;
// Configure here wether you want the movement in
// - Global = World-Space
// - Local = Object's Local-Space
public Alignment align;
private Button button;
private void Awake ()
{
button = GetComponent<Button>();
}
//Detect current clicks on the GameObject (the one with the script attached)
public void OnPointerDown(PointerEventData pointerEventData)
{
// Ignore if button is disabled
if(!button.interactible) return;
StartCoroutine (Move());
}
public void OnPointerUp(PointerEventData pointerEventData)
{
StopAllCoroutines();
}
public void OnPointerExit(PointerEventData pointerEventData)
{
StopAllCoroutines();
}
// Actually not really needed but I'm not sure right now
// if it is required for OnPointerExit to work
// E.g. PointerDown doesn't work if PointerUp is not present as well
public void OnPointerEnter(PointerEventData pointerEventData)
{
}
// And finally to the movement
private IEnumerator Move()
{
// Whut? Looks dangerous but is ok as long as you yield somewhere
while(true)
{
// Depending on the alignment move one step in the given direction and speed/second
if(align == Alignment.Global)
{
targetObject.position += moveStep * Time.deltaTime;
}
else
{
targetObject.localPosition += moveStep * Time.deltaTime;
}
// Very important! This tells the routine to "pause"
// render this frame and continue from here
// in the next frame.
// without this Unity freezes so careful ;)
yield return null;
}
}
}
Alternatively you could stick to your code but separate the button from the movement like
private bool isPressed;
private void OnGUI()
{
isPressed = GUI.Button(new Rect(165, 300, 150, 350), "right");
}
private void Update()
{
if(!isPressed) return;
var pos = transform.position;
var targetPosition = pos + Vector3.right * 0.5f;
if (Vector3.Distance(transform.position, targetPosition) > 0.1f)
{
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, targetPosition, step);
}
}
Upvotes: 1