Getting more than one possition though code (unity c#) - c#

i made a "turret" in unity that shoots automatically on enemies it works with one enemy but when i put 2 it shoots in the midle of then dont know why it does that
public transform enemy;
public void Update() {
enemy = Gameobject.FindgameObjectWithTag("Enemy").getComponent<Transform>;
//just put the getting the possition part because the shooting works just fine
}

Your script is refreshing the enemy position every Update() iteration.
Try to have the turret stick to the enemy until it gets out of range, or until it is dead. Before doing your variable assignation, check if enemy != null, if it is the case, then you can write :
enemy = Gameobject.FindgameObjectWithTag("Enemy").getComponent<Transform>;
Also, try to avoid refreshing every Update() call, instead, use a different function that you call every half second.
I recommend you checking this project by Brackeys, that handles the situation perfectly. Here
GLHF

Related

Child Objects Not Following Parent Object On Frequent Teleportation

Game Screen
Teleportation Code
Child Objects And Their Original Location
I'm new to Unity, and so after taking just some regular online courses for Unity2D I wanted to mess around with adding in different features, the first of which I decided to do was something like in Portal, where a projectile spawns two connected portals you can teleport between. However, I've run into an issue. When I'm teleporting my character, sometimes, usually when I'm teleporting too quickly but can happen at any time, the child objects to the Player game object tend to shift, and I don't understand why. **I'd like to:
Know why the offset between the parent and child objects are changing through teleportation.
Know how to fix this issue, preferably in code I can easily understand as a beginner to Unity. Also preferably in a way that doesn't involve me constantly appending the child objects to the parent object through transform position with the added offset, though if it's the simplest solution I'm not against trying it.**
Something worth noting is that the offset change is different as well, I have a Child Object called Feet which detect the Ground for jumping, which seems to remain at the location of the previous portal when it first breaks. However, another child object called Gun which is where the projectiles spawn from seem to only move down a little bit, meaning there's inconsistency in how they are offset when they break. It might be because the Feet has a collider, but I'm unsure, don't know enough, and only felt it was worth mentioning.
[SerializeField] GameObject otherPortal;
Portal otherPortalComponent;
BoxCollider2D boxCollider2D;
bool firstEntered = true;
// Start is called before the first frame update
void Start()
{
boxCollider2D = GetComponent<BoxCollider2D>();
otherPortalComponent = otherPortal.GetComponent<Portal>();
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (boxCollider2D.IsTouchingLayers(LayerMask.GetMask("Player")) && firstEntered)
{
Teleport(collision.gameObject);
otherPortalComponent.SetFirstEnteredFalse();
}
}
private void Teleport(GameObject obj)
{
obj.transform.position = otherPortal.transform.GetChild(0).transform.position;
}
public void SetFirstEnteredFalse()
{
this.firstEntered = false;
}
private void OnTriggerExit2D(Collider2D collision)
{
this.firstEntered = true;
}
To simplify the question, the position of the child objects relative to the parent changes when I instantly change the parents position sometimes, why does this happen and how do I fix the issue without simply using transform.position in an Update method to constantly append the child to the parent, if possible.
I would look at your OnTriggerEnter2D method's if statement for a solution.
private void OnTriggerEnter2D(Collider2D collision)
{
if (boxCollider2D.IsTouchingLayers(LayerMask.GetMask("Player")) && firstEntered)
{
Teleport(collision.gameObject);
otherPortalComponent.SetFirstEnteredFalse();
}
}
Because you are using OnTriggerEnter this method will only be called with your feet since your player's main collider isn't a Trigger. This means that your collision variable that you call your Teleport method on is actually your feet object, not your player's body object. So you are changing the offset of your feet from your player in your Teleport method.
I would try changing your collision method to OnCollisionEnter2D(Collision2D)
which would pick up your player's base collider when it enters and not the feet collider.
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.GetComponent<Player>() && firstEntered)
{
Teleport(collision.gameObject);
otherPortalComponent.SetFirstEnteredFalse();
}
}
Since the Player script is on the same object as your base player collider you can do a simple GetComponent<Player>() call to check if its the player object. Though you could still use the Layer to check if you want.

