Unity GameObject won't MoveTowards prefab - unity3d

I have a GameObject with a RobotMovment script on it that looks like this:
public class RobotMovement : MonoBehaviour {
private Transform target;
private float speed = 2f;
void Start() {
target = GameObject.FindGameObjectWithTag("Ball").transform;
}
void Update() {
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, target.position, step);
}
}
I then have another script placed on a empty game object called Ball that looks like this:
public class Ball : MonoBehaviour {
public GameObject ballPrefab;
void Start() {
var randomPosition = new Vector3(Random.Range(GetComponent<Collider>().bounds.min.x, GetComponent<Collider>().bounds.max.x), 0.25f, Random.Range(GetComponent<Collider>().bounds.min.z, GetComponent<Collider>().bounds.max.z));
Instantiate(ballPrefab, randomPosition, Quaternion.identity);
}
}
What I want to achieve is to have the RobotMovement gameobject move towards the ball prefab that gets spawned on the start of the game. Now I get a: nullreferenceexception object reference not set error on start of the game. It might be that the the ball prefabs position can't be read by the RobotMovement script at start?

The Awake() function executes before Start(). It's a good idea to use Awake() to find and assign references such as target, then use Start() for whatever initialisation logic you need once you're confident all your references are in place.
That said, your null reference could be in a number of places, but most likely:
No gameobject called "Ball" is found when RobotMovement calls Start().
Ball gets destroyed or the reference is lost at some point, and RobotMovement.Update() throws.
No collider component on Ball, so Ball.Start() throws.
One thing you didn't ask for, but is important to know, is that GetComponent() is an expensive method to invoke, so you'd be better off calling it just once:
Collider collider = GetComponent<Collider>()
var randomPosition = new Vector3(Random.Range(collider.bounds.min.x, collider.bounds.max.x), 0.25f, Random.Range(collider.bounds.min.z, collider.bounds.max.z));

Related

Why more balls are instantiating?

I'm making a game in unity where the user drags to shoot a ball at some objects at a distance. So far I have this DragAndShoot script:
//using System.Collections;
//using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(Collider))]
public class DragAndShoot : MonoBehaviour
{
public Transform prefab;
private Vector3 mousePressDownPos;
private Vector3 mouseReleasePos;
private Rigidbody rb;
private bool isShoot;
void Start()
{
rb = GetComponent<Rigidbody>();
}
private void OnMouseDown()
{
mousePressDownPos = Input.mousePosition;
}
private void OnMouseUp()
{
mouseReleasePos = Input.mousePosition;
Shoot(mouseReleasePos-mousePressDownPos);
}
private float forceMultiplier = 3;
void Shoot(Vector3 Force)
{
if(isShoot)
return;
rb.AddForce(new Vector3(Force.y,Force.x,Force.z) * forceMultiplier);
isShoot = true;
createBall();
}
void createBall(){
Instantiate(prefab, GameObject.Find("SpawnPoint").transform.position, Quaternion.identity);
}
}
As you can see, I made the function createBall() in order to respawn a ball prefab at the position of the game object SpawnPoint. When I run the game, the first ball shoots fine. And another ball respawns.
Issue: when I shoot the second ball and it moves, one more ball seems to have appeared at the second ball somehow, and it moves as well. Not sure why this is happening and how to fix it - can someone pls help? Thanks.
The problem is that you need to Destroy() the game object you threw first. Since you are just bringing the objects back when click down again, here is what you should do:
Make it so that it destroys the old object. Because you just keep instantiating the object, then when you throw it again it throws the old one too. If you understand what I mean, then hopefully, you can turn this into what you want. (It wasn’t exactly clear what your game was; this is what I interpreted)

How to call a method every time, when player stay at any collider?

I have a game like CubeSurfer. When player goes through an collectable, two methods are called (for "jumping" and creating a cube under player). But, when player goes through second, or third collectable, nothing happens. I tried to attached script to collectable, and tried to put the method "OnTriggerEnter" in the body of methods "Start" and "Update". But it doesn't work.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCollider : MonoBehaviour
{
[SerializeField] Collider player;
[SerializeField] GameObject destroyIt;
[SerializeField] GameObject objToClone;
[SerializeField] Transform rootObjInScene;
Transform curParent;
Vector3 posOffset, posPlayer;
float distance = 1f;
private void OnTriggerStay(Collider player)
{
PlayerJumping();
CreateAnother();
Destroy(destroyIt);
}
public void PlayerJumping()
{
posPlayer = Vector3.up * distance;
Vector3 playerPos = rootObjInScene.position + posPlayer;
rootObjInScene.transform.position = playerPos;
}
public void Awake()
{
curParent = rootObjInScene;
posOffset = Vector3.down * distance;
}
public void CreateAnother()
{
Vector3 newPos = curParent.position + posOffset;
GameObject newObj = Instantiate(objToClone, newPos, Quaternion.identity, curParent);
curParent = newObj.transform;
}
}
You should also check your Rigibody collision detection mode in the inspector.
By default, this is set to Discrete, but if your object is fast-moving, you should set it to Continuous or ContinuousDynamic, otherwise the collisions won't be registered because the object is moving too quickly.
These are a little bit performance intensive, so I'd still recommreading up on the Unity documentation or digging through a couple of good articles to know what's best for you :)
You shouldn't call OnTriggerEnter explicitly (in your Update()), it's an event message and gets called automatically by unity when you enter a Collider marked isTrigger.
You can use OnTriggerEnter only if your collider is marked isTrigger, if you want to get a collision with a Collider that is not explicitly a trigger, you use OnCollisionEnter
To execute a method repeatedly while touching a Collider use OnCollisionStay, while touching or inside a Collider with isTrigger use OnTriggerStay
OnCollisionStay
OnTriggerStay
You can use OnCollisionStay or OnTriggerStay
void OnCollisionStay(Collision collisionInfo)
{
//Do something when collisionInfo.gameObject stay in this.gameObject collider
}

