Unity 2d : Objects being reinstantiated on scene reload after being destroyed - c#

GOAL
So I'm creating a top down arena battler type game, and I want you to be able to restart the game by pressing R.
PROBLEM
When I press R, the whole scene resets as it should, except all the enemies that were previously instantiated (and then destroyed) are spawned again, all at once.
CODE
This is the enemy spawning code :
using System.Collections.Generic;
using UnityEngine;
public class EnemySpawn : MonoBehaviour
{
private float nextActionTime = 0.0f;
public float period = 5f;
public GameObject enemy;
void Update()
{
if (Time.time > nextActionTime ) {
nextActionTime += period;
GameObject clone = Instantiate(enemy, new Vector3(-1, 3, 0), Quaternion.identity);
clone.tag = "enemy";
}
}
}
This is the player code, responsible for restarting the scene (I have marked what I belive to be the relevantant sections with dashes) :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class PlayerController : MonoBehaviour
{
public Rigidbody2D rb;
public GameObject Shield;
public GameObject ShieldInstance;
public float moveSpeed = 4.3f;
public float sheildSpeed = 5f;
Vector2 movement;
AudioSource woop;
AudioSource waa;
----------------------------
GameObject[] enemies;
----------------------------
bool isDead = false;
void Start() {
woop = GameObject.Find("Main Camera/ShieldSFX").GetComponent<AudioSource>();
waa = GameObject.Find("Main Camera/DefeatSFX").GetComponent<AudioSource>();
}
void Update()
{
--------------------------------------------------------------
enemies = GameObject.FindGameObjectsWithTag("enemy");
--------------------------------------------------------------
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
Vector3 mouseScreen = Input.mousePosition;
Vector3 mouse = Camera.main.ScreenToWorldPoint(mouseScreen);
transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(mouse.y - transform.position.y, mouse.x - transform.position.x) * Mathf.Rad2Deg - 90);
if (Input.GetMouseButtonDown(0))
{
if (ShieldInstance != null || transform.GetChild(0).GetComponent<SpriteRenderer>().enabled == false) { return; }
woop.Play();
ShieldInstance = Instantiate(Shield, transform.position + transform.forward + transform.up, transform.rotation);
ShieldInstance.transform.parent = transform;
}
if (Input.GetMouseButtonUp(0))
{
if (ShieldInstance == null) { return; }
ShieldInstance.transform.parent = null;
ShieldInstance.GetComponent<ShieldController>().LaunchForward(sheildSpeed);
Destroy(ShieldInstance, 2.3f);
}
-------------------------------------------------------------------------------
if (Input.GetKey("r")) {
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
foreach (GameObject one in enemies) {
Destroy(one);
}
}
-------------------------------------------------------------------------------
}
void FixedUpdate() {
if (!isDead) {
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
}
void OnCollisionEnter2D(Collision2D other) {
if (other.gameObject.tag == "enemy") {
waa.Play();
GameObject.Find("Canvas/gameover").GetComponent<Text>().enabled = true;
transform.GetChild(0).GetComponent<SpriteRenderer>().enabled = false;
GetComponent<PolygonCollider2D>().enabled = false;
}
}
}
And this is the enemy code :
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyFollow : MonoBehaviour
{
public float moveSpeed;
public ParticleSystem explode;
AudioSource boom;
Vector2 movement;
GameObject player;
Rigidbody2D rb;
SpriteRenderer sr;
PolygonCollider2D pc;
void Start() {
rb = GetComponent<Rigidbody2D>();
sr = transform.GetChild(0).GetComponent<SpriteRenderer>();
pc = GetComponent<PolygonCollider2D>();
player = GameObject.Find("Player");
boom = GameObject.Find("Main Camera/ExplodeSFX").GetComponent<AudioSource>();
}
void Update()
{
Vector2 difference = (player.transform.position - new Vector3(2, .5f, 0)) - transform.position;
if (difference.x > 0) {
movement.x = 1;
} else if (difference.x < 0){
movement.x = -1;
} else {
movement.x = 0;
}
if (difference.y > 0) {
movement.y = 1;
} else if (difference.y < 0){
movement.y = -1;
} else {
movement.y = 0;
}
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
void OnCollisionEnter2D(Collision2D other) {
if (other.gameObject.tag == "shield") {
StartCoroutine(ExplodeF());
}
}
private IEnumerator ExplodeF() {
explode.Play();
boom.Play();
sr.enabled = false;
pc.enabled = false;
yield return new WaitForSeconds(explode.main.startLifetime.constantMax);
Destroy(gameObject);
}
}
I would really appreciate any help!
If you want / need more details, just leave a comment :)

