Here we define the new position of the player by setting a new vector when it goes out of bounds:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float horizontalInput;
public float speed = 10.0f;
public float boundary = 10.0f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (transform.position.x > boundary)
{
transform.position = new Vector3(10.0f, transform.position.y, transform.position.z);
}
if (transform.position.x < -boundary)
{
transform.position = new Vector3(-10.0f, transform.position.y, transform.position.z);
}
horizontalInput = Input.GetAxis("Horizontal");
transform.Translate(Vector3.right * horizontalInput * Time.deltaTime * speed);
}
}
It works, but I don’t want to create new vectors and wasting cycles by allocating memory. Instead, I wanted to update the transform.position with the Set method when I go out of bounds. Something like that:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float horizontalInput;
public float speed = 10.0f;
public float boundary = 10.0f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (transform.position.x > boundary)
{
transform.position.Set(boundary, transform.position.y, transform.position.z);
}
if (transform.position.x < -boundary)
{
transform.position.Set(-boundary, transform.position.y, transform.position.z);
}
horizontalInput = Input.GetAxis("Horizontal");
transform.Translate(Vector3.right * horizontalInput * Time.deltaTime * speed);
}
}
The proble is that the Set method does not seem to work; even if Set was called, the x coordinate it’s not updated and the code does not work anymore.
Why Set is not working in this case? What I’m doing wrong?
This is due to a common misconception on how “structs” vs “classes” work.
Your code is really doing something like this:
// this code
transform.position.Set(boundary, transform.position.y, transform.position.z);
// really means this other code
var position = transform.position;
position.Set(boundary, transform.position.y, transform.position.z); // you modified the local Vector3, but Transform still has the old Vector3
what you really want is this:
var position = transform.position;
position.Set(boundary, transform.position.y, transform.position.z);
transform.position = position; // re-assign your modified Vector3
// and now that you know this, it would be simpler like this
var position = transform.position;
position.x = boundary;
transform.position = position; // re-assign your modified Vector3
So, it’s always necessary to create a new instance of Vector3 (due to new operator or assignmentt) in order to update it? It does not seems very efficient…
Is not so much as that you are creating a new instance of a Vector3 (which you are), but that you are “copying” a heap-allocated Vector3 (located on the Transform instance memory location), to the stack (your method body), then you modify on the stack, and re-assign to the heap.
This is because “position” for Transform is exposed as a C# property. A property is just “syntactic sugar” for a Set() and a Get() methods. So you were always getting a copy, you dont have access to the Vector3 field, that would allow you to directly modify the “x” value
Even if you had direct access to the field, modifying position necesarilly requires notifying some systems. So it wouldnt be cheap either way and then you would be required to call some method that notifies the system.
It is always better to retrieve the position once, modify or access it as many times as necessary (your copy), and then re-assign if required.
You should suppress this urge. It is going to cost you dearly in terms of early learning.
Yes, don’t write needlessly wasteful code, but at this stage of your gaming adventure you don’t really have enough context to choose wisely here, and in general, humans are very bad at reasoning about what is slow or fast or wasteful or efficient in computer code. That’s just the reality. That’s why we have the Profiler to give us runtime insights.
You want to focus on learning: look at examples, try lots of stuff, learn how each part works, and over time you will develop a sense of what isn’t a good idea to do a lot of, what doesn’t matter.