How can I respawn the object again after player collides with it? - c#

I want to respawn object at a new position immediately after player collides with it.
For now my code just spawn the object after respawn time and destroy the previous object.
The code on my empty object on unity2d is
public GameObject point;
private Vector2 screenBounds;
public float respawnTime = 10f;
GameObject star;
void Start()
{
screenBounds = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, Camera.main.transform.position.z));
spawnStar();
StartCoroutine(starWave());
}
public void spawnStar()
{
Debug.Log("Yeah it works");
star = Instantiate(point) as GameObject;
star.transform.position = new Vector2(Random.Range(-screenBounds.x, screenBounds.x), Random.Range(-screenBounds.y, screenBounds.y));
}
IEnumerator starWave()
{
while (true)
{
yield return new WaitForSeconds(respawnTime);
Destroy(star);
spawnStar();
}
}
And the script on object prefab is
void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject.tag == "Player")
{
Debug.Log("this is star collider destory");
Destroy(this.gameObject);
}
}

Spawner script
public GameObject point;
void Start()
{
spawnStar();
}
public void spawnStar()
{
Debug.Log("Yeah it works");
star = Instantiate(point) as GameObject;
}
Prefab script
// how long before our star moves
private timeBeforeMoving = 10f;
// our current time
private currentTimer = 0.0f;
// the screen size
private Vector2 screenBounds;
void Start()
{
screenBounds = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, Camera.main.transform.position.z));
transform.position = GenerateNewPosition();
}
private void Update()
{
// increase the time that has passed
currentTimer += Time.deltaTime;
// we have reached the timer threshold, so move the star
if(currentTimer >= timeBeforeMoving)
{
MoveOurStar();
}
}
void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject.tag == "Player")
{
MoveOurStar();
}
}
private void MoveOurStar()
{
// reset the timer as we just moved
currentTimer = 0.0f;
transform.position = GenerateNewPosition();
}
private Vector2 GenerateNewPosition()
{
return new Vector2(Random.Range(-screenBounds.x, screenBounds.x), Random.Range(-screenBounds.y, screenBounds.y));;
}
Instead of destroying it run your randomize position code again. If you do not want it spawning in the same location as the player, you can use a circle cast to determine if the new location the object will spawn is still on top of the player. If it is, just randomly pick a new location again.
If you do not want to put your spawn code inside of the star script when you create the star you can set a delegate callback in the star script to call back to the script that is spawning it letting it know it needs to be moved. Or make the spawner a singleton or even implement an eventsystem to fire an event when the object is destroyed letting the manager know to move that specific object.
If you would like to just go with the example code snippet I provided and are having trouble implementing the circle cast, let me know and I can provide another snippet.
Edit: I changed the code around a bit. Now the spawner will just spawn a single star and the star handles where it moves after it collides.

Related

Script keeps Vector2 values after the scene gets reloaded. Setting new X,Y values in Awake() or Start() functions doesn't work after second load

I'm making a game for android/IOS and I'm using a Vector2 to move the player diagonally by pressing/tapping two buttons(left,right). My problem is that after the player collides with an object and dies, and the scene reloads. The X,Y values equals the values before the reload but i want them to be 0, 0.
I've fiddled around with these three scripts below. It might be something to do with the player object becoming inactive. (Sorry if it's messy first time posting)
//from player movement script
private void Awake()
{
moveChange = new Vector2(0.0f, 0.0f);
}
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void FixedUpdate()
{
Vector3 movement = moveChange * speed * Time.deltaTime;
rb.MovePosition(transform.position + movement);
}
public void ClickR()
{
moveChange = new Vector2(0.5f, 1.0f);
}
public void ClickL()
{
moveChange = new Vector2(-0.5f, 1.0f);
}
//from collision script
private void OnTriggerEnter2D(Collider2D other)
{
GameObject e = Instantiate(explosion) as GameObject;
e.transform.position = transform.position;
this.gameObject.SetActive(false);
}
//from reload script
void Update()
{
if (GameObject.FindWithTag("Player") == null)
{
timer += Time.deltaTime;
if (timer > beforeLoading)
{
Scene scene = SceneManager.GetActiveScene();
SceneManager.LoadScene(scene.name);
}
}
}
So the player object doesn't move on the first scene load, as intended, but instantly starts moving to left/right depending on which button has been pressed/tapped before the scene reloads. I've tried to set the X,Y values to 0f, 0f in the Awake() / Start() functions and also in OnTriggerEnter but it didn't work.
One thing I did notice is that if i tap somewhere else on the screen(android) other than the buttons before reloading level the player doesn't move and X, Y is set to 0, 0.
It had nothing to do with the code. I changed the "Event type" on the "Event Trigger" script on the buttons to "PointerDown" instead of "PointerEnter" and now it's working as intended. As simple as that.

