This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 16 days ago.
So making an asteroid game, trying to spawn in 4 asteroids, one in each centre section of each side. Code is below for the spawnerScript & the Initialize method.
Got a couple of errors/Warnings:
NullReferenceException: Object reference not set to an instance of an
object (UnityEditor.PropertyHandler.isArrayReordable
Should not be capturing when there is a hotcontrol
If someone could point out WHY it's giving that error would be appreciated
[SerializeField] GameObject prefabAsteroid;
List<GameObject> asteroids = new List<GameObject>();
List<Vector3> screenSides = new List<Vector3>();
// Start is called before the first frame update
void Start()
{
//get screen numbers
float screenHeight = ScreenUtils.ScreenTop - ScreenUtils.ScreenBottom;
float screenWidth = ScreenUtils.ScreenRight - ScreenUtils.ScreenLeft;
//collect all screen sides
screenSides.Add(new Vector2(ScreenUtils.ScreenLeft,screenHeight/2));
screenSides.Add(new Vector2(ScreenUtils.ScreenTop, screenWidth / 2));
screenSides.Add(new Vector2(ScreenUtils.ScreenRight, screenHeight / 2));
screenSides.Add(new Vector2(ScreenUtils.ScreenBottom, screenWidth / 2));
//loop through each direction(Up,Left,Down,Right) and
//Instantiate asteroid on center of each side.
int i = 0;
foreach (Direction dir in System.Enum.GetValues(typeof(Direction)))
{
GameObject pa = Instantiate<GameObject>(prefabAsteroid);
//add to list
asteroids.Add(pa);
pa.GetComponent<Asteroid>().Initialize(dir, screenSides[i]);
i++;
}
public void Initialize(Direction direction, Vector2 location)
{
transform.position = location;
float angle = Random.Range(0 * Mathf.Deg2Rad, 30 * Mathf.Deg2Rad);
Vector2 forceMagnitude = new Vector2(Random.Range(minImpulse, maxImpulse), Random.Range(minImpulse, maxImpulse));
if(direction == Direction.Right)
{
angle +=-15*Mathf.Deg2Rad;
}
else if (direction == Direction.Left)
{
angle +=165 * Mathf.Deg2Rad;
}
else if (direction == Direction.Up)
{
angle += 75 * Mathf.Deg2Rad;
}
else if (direction == Direction.Down)
{
angle += 255 * Mathf.Deg2Rad;
}
Vector2 moveDirection = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
rb.AddForce(forceMagnitude * moveDirection, ForceMode2D.Impulse);
}
Tried storing instantiated object into list, tried grabbing component from that but still same error
Fixed it.
Error was the rigidbody component 'rb' wasn't within the Initialise (was in Start() method but that hasn't run at this point) so was considered null. Just noticed Ann.L saying same thing
Related
This question already has answers here:
How to stop movement, when mouse is off screen
(3 answers)
Closed 4 years ago.
I have a little question.I have an object that follows the mouse. The problem is that I want when the mouse goes out of the Camera, the object no longer follows.
private Vector3 _target;
public Camera Camera;
public bool FollowMouse;
public bool ShipAccelerates;
public float ShipSpeed = 2.0f;
public float offset = 0.0f;
public void OnEnable()
{
if (Camera == null)
throw new InvalidOperationException("Camera not set");
}
public void Update()
{
if (FollowMouse || Input.GetMouseButton(0))
{
_target = Camera.ScreenToWorldPoint(Input.mousePosition);
_target.z = 0;
}
Vector3 difference = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
difference.Normalize();
float rotation_z = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, rotation_z + offset);
var delta = ShipSpeed * Time.deltaTime;
if (ShipAccelerates)
delta *= Vector3.Distance(transform.position, _target);
transform.position = Vector3.MoveTowards(transform.position, _target, delta);
if (Bounds)
{
transform.position = new Vector3(Mathf.Clamp(transform.position.x, Min_X, Max_X),
Mathf.Clamp(transform.position.y, Min_y, Max_Y));
}
}
Simply check the mouses position before doing your MoveTowards:
if(Input.mousePosition.x < YourValueHere || Input.mousePosition.x > YourMinValue || Input.mousePosition.y < YourYValue || Input.mousePosition.y > YMinValue)
{
transform.position = Vector3.MoveTowards(transform.position, _target, delta);
}
If you want it to be resolution independent, then I would use a combination of Screen.Height and Screen.Width for the positive values. 0 will always be your minimum value.
I have a scene that my camera doesn't follow my player. When player reaches the end of camera I want player to can't go further (out of camera view). How can I do this?
My codes for movement
public class PlayerBlueController : MonoBehaviour {
public float speed;
private float x;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void FixedUpdate () {
x = Input.GetAxis ("Horizontal") / 100 * speed;
transform.Translate (x,0,0);
}
}
As you can see from this. It gets out of camera's view.
I noticed you used a Collider2D. You should be using Rigidbody2D.MovePosition instead of transform.Translate or you'll likely run into issues when transform.Translate is used.
1.Take the final move position and convert it to new position in ViewPortPoint with Camera.main.WorldToViewportPoint
2.Apply a limit with Mathf.Clamp to the result in #1.
3.Convert the ViewPortPoint back to world point with Camera.main.ViewportToWorldPoint.
4.Finally, move it with Rigidbody2D.MovePosition.
The code below is modified from this answer to include restriction to screen boundary.
Move without Rigidbody:
Use only if collision and physics are NOT required:
public float speed = 100;
public Transform obj;
public void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
//Move only if we actually pressed something
if ((h > 0 || v > 0) || (h < 0 || v < 0))
{
Vector3 tempVect = new Vector3(h, v, 0);
tempVect = tempVect.normalized * speed * Time.deltaTime;
Vector3 newPos = obj.transform.position + tempVect;
checkBoundary(newPos);
}
}
void checkBoundary(Vector3 newPos)
{
//Convert to camera view point
Vector3 camViewPoint = Camera.main.WorldToViewportPoint(newPos);
//Apply limit
camViewPoint.x = Mathf.Clamp(camViewPoint.x, 0.04f, 0.96f);
camViewPoint.y = Mathf.Clamp(camViewPoint.y, 0.07f, 0.93f);
//Convert to world point then apply result to the target object
obj.position = Camera.main.ViewportToWorldPoint(camViewPoint);
}
Move Object with Rigidbody2D:
Use if collision and physics are required:
public float speed = 100;
public Rigidbody2D rb;
public void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
//Move only if we actually pressed something
if ((h > 0 || v > 0) || (h < 0 || v < 0))
{
Vector3 tempVect = new Vector3(h, v, 0);
tempVect = tempVect.normalized * speed * Time.deltaTime;
//rb.MovePosition(rb.transform.position + tempVect);
Vector3 newPos = rb.transform.position + tempVect;
checkBoundary(newPos);
}
}
void checkBoundary(Vector3 newPos)
{
//Convert to camera view point
Vector3 camViewPoint = Camera.main.WorldToViewportPoint(newPos);
//Apply limit
camViewPoint.x = Mathf.Clamp(camViewPoint.x, 0.04f, 0.96f);
camViewPoint.y = Mathf.Clamp(camViewPoint.y, 0.07f, 0.93f);
//Convert to world point then apply result to the target object
Vector3 finalPos = Camera.main.ViewportToWorldPoint(camViewPoint);
rb.MovePosition(finalPos);
}
image not respond .
but you can check player location
x = Input.GetAxis ("Horizontal") / 100 * speed;
if(gameobject.transform.x > someValue)
x=0
gameobject will be OBJECT in scene that u attach class to it.
another way is place 2 empty gameobject with collider as invisibleWall and get collider to player
Possible solution is:
1.Get the coordinates of your screen cornes (top left, top right, bottom left, bottom right). You can get this coordinates using Screen.height and Screen.width.
2.Convert this coordinates using the camera you need with Camera.ScreenToWorldPoint.
3.Get your player coordinates and check that they are inside the rect which is formed by 4 coordinates of the screen corners.
You need to limit your transform's position based on the edges of the camera. Here is an answer describing the different coordinate systems in unity
You're probably looking to do something like this:
float xMin = Camera.main.ViewportToWorldPoint(Vector3.zero).x;
float xMax = Camera.main.ViewportToWorldPoint(Vector3.one).x;
Vector3 currentPos = transform.position;
float dx = Input.GetAxis ("Horizontal") / 100 * speed;
Vector3 desiredPos = new Vector3(currentPos.x + dx, currentPos.y, currentPos.z);
Vector3 realPos = desiredPos;
if(desiredPos.x > xMax)
realPos.x = xMax;
else if(desiredPos.x < xMin)
realPos.x = xMin;
transform.position = realPos;
Read up here for more info on ViewportToWorldPoint(), it's extremely useful to become comfortable with the different coordinate spaces and how you can convert between them.
In the top
public GameObject[] waypoints;
public Transform target;
public float moveSpeed = 1f;
public float rotationSpeed = 1f;
Transform myTransform;
public float walkSpeed = 10f;
public ThirdPersonCharacter[] thirdPersonCharacter;
Vector3 boundLower;
Vector3 boundUpper;
public Terrain terrain;
Awake and Start:
void Awake()
{
myTransform = transform;
}
void Start()
{
GameObject tpc1 = GameObject.Find("ThirdPersonController");
thirdPersonCharacter[0] = tpc1.GetComponent<ThirdPersonCharacter>();
GameObject tpc2 = GameObject.Find("ThirdPersonController (1)");
thirdPersonCharacter[1] = tpc2.GetComponent<ThirdPersonCharacter>();
waypoints = GameObject.FindGameObjectsWithTag("ClonedObject");
boundLower = terrain.transform.position - terrain.terrainData.size / 2;
boundUpper = terrain.transform.position + terrain.terrainData.size / 2;
}
The Update:
void Update()
{
thirdPersonCharacter[0].m_MoveSpeedMultiplier = walkSpeed;
thirdPersonCharacter[1].m_MoveSpeedMultiplier = walkSpeed;
WayPoints();
CheckBounds();
}
The WayPoints:
int index = 0;
private void WayPoints()
{
if (index == waypoints.Length)
index = 0;
target = waypoints[index].transform;
float distance = Vector3.Distance(myTransform.position, target.transform.position);
myTransform.rotation = Quaternion.Slerp(myTransform.rotation,
Quaternion.LookRotation(target.position - myTransform.position),
rotationSpeed * Time.deltaTime);
myTransform.position += myTransform.forward * moveSpeed * Time.deltaTime;
if (distance < 2f)
index++;
}
And the CheckBounds:
private Vector3 direction = Vector3.forward;
void CheckBounds()
{
foreach (var child in thirdPersonCharacter)
{
var pos = child.transform.position;
pos.x = Mathf.Clamp(pos.x, boundLower.x, boundUpper.x);
pos.z = Mathf.Clamp(pos.z, boundLower.z, boundUpper.z);
if (pos.x == boundLower.x || pos.x == boundUpper.x) direction.x = -direction.x;
if (pos.z == boundLower.z || pos.z == boundUpper.z) direction.z = -direction.z;
child.transform.position = pos;
}
}
Once i added the CheckBounds function and call it from the Update function the characters are walking on place. Not moving. Without the checkBounds they are walking fine between the waypoints. What i want to do is that if the character walked to the terrain edge(bound) just make him turn/rotate back or stop at place.
I must say that the characters(ThirdPersonController) are moving out of the Terrain bounds and falling only if i change the walking speed to 30 for example or more. But in any case i would like to know how to use the CheckBounds for other situations for example if a player is just walking to the Terrain bounds.
There are plenty of ways how to make a Boundary for a game. One example for all is in 1st and 2nd tutorial on Unity web:
https://unity3d.com/learn/tutorials/projects/roll-ball-tutorial/setting-play-area?playlist=17141
https://unity3d.com/learn/tutorials/projects/space-shooter-tutorial/boundary?playlist=17147
You can do it 3 ways:
Create "Boundary" object around the map, create Trigger and once somebody hit the trigger, push him back/stop him/don't allow him pass
Create "Boundary" object which fill whole map. Create Trigger on the OnExit method and once some object will try to leave, stop him/push back/don't allow him to pass
Stick to the programming and some "map" concept where You know the location of Boundaries. In such case You have to check the position and whenever the objects leaves behind the boundary, You have to stop him - this has to happen every update frame, not just on Triggers
Based on the size of the map and complexity of the game, I would pick one of the topper answers. Once the game get complicated You have to create own engine in an engine to handle map control & other things. But first: Step by step.
This code should work (once somebody cross the border, set to the border location + minimal step into center of map):
var pos = child.transform.position;
float step = 1; //adjust to fit scale/size of step
if (pos.x <= boundLower.x) pos.x = boundLower.x + step;
if (pos.x >= boundUpper.x) pos.x = boundUpper.x - step;
if (pos.z <= boundLower.z) pos.z = boundLower.z + step;
if (pos.z >= boundUpper.z) pos.z = boundUpper.z - step;
child.transform.position = pos;
I am using the tilt function on a phone to control an object to roll left and right. I do not want it roll anything beyond the screen width.
As in the simple illustration below, the dotted lines represent the width of the screen. The 'O' is the object and the Max signs indicate the maximum point the object is allowed to roll to.
Max--------O--------Max
But currently using my code, the object still rolls out of the screen. Also tried testing both height n width and ended up the same result where the object rolls out of the screen. Please advice what I am doing wrong. Thank you.
public float speed = 10.0F;
void Update()
{
Vector3 dir = Vector3.zero;
dir.x = Input.acceleration.x;
if (dir.sqrMagnitude > 1)
dir.Normalize();
dir *= Time.deltaTime;
if (!(Mathf.Round(dir.x) > Mathf.Round(Screen.width/2)) || !(Mathf.Round(dir.x) < -Mathf.Round(Screen.width/2)))
{
transform.Translate(dir * speed);
}
}
**Updated
public float speed = 10.0F;
void Update()
{
Vector3 dir = Vector3.zero;
dir.x = Input.acceleration.x;
if (dir.sqrMagnitude > 1)
dir.Normalize();
dir *= Time.deltaTime;
//transform.Translate(dir * speed);
if (transform.position.x < 0)
{
transform.position = new Vector3(0, this.transform.position.y, this.transform.position.z);
}
else if (transform.position.x > Screen.width)
{
transform.position = new Vector3(Screen.width, this.transform.position.y, this.transform.position.z);
}
else
{
transform.Translate(dir * speed);
}
}
I think thereare several ways you can go about checking the transfomrs position.
first off if you were using a 2d camera you could use a method like
leftBounds = Camera.x - (Camera.pixelWidth/2);
however because ortho camera angles are not set at any particulare size at x distace from camera they are hard to calculate.
i have seen some instances were coliders on the camera just outside the render rand were placed as camera children
adding a colision mask to only affect the appropriate game object would be best.
I'm wanting my arrow to point the way I'm targeting in my game.
At the moment, my prefab instantiates in the center of the screen point to the left. When I move my arrow, the point still keeps to the left. How can I get it so that the arrow at least points to the center of my screen, or ideally, has a way of moving, depending on the direction the player is aiming.
For example, if my player is aiming to the top left of the screen, the arrow point would face that way and fire off in that direction.
Here is the code i have so far:
public Object _projectilePrefab;
private bool _pressed = false;
public GameObject _flystickPosition;
private GameObject _currentProjectile;
private Vector3 _firePoint;
private float _startTime;
public float sensitivityX = 15F;
public float sensitivityY = 15F;
int x = 0;
int y = 0;
// Use this for initialization
void Start()
{
_currentProjectile = (GameObject)Instantiate(_projectilePrefab, _flystickPosition.transform.position, _flystickPosition.transform.rotation);
_firePoint = Camera.mainCamera.transform.position - new Vector3(1, 1, 0);
_startTime = (Time.time * 10.0f);
//_serialData = GetComponent<ReadSerial>();
//_udpData = GetComponent<HV_ReadUDPData>();
}
// Update is called once per frame
void Update()
{
_firePoint = Camera.mainCamera.transform.position - new Vector3(1, 1, 0);
float _moveBananaY = transform.localEulerAngles.y + Input.GetAxisRaw("LeftRight") * sensitivityX;
float _moveBananaX = transform.localEulerAngles.x + Input.GetAxisRaw("UpDown") * sensitivityY;
transform.localEulerAngles = new Vector3(_moveBananaX, _moveBananaY, 0);
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
y--;
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
y++;
}
if (Input.GetKeyDown(KeyCode.UpArrow))
{
x--;
}
if (Input.GetKeyDown(KeyCode.DownArrow))
{
x++;
}
float xPercent = 0;
float yPercent = 0;
xPercent = x / 25.0f;
yPercent = y / 25.0f;
_flystickPosition.transform.parent.localEulerAngles = new Vector3(xPercent * 90, yPercent * 90, 0.0f);
float smooth = Time.time - _startTime;
_currentProjectile.transform.position = Vector3.Lerp(lerpFrom, _flystickPosition.transform.position, smooth);
if (Input.GetKeyDown(KeyCode.Space))
{
_currentProjectile.GetComponent<Rigidbody>().velocity = _flystickPosition.transform.parent.forward.normalized * 20;
_currentProjectile = null;
_currentProjectile = (GameObject)Instantiate(_projectilePrefab, _firePoint, transform.rotation);
lerpFrom = _currentProjectile.transform.position;
_startTime = Time.time;
}
}
All of this code is found within my FireProjectile class. It is attached to my camera.
Well if I understand you correctly, your game is 2D. Its not important though. I would offer two solutions for your issue:
You can get your pointing direction by using simple vector math. Vector3(to - from). So your arrow pointing direction is : Target.transform.position - Player.transform.position. Now when it is pointing the right direction you can move it like:
Arrow.transform.Translate(Vector3.forward * Time.deltaTime);
Also if your arrow must point to target, but stay in different position than player, just raycast from Player to Target, get raycast point and theres your arrow "to" Vector3.
If arrow always mimic user rotation, you can simply apply rotation to arrow Arrow.transform.rotation = Player.transform.rotation. If rotations don't match (i.e. your object is rotated), just add empty gameobject to mimic rotations and put arrow as child of it. now you can rotate it as you will.