Instantiate creates multiple clones in Unity

I have the following code:
public Rigidbody2D ball;
Vector2 sp = new Vector2(0f, 2.1f);
void Update() {
if (Input.GetKeyDown("w")) {
SpawnBall();
DestroyBall();
}
}
void SpawnBall()
{
Instantiate(ball, sp, transform.rotation);
}
void DestroyBall()
{
if (ball.transform.position.y >= -5.7f)
{
Destroy(ball);
}
}
and the code is supposed to generate a new ball every time when "w" is pressed, but for some reason it creates multiple clones and it crashes the engine. How can I create a single clone only?
And also the destroy method doesn't do anything, although it should remove the clone when it passes -5.7 on the y-axis.
Thanks in advance
Create a new script named "SpawnRigidbody" and copy and paste the below code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnRigidbody : MonoBehaviour
{
public Rigidbody2D ball;
Vector2 sp = new Vector2(0f, 2.1f);
void Update()
{
if (Input.GetKeyDown("w")) {
SpawnBall();
}
}
void SpawnBall()
{
Debug.Log ("spawn");
GameObject go = Instantiate(ball, sp, transform.rotation).gameObject;
go.AddComponent<DestroyAfterPosition> ();
}
}
Now create another script named "DestroyAfterPosition" and copy and paste the below code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DestroyAfterPosition : MonoBehaviour
{
void Update ()
{
if (transform.position.y <= -5.7f)
{
Destroy(gameObject);
}
}
}
Create an empty game object and attach the SpawnRigidbody and then assign your ball in the inspector.
Hope this help you.
There are a couple problems with your Destroy() statement. First, it is destroying ball which is the Rigidbody2D. You will instead want to destroy the gameobject attached to the ball:
Destroy(ball.gameObject);
Second, you are trying to destroy the ball immediately after it is created, but only if y>=-5.7f. I think instead what you are looking to do is continuously check if the ball is above that point and destroy it if it is. Since you are creating multiple balls, they will all need their own check, which means you need to create a script for the ball prefab and in the Update() check its position and Destroy(gameObject) as necessary.
I think you may want to declare ball as a GameObject at the beginning of your script as well, so you are instantiating a gameobject and not just a Rigidbody2D:
public GameObject ball;
Object.Instantiate creates a clone of the provided object, so each time it is called a new object is created. MonoBehaviour.Update is called every frame, which means it's called at least 30 times per second (usually 60 or more on a PC).
So 30+ times per second, your code checks if the w key is held down, and, if so:
A clone of ball is created
Destroy the original ball if it is beyond -5.7 on the y-axis.
Thus, you're creating 30+ ball clones per second, and none will be deleted (because the DestroyBall method only looks at the original ball, not the clones).
If you want to work with the cloned object, assign the result of Instantiate to a field:
ballClone = Instantiate(ball, sp, transform.rotation);
Then you can check if ballClone exists and skip the SpawnBall call if the clone already exists. You can also use ballClone in the DestroyBall method.
ryemoss' answer seems like it's
also important. This answer is just based on looking at your code and the public Unity docs; I don't have a lot of experience with Unity.
Your destroy call is being called once, and only immediately after creating the object.
So it's currently doing this...
User clicks button...
Create ball...
Check to see if the ball is a certain height. It's not, so ignore...
Ball drops down based on gravity or whatever force compels it.
... and is never deleted.
If you want the ball to be destroyed when it reaches a certain point, either...
Have SpawnBall return the game object, which you store and check / delete later in Update,
...or...
Create a script that just checks the object's transform.position and blows up if it's where it needs to be. Attach that to the prefab of the ball you're creating a duplicate of.

