I'm trying to make my enemy freeze when it gets in contact with an ice projectile. Everything works no errors except the animator doesn't play the animations and the script doesn't get enabled / disabled.
I've tried script = GetComponent(); and anim = gameObject.GetComponent(); too for that section. And for the set active ive tried script.enabled script.setactive ect ect. None of it works. I think this might have to do with the get component but IDK. These are on instantiated prefabs btw.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyHealth : MonoBehaviour
{
public float health;
public float freezeTime;
public Animator anim;
public Enemy script;
// Start is called before the first frame update
IEnumerator Wait(){
yield return new WaitForSeconds (freezeTime);
Debug.Log("waiting over");
}
void Start()
{
anim = gameObject.GetComponent<Animator>();
script = gameObject.GetComponent<Enemy>();
}
// Update is called once per frame
void Update()
{
if(health <= 0){
Dead();
}
}
void OnTriggerEnter2D(Collider2D other){
if(other.CompareTag("Harmful")){
Destroy(other.gameObject);
TakeDamage();
}
if(other.CompareTag("Freezing")){
anim.SetBool("IsFrozen", true);
Destroy(other.gameObject);
gameObject.GetComponent<Enemy>().enabled = false;
TakeDamage();
Debug.Log("waiting started");
StartCoroutine(Wait());
anim.SetBool("IsFrozen", false);
gameObject.GetComponent<Enemy>().enabled = true;
}
}
void TakeDamage(){
health -= 1f;
}
void Dead(){
Destroy(gameObject);
}
}
The problem was not in fact the animator or the scripts being set to false but it was actually because I had started a wait function but it started the wait function and immediately ran the code that was supposed to go after the wait function.
TLDR; waited but the code ran anyway.
If you want the completed working code here it is. The spacing is a little weird because of stackoverflow btw:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyHealth : MonoBehaviour
{
public float health;
public float freezeTime;
public Animator anim;
public Enemy script;
public Rigidbody2D rb;
public bool WaitOver;
// Start is called before the first frame update
IEnumerator Wait(){
yield return new WaitForSeconds (freezeTime);
WaitOver = true;
Debug.Log("waiting over");
}
void Start()
{
anim = gameObject.GetComponent<Animator>();
script = gameObject.GetComponent<Enemy>();
rb = gameObject.GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
if(health <= 0){
Dead();
}
if (WaitOver == true){
anim.SetBool("IsFrozen", false);
gameObject.GetComponent<Enemy>().enabled = true;
rb.isKinematic = false;
}
}
void OnTriggerEnter2D(Collider2D other){
if(other.CompareTag("Harmful")){
Destroy(other.gameObject);
TakeDamage();
}
if(other.CompareTag("Freezing")){
WaitOver = false;
anim.SetBool("IsFrozen", true);
rb.isKinematic = true;
Destroy(other.gameObject);
GetComponent<Enemy>().enabled = false;
TakeDamage();
Debug.Log("waiting started");
StartCoroutine(Wait());
}
}
void TakeDamage(){
health -= 1f;
}
void Dead(){
Destroy(gameObject);
}
}
Related
So . I work at a 2d game in unity and I have some problems with some mechanics and i really need some help from you guys. All I want to do is to make my character hand to stop and grab a object. When I press E the animation of the hand start and have a collider for each frame, in case that the hand collide with a closer object, the animation to stop at that frame. I have a week since I try to figure it out. If you want to help me we can do it on discord. I will put the codes here, maybe the reason that I can't to what I want to do is very clear and I dont see it.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class showHide : MonoBehaviour
{
[SerializeField]
GameObject hand;
private Animator freeze;
public bool touch = false;
private bool ok = true;
// Start is called before the first frame update
void Start()
{
freeze = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.E) && ok == true)
{
freeze.Play("Follower");
StartCoroutine(show());
}
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "box")
{
StartCoroutine(colliderShow());
}
}
private IEnumerator show()
{
ok = false;
hand.SetActive(true);
yield return new WaitForSeconds(4f);
hand.SetActive(false);
ok = true;
}
private IEnumerator colliderShow()
{
touch = true;
print(touch);
yield return new WaitForSeconds(4f);
touch = false;
print(touch);
}
private void FreezeAniamtion()
{
freeze.speed = 0f;
StartCoroutine(waitTime());
}
private IEnumerator waitTime()
{
yield return new WaitForSeconds(0f);
freeze.speed = 1f;
}
}
This is the code that activate and deactivate my hand object , including the animation .
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class facingScript : MonoBehaviour
{
private SpriteRenderer render;
private Camera mainCam;
private Vector3 mousePos;
private Animator aniHand;
public bool atinge;
void Start()
{
mainCam = Camera.main;
render = GetComponent<SpriteRenderer>();
aniHand = GetComponent<Animator>();
gameObject.SetActive(false);
}
// Update is called once per frame
void Update()
{
mousePos = Input.mousePosition;
mousePos = mainCam.ScreenToWorldPoint(
new Vector3(mousePos.x, mousePos.y, mainCam.transform.position.z - transform.position.z)
);
Vector3 rotation = mousePos - transform.position;
if (rotation.x > 0)
render.flipY = true;
else
render.flipY = false;
if (atinge == false)
aniHand.speed = 1f;
Debug.Log(aniHand.speed);
}
// Collision with objects
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "box")
{
atinge = true;
aniHand.speed = 0f;
StartCoroutine(freezingTime());
}
}
private IEnumerator freezingTime()
{
yield return new WaitForSeconds(4f);
atinge = false;
}
// No collision with any object
private void FreezeAnimation()
{
aniHand.speed = 0f;
StartCoroutine(waitTime());
}
private IEnumerator waitTime()
{
yield return new WaitForSeconds(0f);
aniHand.speed = 1f;
}
}
This is the hand component script . When the hand don't collide with anything the object is deactivated . The FreezeAnimation() is a event at the last frame. I tryed to do a collider animation for the showHide component that will be exact with the hand animation collider for each frame to check if the hand collide in the showHide script and if it collide to have a 4 seconds of waiting with the hand at that position.
I really tryed my best but I really can't figure it out.
I have a problem in unity , the player mouvement is going good until I add an animation the player stop moving even if I press the keyboard keys,when I remove the animator compenent the player move normaly without problems !
I tried separate the animation script from the movement script and still theame problem , I don't think that the problem is comming from the code
playerAnimation code :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class playerAnim : MonoBehaviour
{
Animator anim;
Rigidbody2D rb;
void Start()
{
rb = gameObject.GetComponent<Rigidbody2D>();
anim = gameObject.GetComponent<Animator>();
}
void FixedUpdate()
{
if (rb.velocity.x == 0)
anim.SetBool("isRunning", false);
else
anim.SetBool("isRunning", true);
if (rb.velocity.y > 0)
anim.SetBool("isJumping", true);
else
anim.SetBool("isJumping", false);
}
}
playerMovement script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class playerControl : MonoBehaviour
{
Rigidbody2D rb;
private float horizontal;
public float runSpeed;
public float jumpPower;
public bool inTheGround;
private SpriteRenderer sp;
Animator anim;
// Start is called before the first frame update
void Start()
{
rb = gameObject.GetComponent<Rigidbody2D>();
sp = gameObject.GetComponent<SpriteRenderer>();
anim = gameObject.GetComponent<Animator>();
}
private void Update()
{
horizontal = Input.GetAxisRaw("Horizontal");
}
private void FixedUpdate()
{
rb.velocity = new Vector2(horizontal * runSpeed,
rb.velocity.y);
if (Input.GetButton("Jump")&& inTheGround)
{
rb.velocity = new Vector2(rb.velocity.x,jumpPower);
}
flipping();
Debug.Log(rb.velocity.x);
}
private void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.CompareTag("ground"))
inTheGround = true;
}
private void OnCollisionExit2D(Collision2D other)
{
if
(other.gameObject.CompareTag("ground")&&rb.velocity.y>0.1)
inTheGround = false;
}
void flipping()
{
if (Input.GetKey(KeyCode.RightArrow))
sp.flipX = false;
if (Input.GetKey(KeyCode.LeftArrow))
sp.flipX = true;
}
}
Check if Apply Root Motion on Animator Component is set to false. This setting can overwrite your changes of the object's position over time. if not - can you please provide more information, perfectly a screenshot of your player components, and Animator Controller.
Hey i am making a zombie game and i want everytime the zombie colides with my player it should deal damage every 2 seconds as long as they are colliding it should continue. while not colliding it should stop. what i did is this code bellow and the problem with it is that when i collide with the zombie it does damage once and stops i need to collide with it again for it to deal damage can anyone help so the zombie deals damage as long as they are colliding and the damage should be dealt every 2 seconds, thanks for the help :)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerHealth : MonoBehaviour
{
public float Health = 100f;
public bool gameOver;
private Animator playerAnim;
float timeColliding;
// Start is called before the first frame update
private void Start()
{
playerAnim = GetComponent<Animator>();
}
private void Update()
{
if (Health <= 0)
{
playerAnim.SetBool("PlayerDeath", true);
gameOver = true;
}
}
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Enemy")
{
Debug.Log("Enemy started colliding with player.");
this.Health -= 10;
}
}
}
I'm not good at unity, but i think something like this will work. Place all code inside while loop in my code to function in your code called to detect collision. And place isEven outside that function. You can test my code in c# compiler. For example if you replace //reduce health here with Console.WriteLine("reduced"); this code will print reduced every 2 second
public class Program
{
public static void Main()
{
bool isEven = false;
while(true){
var timeSpan = DateTime.Now;
if(timeSpan.Second %2 == 0){
if(isEven == false){
//reduce health here
}
isEven = true;
}
else{
isEven = false;
}
}
}
}
In your code it will look like this:
public class PlayerHealth : MonoBehaviour
{
bool isEven = false;
public float Health = 100f;
public bool gameOver;
private Animator playerAnim;
float timeColliding;
// Start is called before the first frame update
private void Start()
{
playerAnim = GetComponent<Animator>();
}
private void Update()
{
if (Health <= 0)
{
playerAnim.SetBool("PlayerDeath", true);
gameOver = true;
}
}
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Enemy")
{
Debug.Log("Enemy started colliding with player.");
var timeSpan = DateTime.Now;
if(timeSpan.Second %2 == 0){
if(isEven == false){
//reduce health here
this.Health -= 10;
}
isEven = true;
}
else{
isEven = false;
}
}
}
}
I get the null reference exception error when trying to change the boolean to right (or left in that regard). My prefab should spawn at FirepointL.
My script does recognise the prefeb as it does not return a Null for finding the prefab (tested this).
I made sure my boolean was set to Public and i had dropped all the GameObjects to their designated places in the Inspector.
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");
bullet = GameObject.FindGameObjectWithTag("Button");
Movement(horizontal);
Flip(horizontal);
if (Input.GetKey("w"))
{
if (ground)
{
GetComponent<Rigidbody2D>().velocity = new Vector2(GetComponent<Rigidbody2D>().velocity.x, jump);
}
}
// this is the part that returns the error
if (facingRight == true)
{
bullet.GetComponent<weapon>().right = true;
}
if (facingRight == false)
{
bullet.GetComponent<weapon>().right = 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;
}
}
}
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 Transform firepointL;
public GameObject bulletPrefab;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown("space"))
{
Debug.Log("It's the space key");
Shoot();
}
}
void Shoot()
{
if (right == true)
{
Instantiate(bulletPrefab, firepointR.position, firepointR.rotation);
}
if(right == false)
{
Instantiate(bulletPrefab, firepointL.position, firepointL.rotation);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class bullet : MonoBehaviour
{
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 Update()
{
}
}
Not sure if it's the exact issue, but there's a problem in PlayerMovement class. When you retrieve bullet you assume that an object with Button tag is present.
In my opinion, you should check for it with
// this is the part that returns the error
if (bullet && facingRight == true)
{
bullet.GetComponent<weapon>().right = true;
}
if (bullet && facingRight == false)
{
bullet.GetComponent<weapon>().right = false;
}
I think there is a problem with naming conventions. You are trying to find out a bullet whose name is "Button" but when you are instantiating the gameobject, it names it to something like Button(clone).
One solution that comes in my mind:
1st step:
Make a public static variable inside PlayerMovement script.
public static PlayerMovement Instance;
private void Awake()
{
Instance = this;
}
Set its value inside the awake function so that you can call it from anywhere.
2nd step:
I modified the shoot function.
void Shoot()
{
GameObject _firePosition = right == true ? firepointR : firepointL;
PlayerMovement.Instance.bullet = Instantiate(bulletPrefab, _firePosition.position, _firePosition.rotation); // we are setting the reference on runtime whenever we spawn a new bullet.
}
3rd Step:
Remove this line from PlayerMovement script as it is not needed now.
bullet = GameObject.FindGameObjectWithTag("Button");
PS: Code will not work if you don't follow step 3. Let me know if it helps. :)
I Have created a 2d stealth game where the enemy fires on the player, only problem is that although the bullets are created and deleted fine on another script, the script itself spams the program with bullets every frame, creating the unwanted result
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HurtPlayer : MonoBehaviour
{
public float timeToShoot;
private float timeToShootCounter;
private bool shot;
private Vector3 moveDirection;
public float timeBetweenShot;
public float timeBetweenShotCounter;
public Transform firePoint;
public GameObject Bullet;
// Use this for initialization
void Start()
{
shot = false;
timeToShootCounter = timeToShoot;
}
// Update is called once per frame
void Update()
{
while (shot == true)
{
StartCoroutine(Delay());
Destroy(GameObject.Find("Bullet"));
timeBetweenShot -= Time.deltaTime;
timeToShoot -= Time.deltaTime;
}
}
IEnumerator Delay()
{
yield return new WaitForSeconds(0.5f);
}
void OnTriggerStay2D(Collider2D other)
{
if (other.gameObject.tag == "player")
{
if (shot == false)
{
if (timeToShoot >= 0f)
{
shot = true;
if (shot == true)
{
shot = false;
Instantiate(Bullet, firePoint.position, firePoint.rotation);
Delay();
if (timeBetweenShot <= 0f)
{
shot = false;
timeToShoot = timeToShootCounter;
timeBetweenShot = timeBetweenShotCounter;
}
}
}
}
}
}
}
What I want is the time betweenshot to work and for the enemy to only shoot once every one or half a second, thanks.
Is this what you are looking for?
IEnumerator ContinuousShoot()
{
// Continuously spawn bullets until this coroutine is stopped
// when the player exits the trigger.
while (true)
{
yield return new WaitForSeconds(1f); // Pause for 1 second.
Instantiate(Bullet, firePoint.position, firePoint.rotation);
}
}
void OnTriggerEnter2D(Collider2D other)
{
// Player enters trigger
if (other.gameObject.CompareTag("player"))
{
StartCoroutine(ContinuousShoot());
}
}
void OnTriggerExit2D(Collider2D other)
{
// Player exits trigger
if (other.gameObject.CompareTag("player"))
{
StopCoroutine(ContinuousShoot());
}
}