How to start an animation of some object while destroying other object? - c#

I want to start the animation when destroying another game object. How is this possible? To have this in mind I was trying to use setActive() in the else statement where the object is destroyed. However, nothing happens, only it does activate when I put it inside if(target). So I'm trying something like this:
public void Update()
{
anim = GetComponent<Animator>();
anim.SetBool("isWalking", isWalking);
if (target)
{
bar.fillAmount = (float)health / baseHealth;
float distance = Vector3.Distance(transform.position, target.transform.position);
if (distance >= attackRange && isAttacking)
{
isWalking = true;
agent.SetDestination(target.transform.position);
}
if (distance - 1 <= attackRange)
{
isWalking = false;
agent.ResetPath();
}
if (distance - 1.5 <= attackRange && Random.value < Time.deltaTime && Time.time > lastAttackedAt + cooldown && agent.remainingDistance <= agent.stoppingDistance)
{
isAttacking = true;
isWalking = false;
Attack();
lastAttackedAt = Time.time;
anim.SetTrigger("isAttacking");
}
}
else
{
OnDeath();
spawnPortal.SetActive(true);
}
}
The object is well destroyed but still the animation does not appear. It remains hidden (unchecked)...

Related

Endless Runner: When I swipe up to jump, the player jumps but then moves left or right on the single up swipe

I am making an endless runner mobile game. The PC controls work perfectly and the Touch/Swipe controls for Left and Right work too. The problem is when I swipe up to jump, the player jumps but then also either moves left or right (seemingly at random). For the life of me I cannot figure it out. This is my first C# project so my code/game is Frankenstein of tutorials and google searches. I found out about the rigidbody component a little too late but I don't want to start using it now if I don't have to... Please help, I am at a total loss. I would also like to apologise in advance if my code is extremely messy and incoherent, I have tried my best. Here is my Player movement script:
PC Controls
public class PlayerMove : MonoBehaviour
{
public float moveSpeed = 8;
public float leftRightSpeed = 7;
static public bool canMove = false;
public KeyCode moveL;
public KeyCode moveR;
public float horizVel = 0;
public int laneNum = 2;
public string controlLocked = "n";
private float speedUpTime;
private float waitTime = 0.45f;
private Vector3 startTouchPosition;
private Vector3 endTouchPosition;
public GroundCheck groundCheck;
public float jumpForce=7;
public float gravity = -9.81f;
public float gravityScale = 3;
public float jumpCoolDown = 0.5f;
private float lastJumpTime = 0;
float velocity;
// Start is called before the first frame update
void Start()
{
speedUpTime = Time.time;
}
// Update is called once per frame
void Update()
{
if (Time.time - speedUpTime >= 10f)
{
moveSpeed += 1;
leftRightSpeed +=1;
waitTime -= 0.05f;
speedUpTime = Time.time;
}
transform.position += new Vector3(horizVel, 0, moveSpeed) * Time.deltaTime;
if((Input.GetKeyDown(moveL)) && (laneNum>1)&& (controlLocked == "n"))
{
horizVel = -leftRightSpeed;
StartCoroutine(stopSlide());
laneNum -= 1;
controlLocked = "y";
}
if((Input.GetKeyDown(moveR)) && (laneNum<3)&& (controlLocked == "n"))
{
horizVel = leftRightSpeed;
StartCoroutine(stopSlide());
laneNum += 1;
controlLocked = "y";
}
velocity += gravity * gravityScale * Time.deltaTime;
if (groundCheck.isGrounded && velocity < 0)
{
velocity = 0;
lastJumpTime = 0;
}
if (Input.GetKeyDown(KeyCode.Space) && (Time.time - lastJumpTime) > jumpCoolDown)
{
lastJumpTime = Time.time;
velocity = jumpForce;
}
transform.Translate(new Vector3(0, velocity, 0) * Time.deltaTime);
Touch Controls
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
{
startTouchPosition = Input.GetTouch(0).position;
}
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Ended)
{
endTouchPosition = Input.GetTouch(0).position;
// Check for horizontal swipe
if((endTouchPosition.x < startTouchPosition.x) && (laneNum>1)&& (controlLocked == "n"))
{
horizVel = -leftRightSpeed;
StartCoroutine(stopSlide());
laneNum -= 1;
controlLocked = "y";
}
if((endTouchPosition.x > startTouchPosition.x) && (laneNum < 3) && (controlLocked == "n"))
{
horizVel = leftRightSpeed;
StartCoroutine(stopSlide());
laneNum += 1;
controlLocked = "y";
}
// Check for vertical swipe
if ((endTouchPosition.y > startTouchPosition.y) && (Time.time - lastJumpTime) > jumpCoolDown)
{
lastJumpTime = Time.time;
velocity = jumpForce;
}
}
}
IEnumerator stopSlide()
{
yield return new WaitForSeconds(waitTime);
horizVel = 0;
controlLocked = "n";
}
}
I've been at it for so many hours, I don't even remember what I've tried. Either the player stops moving, Right becomes Left, Jump is Right, Left is jump, etc...
Since you said the touch-controls were the issue, this answer will be focused on your second block of code.
The reason seems to be because when a player swipes up, their finger will almost never be at the same x-position. To illustrate this, try swiping up on your screen in an exact perfect line.
Computers take things very literally. So even being off by 0.0000001 is significant enough to be counted as less/more.
So what does this mean? When you swipe up, your fingers x and y position will change - causing both if-statements to activate
A fix that wouldn’t be too time-draining would be to create a dead-zone for swipes.
To put it simply, a dead-zone is a threshold that must be passed in addition to the action.
Here is an example of a dead-zone:
if(endPosition < startPosition - 2) { <SNIPPED> }
# ^ THIS IS THE DEADZONE