Bullet passes through the player

I'm using unity and when the enemy shoots, the bullet passes right threw the player. I don't know how to solve this. Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyBullet : MonoBehaviour
{
public float speed;
public Rigidbody2D rb;
private Transform player;
private Vector2 target;
private Vector2 moveDirection;
// Start is called before the first frame update
void Start()
{
player = GameObject.FindGameObjectWithTag("Player").transform;
moveDirection = (player.transform.position - transform.position).normalized * speed;
}
// Update is called once per frame
void Update()
{
rb.velocity = new Vector2(moveDirection.x, moveDirection.y);
//transform.position = Vector2.MoveTowards(transform.position, target, speed * Time.deltaTime);
}
void OnCollisionEnter2D(Collision2D other) {
if (other.gameObject.tag == "Player") {
Destroy(this.gameObject);
}
}
}
I put a tag named BulletEnemy on the bullet but it doesn't work
How fast is your speed value?
At high speeds a bullet might move farther in one frame than the depth of the object you want it to hit. You can still detect collisions by every frame storing the position of your bullet as a vector and on the next frame casting a ray between the current position and the last known position in the previous frame. If the ray hits your enemy then call the same function that you would on a physics collision.
There is no way to do it with only OnCollisionEnter because of the effect of bullet speed.
Check your bullet's speed. if they are too fast, your physics engine just ignore the collision and therefore no OnCollisionEnter will be called.
Use larger Collider for your player. and also check Player tag on your player object. also make sure your tagged object has Collider2D component.
Change OnCollisionEnter2D to OnCollisionStay2D. if you want to Destroy bullet, there will be no difference in runtime

Trying to stop the momentum when re spawn