The problem is in Time.time, it is time since the start of the application, not since the start of the scene. So if you were in the game 30 secs, Time.time is 30 secs. If you reload the scene it is still 30 secs.
You have to count the time passed since entering the scene. Then it won't respawn all the enemies on scene reload.

When you restart the scene, everything is being destroyed and reset back except for the time.
The problem in your code is in the enemy spawner. Time.time returns the time passed since you started the game (and not since the scene was loaded). So, after the restart the if condition is true and the enemies are spawned.
If you want to count the time (in seconds) since the scene was loaded, what you can do is to add a variable in the enemy spawner class that would count the time
using System.Collections.Generic;
using UnityEngine;
public class EnemySpawn : MonoBehaviour
{
private float nextActionTime = 0.0f;
private float timeSinceStart = 0;
public float period = 5f;
public GameObject enemy;
void Update()
{
if (timeSinceStart > nextActionTime ) {
nextActionTime += period;
GameObject clone = Instantiate(enemy, new Vector3(-1, 3, 0), Quaternion.identity);
clone.tag = "enemy";
}
timeSinceStart += Time.deltaTime;
}
}
See Time.deltaTime

Related

Unity: Why wont my movement return to value 0

Hi im new to programming in C# and i ran into a problem.Eveything is working,only the value wont return to 0 when the button is not pressed,i can change the direction of the movement,but the object wont stop moving...Here is the code!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Movement : MonoBehaviour
{
private Rigidbody2D rb2D;
private float speed = 1f;
private float moveHorizontal;
void Start()
{
rb2D = GetComponent<Rigidbody2D>();
}
void Update()
{
moveHorizontal = Input.GetAxisRaw("Horizontal");
}
void FixedUpdate()
{
if (moveHorizontal > 0.1f || moveHorizontal < -0.1f)
{
rb2D.AddForce(new Vector2 (moveHorizontal * speed, 0f), ForceMode2D.Impulse);
}
}
}
I see you adding forces, but you never reset the velocity to 0 anywhere
you could do this like e.g.
if(Mathf.Abs(moveHorizontal) > 0.1f)
{
...
}
else
{
var vel = rb2D.velocity;
vel.x = 0;
rb2D.velocity = vel;
}

How to flip character when moving left unity 2D