Falling Blocks on player touch - Unity (C#)

I'm making a game in unity for a school project. I'm stuck on this one part where I want a block to fall and be destroyed once a player has touched the block and moved to the next. Having so much trouble and would love some assistance.
The concept of what i'm aiming for can be seen here: http://www.coolmath-games.com/0-b-cubed
On each block, you'll need to attach a script which contains the OnCollisionExit () method (reference). Pass in the collision parameter (see reference) and use the collision info to confirm that the object leaving the collider is the player (eg tag the player with a player tag in the inspector and check the collision's collider's tag).
In this method, place your code for making the block fall.
Make sure you've added colliders to your objects so that they interact. If you run into problems, post back some code and I'll get back to you.
Actually you do not need to detect collision here. It is not neccessary. Just compare base cube position with player cube position in x,z plane (there should be only difference in Y-axis since player cube is over base cube). No need for collsions here. Than you attach script to all base cubes checking for playercube to hover other them (position check) and than on playercube next movement you attach rigidbody to basecube and destroy it after a second. Simple:)
EDIT
The code should look like this. More or less.
GameObject playerCube; //this is reference to Player object
bool playerEnter = false;
bool playerLeft = false;
void Start()
{
playerCube = Gameoject.Find("PlayerCube"); // here you put the name of your player object as a string. Exactly as it is in the hierarchy
}
void Update()
{
if(playerCube.transform.position.x == transform.position.x && playerCube.transform.position.z == transform.position.z)
{
playerEnter = true; // this checks if player stepped on the cube
}
if((playerCube.transform.position.x != transform.position.x || playerCube.transform.position.z != transform.position.z) && playerEnter == true && playerLeft == false) //checks if player left the cube
{
playerLeft = true; // we do this so the code below is executed only once
gameObject.AddComponent<Rigidbody>(); // ads rigidbody to your basecube
Destroy(gameObject, 1.0f); //destroys baseCube after one second
}
I think that more or less that should do it. In the final game I probably would use coroutines for your task. Also you need to think how do you check if the cube already was destroyed, I mean how will your game detect if player can step on the next cube - does it exist or not?
EDIT 2
Hard to tell what will work or not without your hierarchy, your code and knowing what do you want to have exactly. Study this code - it will work after some adjustments to your needs

Unity3D - Instantiated gameobject loses method?

Hey everyone and thanks for taking the time.
I'm currently working on a 2D something in Unity and have the following problem:
We have a spawner that periodically creates 'thing':
public float spawnTime = 3;
public Object thing; //public GameObject thing;
// Use this for initialization
void Start () {
InvokeRepeating("spawn", spawnTime, spawnTime);
}
void spawn ()
{
Vector3 pos = new Vector3(-14, 0, 0);
Quaternion ori = new Quaternion(0, 0, 0, 0);
Instantiate(thing, pos, ori);
}
And it does a good job. Meet 'thing':
void Start () {
InvokeRepeating("move", 0.1f, 0.1f);
}
void move()
{
transform.Translate(0.2f, 0, 0);
if (this.transform.position.x > 14)
{
Destroy(this); //Destroy(GameObject);
So basically a 'thing' is created, hauls itself from -14 to 14 and then suffocates.
Problem: As soon as the first 'thing' is deleted the newly created (not the ones already moving) dont ever move from -14.
I guess I haven't properly specified which method to call periodically but wasn't able to find a proper solution in the unity3d top-down-shooter or similar examples.
Thanks again.
€: After applying the proposed changes the spawner stops creating 'thing's after 3 cycles of creation.
€: My mistake was not using the 'thing' as a prefab (dragging it into "assets" as described in the beautiful answer) so I was referencing a soon to be deleted instance of my 'thing'. Dragged it to hell (assets) and was happy ever after.
I recreated you setup with just these scripts and what I got is that the objects just didn't get destroyed, but newly spawned moved properly until 14.
The reason they didn't get destroyed though is, that you called Destroy(this); which destroys the script component, not the gameobject. So this should be Destroy(gameObject); instead. With this fix it runs just fine for me.
Also, if there is no special reason to use object, your public Object thing; should better be public GameObject thing;.
Edit:
How I set it up:
Created a Empty (renamed it to Spawner)
Created a Sphere (as my thing, renamed it to Ball)
Made Ball a prefab by dragging it into the assets folder
Deleted the Ball from the scene
Created a Spawner script and put your spawning code into it
Created a Ball script and put your move code into it
Made the two changes to the scripts
Put the Spawner script on the spawner gameobject
Dragged the Ball prefab on into the public GameObject thing of Spawner
Put the Ball script on the ball prefab
Done.

Spawning Enemy issue

I'm trying to have my game spawn enemies when ever the player reaches a way point.
Right now, I have this functionality working. When my player gets to the first way, the enemies spawn. He only moves on once he has killed all of the enemies on the screen are dead. However, when he gets to the second way point, no enemies spawn.
Right now, in my collision class I call the following line of code:
Destroy(gameObject)
Whilst this work for the first way point, the second one wont spawn anything as the game object my collision class has been attached to has been destroyed. However, all of my enemies are prefabs and I thought the destroy function would only destroy that instance of the prefab. No matter when you called the instantiate method, it would only destroy that instance.
I'm spawning my enemies with the following method:
public GameObject SpawnEnemies()
{
Vector3 _position = new Vector3(transform.position.x, transform.position.y, transform.position.z);
// instantiate particel system
Instantiate(_particle, _position, Quaternion.identity);
_clone = (GameObject)Instantiate(_enemy, _position, transform.rotation);
_ai = _clone.GetComponent<HV_BaseAI>();
_ai._waypoints = _wayPoints;
return _clone;
}
Then I'm finding out how many of the enemies are still alive with the following code in my collision method:
GameObject g, f; // enemies I want to spawn
g = GameObject.FindGameObjectWithTag("SectionController");
f = GameObject.FindGameObjectWithTag("SectionController");
HV_SectionController tempSectionControllerGroundEnemies, tempSectionControllerFlyingEnemies;
tempSectionControllerGroundEnemies = g.GetComponent<HV_SectionController>();
tempSectionControllerFlyingEnemies = f.GetComponent<HV_SectionController>();
tempSectionControllerGroundEnemies._numberOfGroundEnemies.Remove(gameObject); // remove enemies from list
tempSectionControllerFlyingEnemies._numberOfFlyingEnemies.Remove(gameObject);
//Destroy(gameObject);
_numberOfGroundEnemies = tempSectionControllerGroundEnemies._numberOfGroundEnemies.Count;
_numberOfFlyingEnemies = tempSectionControllerFlyingEnemies._numberOfFlyingEnemies.Count;
Then when I want to move on I do the following check:
if (_groundEnemiesRemaining == 0)
{
MoveToNextSection();
_sectionStartTime = Time.time;
}
i know the above line is checking only one type of enemy at the moment, but its the ground enemies I'm having issues with at the moment.
Does anyone know how I can delete the enemy prefab I'm spawning from my first section, once they've been hit, then have it respawn at the next section without the error:
The object of type 'GameObject' has been destroyed but you are still
trying to access it.
My guess would be that the gameobjects are being "destroyed" by two different collision events. First one destroys it, second throws the error.
What I've done in similar situations is put the Destroy code within the object being destroyed. Then from within your collision class, use gameObject.SendMessage(string) to send a message to the actual object, which destroys it.
Without seeing further code I can't speculate as to the origin of the error, but the above is my best guess. SendMessage can also take a DontRequireReceiver parameter, so it won't pop an error if two collision events try to send it a message.
Instead of destroying them u can just disable them using gameObject.SetActive() !

Categories