I have looked around the web for answers but can't find a working one.
I have tried changing the code and I am pretty sure it's a very easy noob mistake as this is my first game.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class respawn : MonoBehaviour
{
[SerializeField] private Transform player;
[SerializeField] private Transform respawnPoint;
private Rigidbody Rigidbody;
void FixedUpdate()
{
if (player.position == respawnPoint.position);
{
GetComponent<Rigidbody>().velocity = 0;
Rigidbody.angularVelocity = 0;
}
}
private void OnTriggerEnter(Collider other)
{
player.transform.position = respawnPoint.transform.position;
}
}
The very first thing you want to do is to look at the Unity error console. Your code throws multiple errors, they will appear in red. Double-click on an error to be taken to its line in your code.
Also, try get a good editor, like VS Code, as it will help you find issues immediately by adding red wavy underlines. With above two approaches in hand, you will be able to find ~99% of your issues yourself the next time, and then can ask in forums for the remaining 1%.
Let's go through your code step by step:
private Rigidbody Rigidbody;
In Unity you normally want the type in upper case Rigidbody, but the variable name in lowercase rigidbody (even though the C# coding conventions suggest uppercase properties). Either way, don't use the same name as the type, so write:
private Rigidbody rigidbody;
or e.g. (I'm now omitting the default private, though you may also prefer to keep it, and I use a shorter variable name, and clarify its start value):
Rigidbody body = null;
In the following code:
GetComponent<Rigidbody>().velocity = 0;
... you first of all get the rigidbody component again. This isn't needed if you got it once in start (and for repeated usage, can lag), so do it like this:
void Start()
{
rigidbody = GetComponent<Rigidbody>();
}
And secondly, you assign a 0, but you want to assign new Vector3(0f, 0f, 0f), or just
rigidbody.velocity = Vector3.zero;
rigidbody.angularVelocity = Vector3.zero;
Lastly, you write
player.transform.position = respawnPoint.transform.position;
... but player and respawnPoint are already transforms, so you can use the simpler
player.position = respawnPoint.position;
Good luck!
When you enter the Trigger you will be teleported to the respawn position, but you cannot depend on FixedUpdate running on that exact pixel of the respawn position.
The most straigh forward answer is to, well, do the code as you would describe the issue: "When you enter a trigger, set the position to the respawn position and set velocity to 0":
I would change the entire script to:
public class respawn : MonoBehaviour
{
[SerializeField] private Transform player;
[SerializeField] private Transform respawnPoint;
private Rigidbody rigidbody;
void Start()
{
rigidbody = GetComponent<Rigidbody>()
}
private void OnTriggerEnter(Collider other)
{
player.position = respawnPoint.position;
rigidbody.velocity = Vector3.zero;
}
}
and don't forget to populate the player and respawnPoint values in the inspector.
Also, keep in mind that the current code is prone to errors, if you have other objects moving around. Right now, if ANY object enters the Trigger the PLAYER position will be reset. You could fix this with check for player
private void OnTriggerEnter(Collider other)
{
if (other.transform == player)
{
player.position = respawnPoint.position;
rigidbody.velocity = Vector3.zero;
}
}

Moving object from one postion to another in unity

I have this code here ,i am trying to move an object from one position to another ,on mouse click ,but everytime i run it it justs instantiate the projectile object in a specific position while it had to instantiate it in a the ffor object position
using UnityEngine;
using System.Collections;
public class Shoot : MonoBehaviour
{
public GameObject projectile;
public GameObject foot;
public GameObject mouse;
void Start()
{
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Vector2 Target = Input.mousePosition;
Vector2 pos1 = Camera.main.ScreenToWorldPoint(Target);
GameObject newObj = (GameObject)GameObject.Instantiate(projectile);
Vector2 pos2 = foot.transform.position;
transform.position=Vector2.Lerp(pos2,pos1,Time.deltaTime);
}
}
There are several issues here, I'll address them one at a time. First, the code for moving the projectile is wired up wrong:
transform.position=Vector2.Lerp(pos2,pos1,Time.deltaTime);
You are moving the object that "Shoot" is attached to, not the new game object (newObj, as you have named it.)
Second, it's important to understand the Update pattern and how to properly use it. Update is run every frame. Time.deltaTime is how much time has passed between the last frame render and this one. This number is usually very small. Lastly, Input.GetMouseButtonDown is true only on the first frame that the mouse is pressed.
The current code you have only attempts to (but fails, due to other code problems) move the projectile the one frame the mouse is clicked. What we want is the mouse click to spawn a projectile, and the projectile to move forward EVERY update.
This will be best accomplished with two classes. I will call them Gun and SeekerBullet. The Gun class will be responsible for creating a bullet every time the mouse button is pressed. The SeekerBullet class will be responsible for moving the bullet to it's target.
Gun
public SeekerBullet ProjectilePrefab;
void Update()
{
if (Input.GetMouseButton(0))
{
Vector2 target = Camera.main.ScreenToWorldPoint(Input.mousePosition);
FireBullet(target);
}
}
void FireBullet(Vector2 target)
{
GameObject projectile = (GameObject)GameObject.Instantiate(ProjectilePrefab, transform.position, Quaternion.Identity);
projectile.GetComponent<SeekerBullet>().Target = target;
}
SeekerBullet
public float MoveSpeed = 5;
public Vector2 Target { get; set; }
public void Update()
{
transform.position = Vector3.MoveTowards(transform.position, Target, MoveSpeed * Time.deltaTime);
if (transform.position == Target)
OnReachTarget();
}
void OnReachTarget()
{
// Do whatever you want here
Destroy(gameObject); // delete this seekerbullet
}
The main Idea I'm trying to stress is isolating your code to perform it's one function well. The gun shouldn't be responsible for moving the projectile, just creating it and telling it where to go.
Also, note that the projectile is starting wherever the Gun is. See this line
GameObject projectile = (GameObject)GameObject.Instantiate(ProjectilePrefab, transform.position, Quaternion.Identity);
The transform.position is the position of the gun object. If you want it to start at the foot, like you have in your code, you can re-implement that just like you have in your example.
Why don't you use Raycast. It's pretty simple. Here's an example (Moves the object (transform) in the direction and distance of translation.):
var obj:Transform;
var hit:RaycastHit;
var move: boolean = false;
var moveSpeed:float;
var moveTime:float;
private var startTime:float;
function Update ()
{
if (Input.GetButtonDown ("Fire1"))
{
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, hit, 10000)){
move = true;
startTime = Time.time;
}
}
if(move){
var curTime = Time.time;
var elapsedTime = curTime - startTime;
var amountToMove = elapsedTime / moveTime;
print(amountToMove);
obj.transform.position = Vector3.Lerp(obj.transform.position, hit.point, amountToMove);
if(obj.transform.position == hit.point){
move = false;
}
This code creates a plane, and a cube. Assign the above code to the plane, assign the cube to the obj var in the inspector. Click on the plane, and watch the fun.
This is pretty simple. You can use the Vector3.Lerp function to achieve this. Use raycasting to get the mouse click position or the touch position. Then use the initial and the final position in the lerp function. The initial position being the position that the gameobject is at now and the final position being the click / touch position.
You can find the article by The Game Contriver on the same here
Move to Touch / Click Position - The Game Contriver