I am trying to flip my character sprite when moving left in my game, and I have followed multiple tutorials however my sprite does not seem to flip. It is always facing the same way.
Below is my code for my character's movement. I have created a Flip() function and 2 if statements used to call the function. The character can move left, right, up and down (no jumping).
I cannot seem to see where an error would be and why it is not flipping, so any help would be appreciated. thank you.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
// Start is called before the first frame update
private Animator animate;
public float moveSpeed = 6f;
bool facingRight = true;
public Rigidbody2D rb;
Vector2 movement;
private void Start()
{
animate = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
animate.SetFloat("Speed", Mathf.Abs(movement.x));
if(movement.x < 0 && facingRight)
{
Flip();
}
else if (movement.x > 0 && !facingRight)
{
Flip();
}
}
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
void Flip()
{
Vector3 currentScale = gameObject.transform.localScale;
currentScale.x *= -1;
gameObject.transform.localScale = currentScale;
facingRight = !facingRight;
}
}
Updated code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
// Start is called before the first frame update
private Animator animate;
public float moveSpeed = 6f;
bool facingRight = true;
public Rigidbody2D rb;
Vector2 movement;
private void Start()
{
animate = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
animate.SetFloat("Speed", Mathf.Abs(movement.x));
if (movement.x < 0 && facingRight)
{
GetComponent<SpriteRenderer>().flipX = true;
}
else if (movement.x > 0 && !facingRight)
{
GetComponent<SpriteRenderer>().flipX = false;
}
}
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
void Flip()
{
Vector3 currentScale = gameObject.transform.localScale;
currentScale.x *= -1;
gameObject.transform.localScale = currentScale;
facingRight = !facingRight;
}
}
Try to set the flipX property of the SpriteRenderer.
GetComponent<SpriteRenderer>().flipX = true;
You have an animator attached to the game object, if the scale value is controlled by the animation clip, you cannot change it. A typical workaround is give the game object an empty parent and change its scale.
Player <---- Change scale here
Model <---- Animator here
transform.Rotate(0f, 180f, 0f); you have to change y while fliping
will work better instead of using currentScale.x *= -1;
gameObject.transform.localScale = currentScale;
This code worked for me
private void Flip()
{
// Rotate the player
if (transform.localEulerAngles.y != 180 && !facingRight)
transform.Rotate(0f, 180f, 0f);
else if(transform.localEulerAngles.y != 0 && facingRight)
transform.Rotate(0f, -180f, 0f);
// player flip point of attck also flip is direction
//transform.Rotate(0f, 180f, 0f);
}
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
GetComponent<SpriteRenderer>().flipX = true;
isLookingRight = false;
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
GetComponent<SpriteRenderer>().flipX = false;
isLookingRight = true;
}
Going to right
Going to left

Unity 2D - Moving Any Object Between Two (or more) Spaces

new Unity person, and new coder in general. I'm trying to have an object move back and forth between two spots. I have it right now going from Point 1 to Point 2, but it stops. I tried a do loop, and to call back the Move() function again but it just froze Unity.
I'm guessing I need some sort of Loop, but not sure where to do it? I wouldn't mind having the ability to add more spots as well. I have waypoints in Unity itself, tied to the Object. Thanks!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ZombiePathing : MonoBehaviour
{
[SerializeField] List<Transform> waypoints;
[SerializeField] float moveSpeed = 2f;
int waypointIndex = 0;
void Start()
{
transform.position = waypoints[waypointIndex].transform.position;
}
// Update is called once per frame
void Update()
{
Move();
}
private void Move()
{
if (waypointIndex <= waypoints.Count -1)
{
var targetPosition = waypoints[waypointIndex].transform.position;
var movementThisFrame = moveSpeed * Time.deltaTime;
transform.position = Vector2.MoveTowards
(transform.position, targetPosition, movementThisFrame);
if (transform.position == targetPosition)
{
waypointIndex++;
}
}
}
}
just add an index equal to 1 or -1 depends on the current transform,
I wrote this code very quickly so it's unsorted, and I do my best to make it very close to your code with some edits.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ZombiePathing : MonoBehaviour
{
[SerializeField] List<Transform> waypoints;
[SerializeField] float moveSpeed = 2f;
Vector3 targetPosition;
int waypointIndex = 0;
int index = 1;
void Start()
{
transform.position = waypoints[waypointIndex].position;
UpdateTransform();
}
void Update()
{ transform.position = Vector2.MoveTowards
(transform.position, targetPosition, moveSpeed * Time.deltaTime);
if (transform.position == targetPosition) UpdateTransform();
}
private void UpdateTransform()
{
waypointIndex += index;
targetPosition = waypoints[waypointIndex].position;
if (waypointIndex >= waypoints.Count -1) index = -1;
else if (waypointIndex <= 0 && index == -1)index = 1;
}
}

How can i make my prefab completely reverse (180 degrees) from it's spawnpoint? Unity 2D