My bullet spawns randomly and does no damage

using UnityEngine;
using System.Collections;
using System;
public class TurretScript : MonoBehaviour
{
public float rangeToPlayer;
public GameObject bullet;
// public GameObject spherePrefab;
private GameObject player; // Tag for DynamicWaypointSeek
private bool firing = false; //Firing status
private float fireTime; // Fire Time
private float coolDown = 1.00F; // Time to cool down fire
private int health = 5; //Health of turret
private bool bDead;
private Action cur;
void Start()
{
player = GameObject.FindWithTag("Player");
bDead = false;
}
void Update()
{
if (PlayerInRange())
{ // PlayerInRange is bool function defined at the end
transform.LookAt(player.transform.position); //Rotates the transform (weapon) so the forward vector points at /target (Player)/'s current position
RaycastHit hit;
if (Physics.SphereCast(transform.position, 0.5F, transform.TransformDirection(Vector3.forward), out hit))
{ //The center of the sphere at the start of the sweep,The radius of the sphere,The direction into which to sweep the sphere.
if (hit.transform.gameObject.tag == "Player")
{ //information in hit (only interested in "Player")
if (firing == false)
{
firing = true;
fireTime = Time.time; //keep the current time
GameObject bul;
Quaternion leadRot = Quaternion.LookRotation(player.transform.position); //Calculate the angular direction of "Player";
bul = Instantiate(bullet, transform.position, leadRot) as GameObject; // existing object to be copied, Position of Copy, Orientation of Copy
//Destroy(bullet, 2.0f);
}
}
}
}
if (firing && fireTime + coolDown <= Time.time) // prvious time stored in fireTime + cool down time is less --> means the firing must be turn off
firing = false;
// Destroy(GameObject.FindGameObjectWithTag("Bullet"));
if (health <= 0)
cur = Deadstate;
}
protected void Deadstate()
{
if (!bDead)
{
bDead = true;
Explode();
}
}
void Explode()
{
Destroy(gameObject, 1.5f);
}
bool PlayerInRange()
{
return (Vector3.Distance(player.transform.position, transform.position) <= rangeToPlayer); //Vector3.Distance(a,b) is the same as (a-b).magnitude.
}
void OnTriggerEnter(Collider col)
{
HealthBarScript.health -= 10f;
}
}`
This is code I wrote for a enemy turret in my current unity project. The idea is that it will fire a bullet at the player once it's in range and stop when it's out of range and when the bullet collides with the player, the player will take damage, but I'm struggling to figure out why the bullet won't do any damage. Thoughts? Very much appreciate the help!
According to my experience: bullet speed may be too fast to detect collision.
Imagine that in 2d:
frame 1:
.BB.......OOO......
frame 2:
........BBOOO......
frame 3:
..........OOO..BB..
Where OOO is your object and BB is your bullet.
To fix this you can have a bigger collider for the bullet. Other workaround like "dynamic" collider are also possible.

getting my 2d sprite flip to work depending on a Transform's location from it

So, this code just isn't responding for whatever reason. I have an enemy that I'm trying to get to face the player at all times (The enemy swoops over the player's head back and forth periodically). But other than making a flip happen whenever a timer hits 0, which doesn't really work all that well, I can't get the Flip function to work. I know the Flipper function is fine; I already tested it out and everything. I'm just not sure how to tell the enemy that when the player is to the left of it, to turn, and vice versa.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class dragoonDetection : MonoBehaviour {
private Rigidbody2D rb;
private Animator anim;
public Transform Player;
private bool facingRight = true;
void Start ()
{
rb = GetComponent<Rigidbody2D> ();
anim = GetComponent<Animator> ();
}
void Update()
{
Flip();
}
void Flip()
{
if (Player.transform.localScale.x > 0) {
transform.localScale = new Vector3 (1.69f, 1.54f, 1f);
}
if (Player.transform.localScale.x < 0) {
transform.localScale = new Vector3 (-1.69f, 1.54f, 1f);
}
}
void Flipper()
{
facingRight = !facingRight;
Vector2 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
Got any ideas? I'd rather avoid using FindGameObject because it's not actually looking for the player script. It's looking for a child transform with no script attached to the player. And because I have two different player GameObjects that you can switch to anytime in the game, it wouldn't really work for me in that regard.
You will need to perform a check of some sort against the players position with the bird position if you want it to face the player at all times. A barebones method would just be to compare the x-positions of the two objects and change the scale accordingly.
void Update()
{
transform.localScale = new Vector3(getDir()*1.69f, 1.54f, 1);
}
private int getDir()
{
if (player.transform.position.x < transform.position.x)
return -1;
else
return 1;
}
You should throw some additional checks in here to keep it from updating the scale every frame when there is no change.

How can I add a particle system while my player is dead?

I have a death animation already. I want a particle system particleRed to start along with the death animation. I have a private variable particleRed and I have initiated it in the awake function.
What should I do now?
using UnityEngine;
using System.Collections;
using UnityStandardAssets.CrossPlatformInput;
public class CharacterController2D : MonoBehaviour {
// player controls
[Range(0.0f, 10.0f)] // create a slider in the editor and set limits on moveSpeed
public float moveSpeed = 3f;
public float jumpForce = 600f;
// player health
public int playerHealth = 1;
// LayerMask to determine what is considered ground for the player
public LayerMask whatIsGround;
// Transform just below feet for checking if player is grounded
public Transform groundCheck;
// player can move?
// we want this public so other scripts can access it but we don't want to show in editor as it might confuse designer
[HideInInspector]
public bool playerCanMove = true;
// SFXs
public AudioClip coinSFX;
public AudioClip deathSFX;
public AudioClip fallSFX;
public AudioClip jumpSFX;
public AudioClip victorySFX;
// private variables below
// store references to components on the gameObject
Transform _transform;
Rigidbody2D _rigidbody;
Animator _animator;
AudioSource _audio;
ParticleSystem particleRed;
// hold player motion in this timestep
float _vx;
float _vy;
// player tracking
bool facingRight = true;
bool isGrounded = false;
bool isRunning = false;
bool _canDoubleJump = false;
// store the layer the player is on (setup in Awake)
int _playerLayer;
// number of layer that Platforms are on (setup in Awake)
int _platformLayer;
void Awake () {
// get a reference to the components we are going to be changing and store a reference for efficiency purposes
_transform = GetComponent<Transform> ();
_rigidbody = GetComponent<Rigidbody2D> ();
if (_rigidbody==null) // if Rigidbody is missing
Debug.LogError("Rigidbody2D component missing from this gameobject");
_animator = GetComponent<Animator>();
if (_animator==null) // if Animator is missing
Debug.LogError("Animator component missing from this gameobject");
_audio = GetComponent<AudioSource> ();
if (_audio==null) { // if AudioSource is missing
Debug.LogWarning("AudioSource component missing from this gameobject. Adding one.");
// let's just add the AudioSource component dynamically
_audio = gameObject.AddComponent<AudioSource>();
}
particleRed = GetComponent<ParticleSystem>();
// determine the player's specified layer
_playerLayer = this.gameObject.layer;
// determine the platform's specified layer
_platformLayer = LayerMask.NameToLayer("Platform");
}
// this is where most of the player controller magic happens each game event loop
void Update()
{
// exit update if player cannot move or game is paused
if (!playerCanMove || (Time.timeScale == 0f))
return;
// determine horizontal velocity change based on the horizontal input
_vx = CrossPlatformInputManager.GetAxisRaw ("Horizontal");
// Determine if running based on the horizontal movement
if (_vx != 0)
{
isRunning = true;
} else {
isRunning = false;
}
// set the running animation state
_animator.SetBool("Running", isRunning);
// get the current vertical velocity from the rigidbody component
_vy = _rigidbody.velocity.y;
// Check to see if character is grounded by raycasting from the middle of the player
// down to the groundCheck position and see if collected with gameobjects on the
// whatIsGround layer
isGrounded = Physics2D.Linecast(_transform.position, groundCheck.position, whatIsGround);
// Allow Double Jump after grounded
if (isGrounded)
{
_canDoubleJump = true;
}
// Set the grounded animation states
_animator.SetBool("Grounded", isGrounded);
if (isGrounded && CrossPlatformInputManager.GetButtonDown ("Jump")) { // If grounded AND jump button pressed, then allow the player to jump
DoJump ();
} else if (_canDoubleJump && CrossPlatformInputManager.GetButtonDown ("Jump"))
{
DoJump();
// double jumo can be possible once
_canDoubleJump = false;
}
// If the player stops jumping mid jump and player is not yet falling
// then set the vertical velocity to 0 (he will start to fall from gravity)
if(CrossPlatformInputManager.GetButtonUp("Jump") && _vy>0f)
{
_vy = 0f;
}
// Change the actual velocity on the rigidbody
_rigidbody.velocity = new Vector2(_vx * moveSpeed, _vy);
// if moving up then don't collide with platform layer
// this allows the player to jump up through things on the platform layer
// NOTE: requires the platforms to be on a layer named "Platform"
Physics2D.IgnoreLayerCollision(_playerLayer, _platformLayer, (_vy > 0.0f));
}
// Checking to see if the sprite should be flipped
// this is done in LateUpdate since the Animator may override the localScale
// this code will flip the player even if the animator is controlling scale
void LateUpdate()
{
// get the current scale
Vector3 localScale = _transform.localScale;
if (_vx > 0) // moving right so face right
{
facingRight = true;
} else if (_vx < 0) { // moving left so face left
facingRight = false;
}
// check to see if scale x is right for the player
// if not, multiple by -1 which is an easy way to flip a sprite
if (((facingRight) && (localScale.x<0)) || ((!facingRight) && (localScale.x>0))) {
localScale.x *= -1;
}
// update the scale
_transform.localScale = localScale;
}
// if the player collides with a MovingPlatform, then make it a child of that platform
// so it will go for a ride on the MovingPlatform
void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.tag=="MovingPlatform")
{
this.transform.parent = other.transform;
}
}
// if the player exits a collision with a moving platform, then unchild it
void OnCollisionExit2D(Collision2D other)
{
if (other.gameObject.tag=="MovingPlatform")
{
this.transform.parent = null;
}
}
//make the player jump
void DoJump()
{
// reset current vertical motion to 0 prior to jump
_vy = 0f;
// add a force in the up direction
_rigidbody.AddForce (new Vector2 (0, jumpForce));
// play the jump sound
PlaySound(jumpSFX);
}
// do what needs to be done to freeze the player
void FreezeMotion() {
playerCanMove = false;
_rigidbody.isKinematic = true;
}
// do what needs to be done to unfreeze the player
void UnFreezeMotion() {
playerCanMove = true;
_rigidbody.isKinematic = false;
}
// play sound through the audiosource on the gameobject
void PlaySound(AudioClip clip)
{
_audio.PlayOneShot(clip);
}
// public function to apply damage to the player
public void ApplyDamage (int damage) {
if (playerCanMove) {
playerHealth -= damage;
if (playerHealth <= 0) { // player is now dead, so start dying
PlaySound(deathSFX);
StartCoroutine (KillPlayer ());
}
}
}
// public function to kill the player when they have a fall death
public void FallDeath () {
if (playerCanMove) {
playerHealth = 0;
PlaySound(fallSFX);
StartCoroutine (KillPlayer ());
}
}
// coroutine to kill the player
IEnumerator KillPlayer()
{
if (playerCanMove)
{
// freeze the player
FreezeMotion();
// play the death animation
_animator.SetTrigger("Death");
// After waiting tell the GameManager to reset the game
yield return new WaitForSeconds(2.0f);
if (GameManager.gm) // if the gameManager is available, tell it to reset the game
GameManager.gm.ResetGame();
else // otherwise, just reload the current level
Application.LoadLevel(Application.loadedLevelName);
}
}
public void CollectCoin(int amount) {
PlaySound(coinSFX);
if (GameManager.gm) // add the points through the game manager, if it is available
GameManager.gm.AddPoints(amount);
}
// public function on victory over the level
public void Victory() {
PlaySound(victorySFX);
FreezeMotion ();
_animator.SetTrigger("Victory");
if (GameManager.gm) // do the game manager level compete stuff, if it is available
GameManager.gm.LevelCompete();
}
// public function to respawn the player at the appropriate location
public void Respawn(Vector3 spawnloc) {
UnFreezeMotion();
playerHealth = 1;
_transform.parent = null;
_transform.position = spawnloc;
_animator.SetTrigger("Respawn");
}
public void EnemyBounce ()
{
DoJump ();
}
}
I suggest making a empty game object prefab that holds the particle system. Then when you want to use the particle system, just instantiate the object. That is the easiest way i've found to go about it, and its rather versatile. Another way is, you could make the empty game object a child of your player, and then activate it when you want to use it. The second way isn't as ideal, but will get the job done too.
For the ParticleSystem component that you have added to the gameObject, set the enabled property to false by unchecking the enabled checkbox on the component.
Then in the KillPlayer function
particleRed.enabled = true;
Additionally you can ensure it is disabled in the Awake function by setting it to false.

Verifying there is no collision with a certain object after clicking it

I'm having trouble creating a way to check if the Player is NOT colliding with a certain 'waypoint' if I click that waypoint. I've set up 7 waypoints which the player will want to be able to move to.
Now I'm trying to write a piece of script that checks that AFTER the waypoint is clicked (onMouseDown) if there's a collision with the player. Because if that's the case it won't calculate the position to move to.
public class WayPointPositioner : MonoBehaviour {
private Vector3 wayPointPosition;
public GameObject playercheck;
//Check if object is clicked
void OnMouseDown ()
{
Debug.Log ("Object Clicked " + GameObject.name);
// Check if collision occurs with playercheck
OnCollisionEnter(playercheck != Collision)
{
// If its the player, then return a new position for the player to move to for walking
// Else debug that its not so
if (playercheck.gameObject.CompareTag("Player"))
{
Debug.Log ("Object not colliding and retrieving position");
wayPointPosition = new Vector3 (GameObject.X, GameObject.Y, 10);
wayPointPosition = Camera.main.ScreenToWorldPoint(wayPointPosition);
}
else
{
Debug.Log ("Object is colliding, no movement needed");
}
}
}
}
Now I've already figured out that OnCollisionEnter will not work. Because it requires the void-statement before it for it to function. However I have no clue how else I am able to do this.
I would just compare the position of the player and the way point. If equal then the player is there otherwise move to the way point. Hope I understand the problem right.
Managed to fix it. Was just being an idiot.
Key is to use both functionalities, SEPERATELY. So I divided the tasks of checking for Mousedown and checking if the place is occupied by creating a seperate variable to ask true of false from to check it all.
public class WayPointPositioner : MonoBehaviour {
private Vector3 wayPointPosition;
private bool checkPlayerWaypointCollision;
void Start()
{
wayPointPosition = transform.position;
}
void OnTriggerStay2D (Collider2D other)
{
if (other.gameObject.name == "Player")
{
checkPlayerWaypointCollision = true;
}
else
{
checkPlayerWaypointCollision = false;
}
}
//Check if object is clicked
void OnMouseDown ()
{
// If its the player, then return a new position for the player to move to for walking
// Else debug that its not so
if (checkPlayerWaypointCollision == false)
{
Debug.Log ("Object not colliding and retrieving position");
transform.position = new Vector3 (transform.position.x, transform.position.y, 10);
wayPointPosition = Camera.main.ScreenToWorldPoint(wayPointPosition);
}
else
{
Debug.Log ("Object is colliding, no movement needed");
}
}
}

Categories