2D Jumping System not working correctly - Unity 2D

I was working on my 2D game in unity and i made this system to set the character to jump, and move around, but for some reason, i can only move mid air when i was moving on the ground, but if i stand still and then jump, i can not move mid air
Further Explaination: imagine you want to pick a coin in the air, and there is an obstacle under the coin, thus you have to jump while moving forward to pick it up, my problem is that you can only move mid air, if you were moving on the floor originally, but if you jump and THEN move right or left, the system just ignores it
My code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(CapsuleCollider2D))]
public class CharacterController2D : MonoBehaviour
{
// Move player in 2D space
public float maxSpeed = 3.4f;
public float jumpHeight = 6.5f;
public float gravityScale = 1.5f;
public Camera mainCamera;
bool facingRight = true;
float moveDirection = 0;
bool isGrounded = false;
Vector3 cameraPos;
Rigidbody2D r2d;
CapsuleCollider2D mainCollider;
Transform t;
// Use this for initialization
void Start()
{
t = transform;
r2d = GetComponent<Rigidbody2D>();
mainCollider = GetComponent<CapsuleCollider2D>();
r2d.freezeRotation = true;
r2d.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
r2d.gravityScale = gravityScale;
facingRight = t.localScale.x > 0;
if (mainCamera)
{
cameraPos = mainCamera.transform.position;
}
}
// Update is called once per frame
void Update()
{
// Movement controls
if ((Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D)) && (isGrounded || Mathf.Abs(r2d.velocity.x) > 0.01f))
{
moveDirection = Input.GetKey(KeyCode.A) ? -1 : 1;
}
else
{
if (isGrounded || r2d.velocity.magnitude < 0.01f)
{
moveDirection = 0;
}
}
// Change facing direction
if (moveDirection != 0)
{
if (moveDirection > 0 && !facingRight)
{
facingRight = true;
t.localScale = new Vector3(Mathf.Abs(t.localScale.x), t.localScale.y, transform.localScale.z);
}
if (moveDirection < 0 && facingRight)
{
facingRight = false;
t.localScale = new Vector3(-Mathf.Abs(t.localScale.x), t.localScale.y, t.localScale.z);
}
}
// Jumping
if (Input.GetKeyDown(KeyCode.W) && isGrounded)
{
r2d.velocity = new Vector2(r2d.velocity.x, jumpHeight);
}
// Camera follow
if (mainCamera)
{
mainCamera.transform.position = new Vector3(t.position.x, cameraPos.y, cameraPos.z);
}
}
void FixedUpdate()
{
Bounds colliderBounds = mainCollider.bounds;
float colliderRadius = mainCollider.size.x * 0.4f * Mathf.Abs(transform.localScale.x);
Vector3 groundCheckPos = colliderBounds.min + new Vector3(colliderBounds.size.x * 1f, colliderRadius * 0.9f, 0);
// Check if player is grounded
Collider2D[] colliders = Physics2D.OverlapCircleAll(groundCheckPos, colliderRadius);
//Check if any of the overlapping colliders are not player collider, if so, set isGrounded to true
isGrounded = false;
if (colliders.Length > 0)
{
for (int i = 0; i < colliders.Length; i++)
{
if (colliders[i] != mainCollider)
{
isGrounded = true;
break;
}
}
}
// Apply movement velocity
r2d.velocity = new Vector2((moveDirection) * maxSpeed, r2d.velocity.y);
// Simple debug
Debug.DrawLine(groundCheckPos, groundCheckPos - new Vector3(0, colliderRadius, 0), isGrounded ? Color.green : Color.red);
Debug.DrawLine(groundCheckPos, groundCheckPos - new Vector3(colliderRadius, 0, 0), isGrounded ? Color.green : Color.red);
}
}```
if ((Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D)) && (isGrounded || Mathf.Abs(r2d.velocity.x) > 0.01f))
In this line you check if you are grounded isGrounded or have some horizontal velocity Mathf.Abs(r2d.velocity.x) > 0.01f.
If you have any of those you give horizontal control.
So if you are moving horizontal en then jump Mathf.Abs(r2d.velocity.x) > 0.01f is true and gives you control in the air.
But if you are standing still and the jump isGrounded is false bequase you are in the air and Mathf.Abs(r2d.velocity.x) > 0.01f is false so you cant control your jump in the air.
If you always want control in the air remove the (isGrounded || Mathf.Abs(r2d.velocity.x) > 0.01f) check

Ladder climbing function in C# script for Unity won't allow the character to come off the ladder

I created a function in Unity that is supposed to allow the character to climb. It creates two problems, first of all it somehow interacts with the general movement function. When the character starts running their animation won't stop even when the player isn't moving them. Second of all the character can climb up and down the ladder but won't get off them, even though technically the logic is constructed in such a way that they should just go back to their normal state.
I have tried turning off the climb function in the Update() function so I know the running problem is caused by it, because it works fine without it.
private void Climb()
{
RaycastHit2D ladder = Physics2D.Raycast(transform.position, Vector2.up, 5, whatIsLadder);
float hDirection = Input.GetAxisRaw("Horizontal");
float vDirection = Input.GetAxisRaw("Vertical");
if (ladder.collider != null)
{
if (vDirection > 0.1f)
{
isClimbing = true;
}
}
else
{
if (hDirection > 0.1f)
{
isClimbing = false;
}
}
if (isClimbing == true && ladder.collider != null)
{
rb.gravityScale = 0;
rb.velocity = new Vector2(rb.velocity.x, climbSpeed * vDirection);
if (Mathf.Abs(vDirection) > 0.1f)
{
anim.speed = 1f;
}
else
{
anim.speed = 0f;
}
}
else
{
rb.gravityScale = naturalGravity;
}
}
I'll also give a link to the whole PlayerController script since that might help some people:
https://github.com/Pacal2/Platformer/blob/master/Assets/Scripts/PlayerController.cs
Try resetting the velocity on the rigidbody when he stops climbing, near the end of the function:
//....
{
rb.gravityScale = naturalGravity;
}
into:
{
rb.gravityScale = naturalGravity;
rb.velocity = new Vector2(0.0f, 0.0f);
}
this code also looks suspect
if (ladder.collider != null)
{
if (vDirection > 0.1f)
{
isClimbing = true;
}
}
else
{
if (hDirection > 0.1f)
{
isClimbing = false;
}
}
change to:
if (ladder.collider != null)
{
if (vDirection > 0.1f || vDirection < -0.1f) //if allowed to climb down
{
isClimbing = true;
}
if (hDirection > 0.1f || hDirection < -0.1f) //moving left
{
isClimbing = false;
}
}
for animation speed try:
anim.speed = rb.velocity.x;

Unity 2D Jump script

So I was trying to implement double jumping in my game, which doesn't work. And now, somehow, not only can't my players double jump, they can't even jump either!
update: they can jump now, still can't double jump though.
This is my whole movement script:
using UnityEngine;
namespace Players
{
public class Actor : MonoBehaviour
{
//in order to control both players using 1 script.
public int playerIdx;
//Variables.
public float movementSpeed = 150f;
public float jumpForce = 250f;
//Ground stuff.
public LayerMask whatIsGround;
public bool grounded;
//boolean stuff.
private bool facingRight;
private bool moving;
//Needed to check if player is on the ground.
public Transform groundCheck;
//Limit player's movement speed.
public float maxMovementSpeed = 400f;
//Double jump stuff.
private bool doubleJumpReady;
//rb
private Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
doubleJumpReady = true;
rb = GetComponent<Rigidbody2D>();
facingRight = true;
}
// Update is called once per frame
void FixedUpdate()
{
SlowDown();
}
private void LateUpdate()
{
grounded = Physics2D.OverlapCircle(groundCheck.position, 0.1f, whatIsGround);
if (grounded)
doubleJumpReady = true;
}
private void SlowDown()
{
if (moving) return;
//if player is not moving, slow them down.
if (rb.velocity.x > 0.2f)
rb.AddForce(movementSpeed * Time.deltaTime * -Vector2.right);
if (rb.velocity.x < -0.2f)
rb.AddForce(movementSpeed * Time.deltaTime * Vector2.right);
}
public void Move(int dir)
{
//Flip the player.
Flip(dir);
//Moving the player.
moving = true;
float xVel = rb.velocity.x; //Get x velocity.
if ( dir > 0)
rb.AddForce(movementSpeed * Time.deltaTime * Vector2.right * dir);
else if (dir < 0)
rb.AddForce(movementSpeed * Time.deltaTime * Vector2.right * dir);
else if (dir == 0) { } //do nothing.
//Help player turn around faster.
if (xVel > 0.2f && dir < 0)
rb.AddForce(movementSpeed * 3.2f * Time.deltaTime * -Vector2.right);
if (xVel < 0.2f && dir > 0)
rb.AddForce(movementSpeed * 3.2f * Time.deltaTime * Vector2.right);
}
private void Flip(int dir)
{
if (facingRight && dir == -1 || !facingRight && dir == 1)
{
facingRight = !facingRight;
transform.Rotate(0f, 180f, 0f);
}
}
protected void Jump()
{
if (grounded)
{
rb.AddForce(Vector2.up * jumpForce);
grounded = false;
doubleJumpReady = true;
}
else if (!grounded && doubleJumpReady)
{
rb.AddForce(Vector2.up * jumpForce);
doubleJumpReady = false;
}
}
}
}
I don't know if it is because of my jump script, or my player script:
void Update()
{
if (playerIdx == 1)
{
if (Input.GetKey(KeyCode.A))
Move(-1);
if (Input.GetKey(KeyCode.D))
Move(1);
if (Input.GetKey(KeyCode.W))
Jump();
}
if (playerIdx == 2)
{
if (Input.GetKey(KeyCode.LeftArrow))
Move(-1);
if (Input.GetKey(KeyCode.RightArrow))
Move(1);
if (Input.GetKey(KeyCode.UpArrow))
Jump();
}
}
So how can I fix this?
as far as i can see you never reset the
doubleJumpReady = false;
Variable. To fix this simply change the jump code to:
protected void Jump()
{
if (grounded)
{
rb.AddForce(Vector2.up * jumpForce);
grounded = false;
doubleJumpReady = true;
}
else if (!grounded && doubleJumpReady)
{
rb.AddForce(Vector2.up * jumpForce);
doubleJumpReady = false;
}
}
Hope it works ;).
EDIT:
grounded is set by overlapping spheres. Therefore no need to set it here.
Use this code and press your jump btn 2 times and see if the Debug.Log message shows up. Also, your player ID (idx is not needed.) As far as i can see your script is attached two to different objects. Therefore their variables are not shared anyways.
protected void Jump()
{
if (grounded)
{
rb.AddForce(Vector2.up * jumpForce);
doubleJumpReady = true;
}
else if (!grounded && doubleJumpReady)
{
rb.AddForce(Vector2.up * jumpForce);
doubleJumpReady = false;
Debug.Log("I am double jumping");
}
}
And the final problem is, you do not execute one of your jumps you execute both at once.
THis happens due to your execution.
Input.GetKey(KeyCode.UP)
instead use:
Input.GetKeyDown(KeyCode.Up);
GetKeyDown returns true when the button is pressed.
GetKey returns true WHILE the button is pressed.
Hope it works now ;)
I would implement it with a counter, you can set the number of jumps you want.
The code would be like this:
jumpCount = 0;
protected void Jump()
{
if(!grounded && jumpCount < 2)
{
jumpCount++;
rb.AddForce(Vector2.up * jumpForce);
}
if(grounded)
jumpCount = 0;
}
Going off the assumption that you can now perform the normal jump again after reading the comments. I think the reason you can't 'double jump' is that when you call the Jump() method, you don't just call it once, you call it twice, so what happens is the player jumps and then immediately double jumps and so you don't actually notice that the double jump has occurred. You could make it so that your doubleJumpReady boolean is only true after a set amount of time after you have jumped initially using some sort of co-routine or something I implemented for a sort of double jump mechanic once was that the user could press the jump button again to double jump only when the player had reached the maximum height of the initial jump or after.

how can i use a for loop so my character can double jump?

I am trying to code a platforming game as right now all my character model can do is either jump infinitely or doesn't jump at all. I want to use a for loop so my character can jump one when grounded and once more when he is in the air but I cant figure out how to make it stop after double jumping once and resetting when the character hits the floor again. please help!!
public class SimplePlatformController : MonoBehaviour
{
[HideInInspector]
public bool facingRight = true;
[HideInInspector]
public bool jump = false;
public float moveForce = 365f;
public float maxSpeed = 5f;
public float jumpForce = 1000f;
public Transform groundCheck;
private bool grounded = false;
private Animator anim;
private Rigidbody2D rb2d;
// Use this for initialization
void Awake()
{
anim = GetComponent<Animator>();
rb2d = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
for (int i = 0; i <= 1; i++)
{
grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));
if (Input.GetButtonDown("Jump") && grounded)
{
i = 0;
jump = true;
}
if (Input.GetButtonDown("Jump") && !grounded)
{
jump = true;
i = i + 1;
}
}
}
void FixedUpdate()
{
float h = Input.GetAxis("Horizontal");
anim.SetFloat("Speed", Mathf.Abs(h));
if (h * rb2d.velocity.x < maxSpeed)
rb2d.AddForce(Vector2.right * h * moveForce);
if (Mathf.Abs(rb2d.velocity.x) > maxSpeed)
rb2d.velocity = new Vector2(Mathf.Sign(rb2d.velocity.x) * maxSpeed, rb2d.velocity.y);
if (h > 0 && !facingRight)
Flip();
else if (h < 0 && facingRight)
Flip();
if (jump)
{
anim.SetTrigger("Jump");
rb2d.AddForce(new Vector2(0f, jumpForce));
jump = false;
}
}
void Flip()
{
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
A for loop is inappropriate for this, because you only want to advance the counter if you jump. and you need to leave the loop when it's time for the frame to end. You could in theory make it happen with a while loop in a Coroutine but that is unnecessarily complicated.
A better alternative is to just keep a counter as a class field and update it appropriately, according to the double jump state.
Also, since the if statement is being reached on every frame, you have to check if you have any more air jumps before you double jump.
If you want to be able to double-jump after you simply walk off a platform, you'll want to set the jump counter to 0 anytime grounded is set to be true.
Combining all of these suggestions might look like this:
public class SimplePlatformController : MonoBehaviour
{
// ...
private int airJumpCount = 0; // Add this counter
// ...
// Update is called once per frame
void Update()
{
grounded = Physics2D.Linecast(
transform.position, groundCheck.position,
1 << LayerMask.NameToLayer("Ground"));
if (grounded) airJumpCount = 0; // reset the counter when grounded
if (Input.GetButtonDown("Jump") && grounded)
{
jump = true;
}
// Only enter the air jump block if we still have more air jumps
if ( Input.GetButtonDown("Jump") && !grounded && airJumpCount < 1)
{
airJumpCount++;
jump = true;
}
}
// ...
}

Categories