Don't know what I'm am doing wrong here, I am trying to trigger an animation in unity
Edit: The problem is not that the enemy is destroyed before the animation plays, as the enemy doesn't even get destroyed when
player.cs
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Enemy")
{
Blue blue = collision.gameObject.GetComponent<Blue>();
if (action == State.jump || action == State.fall)
{
blue.JumpedOn();
blue.Death();
jumpVelocity = multiplier * jumpVelocity;
rb.velocity = Vector2.up * jumpVelocity;
}
}
}
enemy.cs
public void JumpedOn(){
action = State.death;
anim.SetBool("Death", true);
}
public void Death() {
Destroy(this.gameObject);
}
have the condition set in the animator window too, if death = true play animation
see here
when I remove the
blue.JumpedOn();
the other lines will run correctly
blue.Death();
jumpVelocity = multiplier * jumpVelocity;
rb.velocity = Vector2.up * jumpVelocity;
You need to put a delay between JumpedOn() and Death() because you are calling them in the same frame, the object gets destroyed before the animation has a chance to play. A good way to do this would be coroutines, which are very valuable to use for delaying execution of code.
private IEnumerator coroutine;
IEnumerator WaitAndDestroy(GameObject _callingObject, float _waitTime)
{
yield return new WaitForSeconds(_waitTime);
_callingObject.Destroy();
}
public void Death() {
coroutine = WaitAndDestroy(gameObject, 1.5f);
StartCoroutine(coroutine);
}
I think you should try adding some delay between blue.JumpedOn(); and blue.Death();.
Related
I have been having some problems with animating my 2D player to simply play a short animation when the left arrow key is pressed and the same with the right arrow key, after the the keys are pressed I want it to go back to the idle animation. I have 3 bool parameters, Isleft, Isright, Isidle. I have been struggling with this for a few days now and was wondering if anyone knows how to actually make this work.
I have been trying everything by trial and error changing the code and changing the conditions in the animator window
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Movement : MonoBehaviour
{
public float speed = 6.0f;
public GameObject character;
private Animator anim;
private Scene scene;
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Enemy")
{
SceneManager.LoadScene(0);
}
else
{
}
}
/*void OnCollisionEnter2D(Collision2D collision)
{
switch (collision.gameObject.tag)
{
case "Enemy":
Destroy(gameObject);
break;
default:
//nothing
break;
}
}*/
void Start()
{
anim = GetComponent<Animator>();
scene = SceneManager.GetActiveScene();
}
void Update()
{
if (Input.anyKey)
{
transform.Translate(Vector3.forward * Time.deltaTime * speed);
}
// Move Right
if (Input.GetKey(KeyCode.RightArrow) || (Input.GetKey(KeyCode.D)))
{
transform.position += Vector3.right * speed * Time.deltaTime;
anim.SetBool("Isright", true);
}
//Move Left
if (Input.GetKey(KeyCode.LeftArrow) || (Input.GetKey(KeyCode.A)))
{
transform.position += Vector3.left * speed * Time.deltaTime;
anim.SetBool("Isleft", true);
}
else
{
anim.SetBool("Isidle", true);
}
}
}
You don't set booleans to false and this last "else" block refers to LeftArrow/A. If you are not holding either of them, Isidle is true.
I'm new to the Unity world (2D) and I've run into some problems.
I have a script in which i want to jump. When i jump, the jump animation is super fast. You can only see it in the animator.
I have two other animations (Idle, Run) that work without any problems.
Can you please help me? :(
public class Player : MonoBehaviour
{
private Rigidbody2D rigid;
[SerializeField]
private float jumpForce = 5.0f;
private bool resetJump;
[SerializeField]
private float speed = 5.0f;
private PlayerAnimation playerAnim;
private SpriteRenderer playerSprite;
// Start is called before the first frame update
void Start()
{
...
}
// Update is called once per frame
void Update()
{
Movement();
}
void Movement()
{
float move = Input.GetAxisRaw("Horizontal");
Flip(move);
if (IsGrounded())
{
playerAnim.Jump(false);
}
if (Input.GetKeyDown(KeyCode.Space) && IsGrounded() == true)
{
rigid.velocity = new Vector2(rigid.velocity.x, jumpForce);
StartCoroutine(ResetJumpNeededRoutine());
playerAnim.Jump(true);
}
rigid.velocity = new Vector2(move * speed, rigid.velocity.y);
playerAnim.Move(move);
}
void Flip(float move)
{
...
}
bool IsGrounded()
{
RaycastHit2D hitInfo = Physics2D.Raycast(transform.position, Vector2.down, 0.3f, 1 << 8);
if (hitInfo.collider != null)
{
if (resetJump == false)
{
return true;
}
}
return false;
}
IEnumerator ResetJumpNeededRoutine()
{
yield return new WaitForSeconds(0.1f);
resetJump = false;
}
}
The problem is in ur code just after space is pressed the resetjump is getting false and isGrounded() is returning true and hence jump anim is getting false. So what i insist is to set trigger instead of setting playerAnim.jump use playerAnim.SetTrigger("Jump").
Study about animation trigger we use trigger to play animations like shoot and jump as these animation are true and then at next instant false.
So, I am trying to create a soccer game from scratch... all I have done until now, is setting up the ball. This is how I want it to work: When the player collides with the ball, the ball jumps forward a bit. If you start running the ball will be pushed further away.
Now, here is my script for the ball (I am using the standard FPSController as character):
using UnityEngine;
using System.Collections;
public class BallController : MonoBehaviour {
private Rigidbody rb;
public GameObject character;
public float moveSpeed = 1000;
public float shootSpeed = 2000;
bool isTurnedUp = false;
bool isTurnedDown = false;
bool done = false;
// Use this for initialization
void Start () {
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void FixedUpdate () {
//Debug.Log(isTurnedUp + ", " + isTurnedDown);
switch (character.GetComponent<UnityStandardAssets.Characters.FirstPerson.FirstPersonController>().m_IsWalking)
{
case true:
if (isTurnedUp == false)
{
moveSpeed = moveSpeed / 1.4f;
isTurnedUp = true;
isTurnedDown = false;
}
break;
case false:
if (isTurnedDown == false)
{
moveSpeed = moveSpeed * 1.4f;
isTurnedDown = true;
isTurnedUp = false;
}
break;
}
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (Vector3.Distance(gameObject.transform.position, character.transform.position) <= 5)
{
float distance = Vector3.Distance(gameObject.transform.position, character.transform.position);
}
}
}
void OnCollisionEnter(Collision collision) {
FixedUpdate();
if (done == false) {
rb.AddForce(Vector3.forward * moveSpeed, ForceMode.Impulse);
done = true;
}
else {
done = false;
}
}
//other
void OnDrawGizmosSelected()
{
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(transform.position, 2);
}
}
My problem is that the ball doesn't behave how I want it... it feels like it's about luck if the ball will jump forward when I touch it. Can someone tell me what I did wrong?
Inside of OnCollisionEnter you need to ensure the ball can only be kicked by the player. You can check whether or not the player has collided with the ball by checking the name or tag of the collision. The following example uses the name and assumes your player GameObject is named "Player".
Remove the done flag since this will only allow the player to kick the ball every other time they collide, and remove the FixedUpdate() call since FixedUpdate() is already called automatically every physics calculation.
Finally, if you want to kick the ball away from the player, then you need to calculate the direction away from the collision point instead of using Vector3.forward as seen below.
void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.name == "Player")
{
Vector3 direction = (collision.transform.position - transform.position).normalized;
rb.AddForce(-direction * moveSpeed, ForceMode.Impulse);
}
}
I have an object in my game that is like a power object: when my player enters the power it should activate a panel that indicates that the power was grabbed, and past 3 seconds that panel should disappear. At the moment my panel appears when I hit the power, but it doesn't disappear. I am using a Coroutine like this:
using UnityEngine;
using System.Collections;
public class shrink : MonoBehaviour {
public float value = 0.1f; //1 by default in inspector
private bool colided = false;
private float speed;
Manager gameManager;
public GameObject panel;
// Update is called once per frame
void Start(){
speed = 3.4f;
gameManager = GameObject.Find ("GameController").GetComponent<Manager> ();
}
void OnTriggerEnter(Collider c)
{
if (c.gameObject.tag == "Player") {
colided = true;
gameManager.powerUp1 = true;
StartCoroutine(menuOp());
}
}
//This method is executed every frame
void Update(){
if (colided) {
Vector3 temp = transform.localScale;
//We change the values for this saved variable (not actual transform scale)
temp.x -= value * Time.time;
temp.y -= value * Time.time;
if (temp.x > 0) {
speed += 0.02f;
transform.Rotate (0f, 0f, Time.deltaTime * 90 * speed);
transform.localScale = temp;
} else {
Object.Destroy (this.gameObject);
}
}
}
IEnumerator menuOp(){
panel.SetActive (true);
yield return new WaitForSeconds (3f);
panel.SetActive (false);
}
}
Ps: what is inside the update is independent from what i need to do, so i think it doesn't interfer with my needs.
I think you might be destroying the GameObject before the WaitForSeconds(3f) has ended, which will prevent panel.SetActive(false) from executing.
In your Update-method's "else statement to if (temp.x > 0)" you're destroying the GameObject that tries to show/hide the panel.
If you absolutely need to Destroy this gameobject at that time you should break out your IEnumerator to another script and call it from this (shrink.cs) script.
Destroying the object before 3 seconds might be the issue. You can check by putting two logs:
1- After "Object.Destroy" line
2- After "WaitForSeconds"
maybe you should check if your gameobject(shrink's) is unactive or destroyed.
coroutine does not work with unactive gameobject.
Right now I'm not getting much Out of this. Depending on what I do different i either end up with an infinite loop, or poor jumping ability. I used a timer to tick my jumped bool but I was getting a double like jump ability and my ground detection wasn't good enough. Can you See why I can't jump, or jump well?
using UnityEngine;
using System.Collections;
public class player : MonoBehaviour
{
public float speed = 0.05f;
public float jumpVelocity = 0.05f;
public bool onGround = true;
public bool jumped = false;
// Use this for initialization
void Start () { }
// Update is called once per frame
void Update ()
{
//test if player is on the ground
if (onGround) { jumped = false; }
// USER CONTROLS HERE.
if (Input.GetKeyDown(KeyCode.Space) && onGround == true)
{
jumped = true;
while(jumped)
{
this.rigidbody2D.AddForce(new Vector2(0, jumpVelocity));
if (onGround) { jumped = false; }
}
}
else if (Input.GetKey(KeyCode.RightArrow))
{
this.transform.position += Vector3.right * speed * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.LeftArrow))
{
this.transform.position += Vector3.left * speed * Time.deltaTime;
}
}
void OnCollisionEnter2D(Collision2D col)
{
if(col.gameObject.tag == "floor") { onGround = true; }
}
void OnCollisionStay2D(Collision2D col)
{
if(col.gameObject.tag == "floor") { onGround = true; }
}
}
Your problem stems from a misunderstanding how the Update method and physics work. If you do this in the update method, it will create an endless loop:
while(jumped)
{
this.rigidbody2D.AddForce(new Vector2(0, jumpVelocity));
if(onGround)
{
jumped = false;
}
}
The thing is that you tell the physics body to add a force. But you keep doing so over and over again. The physics simulation only takes place after the Update method returns, so whatever "onGround" is it will never become true because the forces aren't being applied until after the Update method.
Instead you have to make this check over and over again every time the Update method runs until onGround is true.