So i made a little side scroller that uses a prefab to spawn bullets.
My problem is that it only shoots to one side... the Right.
I need it to fire to the left as well. I've already made a variable to see if the player is looking to the right or left.
I've tried to put the Speed to -20 and i've tried to rotate it 180 degrees on it's Z axis. I tested if the bullet script even picked up the change from the player movement script and it does.
Player Movement script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public GameObject bullet;
private Rigidbody2D myRigidbody;
private float speed = 15;
private bool facingRight;
private bool ground = false;
private float jump = 23;
// Start is called before the first frame update
void Start()
{
facingRight = true;
myRigidbody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void FixedUpdate()
{
float horizontal = Input.GetAxis("Horizontal");
Movement(horizontal);
Flip(horizontal);
if (Input.GetKey("w"))
{
if (ground)
{
GetComponent<Rigidbody2D>().velocity = new Vector2(GetComponent<Rigidbody2D>().velocity.x, jump);
}
}
if(facingRight == false)
{
bullet.GetComponent<bullet>().left = true;
}
if (facingRight == true)
{
bullet.GetComponent<bullet>().left = false;
}
}
void OnTriggerEnter2D()
{
ground = true;
}
void OnTriggerExit2D()
{
ground = false;
}
private void Movement(float horizontal)
{
myRigidbody.velocity = new Vector2(horizontal * speed,myRigidbody.velocity.y);
}
private void Flip(float horizontal)
{
if (horizontal > 0 && !facingRight || horizontal < 0 && facingRight)
{
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
}
Weapon script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class weapon : MonoBehaviour
{
// Start is called before the first frame update
public bool right;
public Transform firepointR;
public GameObject bulletPrefab;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown("space"))
{
Debug.Log("Oh well");
Shoot();
}
}
void Shoot()
{
Instantiate(bulletPrefab, firepointR.position, firepointR.rotation);
}
}
bullet script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class bullet : MonoBehaviour
{
public bool left;
public float speed = 20;
public Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
rb.velocity = transform.right * speed;
}
// Update is called once per frame
void FixedUpdate()
{
Debug.Log(speed);
if (left == false)
{
transform.Rotate(0, 0, 180);
}
}
}
As i previously said i need my bullet (prefab) to go the opposite direction but whatever i do right now it will always go right.
Expanding on my comment:
Did you try reversing the velocity?
rb.velocity = -(transform.right * speed);
Note: There are instances when using a negative float wont return the opposite of the positive result. However, in this example, it will work just fine.
I imagine this will work also (and is probably the correct way of doing it):
rb.velocity = transform.left * speed;

My character is animating but still not moving

I am just starting out with unity and am also making a game for a school project. My 2d game character can do the walk animation when I press the "a" and "d" keys and the sprite flips, but it stays in the same position. Below is my PlayerController script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private float speed = 3f;
private Animator anim;
private SpriteRenderer sr;
// Start is called before the first frame update
void Awake()
{
anim = GetComponent<Animator>();
sr = GetComponent<SpriteRenderer>();
}
// Update is called once per frame
void Update()
{
Move();
}
void Move()
{
float h = Input.GetAxisRaw("Horizontal");
Vector3 temp = transform.position;
if (h > 0)
{
temp.x += speed * Time.deltaTime;
sr.flipX = true;
anim.SetBool("Walk", true);
}
else if (h < 0)
{
temp.x -= speed * Time.deltaTime;
sr.flipX = false;
anim.SetBool("Walk", true);
}
else if (h == 0)
{
anim.SetBool("Walk", false);
}
}
}
You're setting 'temp' to equal transform.position, but that doesn't mean that transform.position equals 'temp'. Here, the below script should give you what you want
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private float speed = 3f;
private Animator anim;
private SpriteRenderer sr;
void Awake()
{
anim = GetComponent<Animator>();
sr = GetComponent<SpriteRenderer>();
}
void Update()
{
Move();
}
void Move()
{
float h = Input.GetAxisRaw("Horizontal");
transform.Translate(Vector2.right * (h * speed * Time.deltaTime));
anim.SetBool("Walk", h != 0f);
if (anim.GetBool("Walk"))
Flip(h > 0f);
}
void Flip(bool facingRight)
{
sr.flipX = !facingRight;
}
}

Categories

Resources