The Setup
I have a basketball player with an animator and 5 assigned animations to that animator as followed:
PlayerIdle
PlayerWalk
PlayerJump
PlayerBend
PlayerShoot
Setup_FruitHoops
Player Animation Window with Parameters
The Problem
In PlayMode, the player is able to move and jump successfully. The issue comes when the player attempts to grab the apple that is on the ground. The desired game design that I wanted was for the player to bend over and grab the apple by pressing the G key and then press G again to throw the apple towards the hoop to score a point. However, when I run it and after I first press G, the player can no longer jump, grab, or throw. The below section is the code for PlayerMovement and GrabberScript. Any advice is greatly appreciated.
PlayerMovement.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float speed = 5f;
private Rigidbody2D rb;
private Animator anim;
private bool isGrounded, jumped;
private float jumpshotPower = 6f;
public Transform groundCheck;
public LayerMask groundLayer;
private void Awake()
{
rb = GameObject.Find("Player Parent").GetComponent<Rigidbody2D>();
anim = GameObject.Find("Player Parent").GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
CheckIfGrounded();
PlayerJump();
}
private void FixedUpdate()
{
PlayerWalk();
}
void PlayerWalk()
{
float h = Input.GetAxisRaw("Horizontal");
if (h > 0)
{
//going right
anim.SetBool("isWalking", true);
rb.velocity = new Vector2(speed, rb.velocity.y);
ChangeDirection(-1);
}
else if (h < 0)
{
//going left
anim.SetBool("isWalking", true);
rb.velocity = new Vector2(-speed, rb.velocity.y);
ChangeDirection(1);
}
else
{
//standing still
anim.SetBool("isWalking", false);
rb.velocity = new Vector2(0f, rb.velocity.y);
}
}
void ChangeDirection(int d)
{
Vector3 temp = transform.localScale;
temp.x = d;
transform.localScale = temp;
}
void CheckIfGrounded()
{
isGrounded = Physics2D.Raycast(groundCheck.position, Vector2.down, 0.1f, groundLayer);
if (isGrounded)
{
if (jumped)
{
jumped = false;
anim.SetBool("isJumping", false);
}
}
}
void PlayerJump()
{
if (isGrounded)
{
if (Input.GetKey(KeyCode.UpArrow))
{
jumped = true;
rb.velocity = new Vector2(rb.velocity.x, jumpshotPower);
anim.SetBool("isJumping", true);
}
}
}
}
GrabberScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GrabberScript : MonoBehaviour
{
private bool grabbed, throwObject;
private RaycastHit2D hit;
public float distance;
public Transform holdpoint;
public float throwForce;
public LayerMask notFruitLayer;
private Animator anim;
private void Awake()
{
anim = GameObject.Find("Player Parent").GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.G))
{
if (!grabbed)
{
//grab fruit
anim.Play("PlayerBend");
Physics2D.queriesStartInColliders = false;
hit = Physics2D.Raycast(transform.position, Vector3.down * transform.localScale.x, distance);
if(hit.collider != null && hit.collider.tag == "Apple")
{
grabbed = true;
}
}
else if(!Physics2D.OverlapPoint(holdpoint.position, notFruitLayer))
{
//throw fruit
grabbed = false;
if(hit.collider.gameObject.GetComponent<Rigidbody2D>() != null)
{
PlayerShooting();
}
}
if (grabbed)
{
hit.collider.gameObject.transform.position = holdpoint.position;
}
}
}
private void OnDrawGizmos()
{
Gizmos.color = Color.green;
Gizmos.DrawLine(transform.position, transform.position + Vector3.down * transform.localScale.x * distance);
}
void PlayerShooting()
{
if (grabbed == true)
{
if (Input.GetKey(KeyCode.G))
{
throwObject = true;
hit.collider.gameObject.GetComponent<Rigidbody2D>().velocity = new Vector2(transform.localScale.x, 1) * throwForce;
anim.Play("PlayerShoot");
}
}
}
}
Related
I was following a tutorial for creating an enemy in Unity, but they didn't teach how to flip the enemy in case the Player goes to the other side of the map, oppose to where the enemy is.
So I tried to increase the raycast area, so when the Player collides with it from behind, the enemy will know that it has to flip. But something isn't working, cause it goes fine to the Player when it's facing the left side of the map, but once it flips, it totally stops working, and I can't figure it out why.
Anyone have any idea what should I do?
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Skeleton : MonoBehaviour
{
#region Public Variables
public Transform rayCast;
public LayerMask raycastMask;
public GameObject target;
public float rayCastLength;
public float attackDistance; //Mininum distance to attack
public float moveSpeed;
public float timer; // Cooldown b/w attacks
public bool inRange; //check if the player is near
#endregion
#region Private Variables
private RaycastHit2D hit;
private Animator anim;
private float distance; //Distance b/w enemy and player
public bool attackMode;
private float intTimer;
#endregion
void Awake() {
intTimer = timer;
anim = GetComponent<Animator>();
}
void Update() {
if (inRange)
{
hit = Physics2D.Raycast(rayCast.position, Vector2.left, rayCastLength, raycastMask);
}
//When the player is detected
if(hit.collider != null)
{
EnemyLogic();
}
// If it's not inside the raycast
else if(hit.collider == null)
{
inRange = false;
}
// If the player leaves the range
if (inRange == false)
{
anim.SetBool("canWalk", false);
StopAttack();
anim.SetInteger("Idle", 0);
}
}
void OnTriggerEnter2D(Collider2D col)
{
if(col.gameObject.tag == "Player")
{
target = col.gameObject;
inRange = true;
Flip();
}
}
void EnemyLogic()
{
distance = Vector2.Distance(transform.position, target.transform.position);
if(distance > attackDistance)
{
Move();
StopAttack();
}
else if(attackDistance >= distance)
{
Attack();
}
}
void Move()
{
anim.SetInteger("Idle", 1);
anim.SetBool("canWalk", true);
if (!anim.GetCurrentAnimatorStateInfo(0).IsName("attack"))
{
Vector2 targetPosition = new Vector2(target.transform.position.x, transform.position.y);
transform.position = Vector2.MoveTowards(transform.position, targetPosition, moveSpeed * Time.deltaTime);
}
}
void Attack()
{
timer = intTimer; //reset timer
attackMode = true;
anim.SetInteger("Idle", 1);
anim.SetBool("canWalk", false);
anim.SetBool("Attack", true);
}
void StopAttack()
{
attackMode = false;
anim.SetBool("Attack", false);
}
// Detects if the player is on the other side
void Flip()
{
Vector3 rotation = transform.eulerAngles;
if(target.transform.position.x < transform.position.x)
{
rotation.y = 180f;
}
else
{
rotation.y = 0f;
}
transform.eulerAngles = rotation;
}
}
You can flip the enemy using localScale. Do this:
if (Player.transform.position.x < this.transform.position.x)
{
transform.localScale = new Vector3(-1, 1, 1);
}else
{
transform.localScale = new Vector3(1, 1, 1);
}
This detects whenever the player's x position is greater or lower than the enemy and flips the whole object.
When shooting a bullet or making a bomb explode, the player doesn't move as a projectile. Instead, they just move an unusually little distance. The players move as expected - a projectile, after reassigning groundCheck to "none", but the players themselves can't be moved any more. When colliding with a bullet or is in the range of a bomb, how can I change the code so that the player can move as a projectile without assigning groundCheck to "none" ?
Code of player:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveWASDPlayer1 : MonoBehaviour
{
public float speed = 5;
public float jumpForce = 10;
private float moveInput;
private Rigidbody2D rb;
private bool facingRight = true;
private bool isGrounded;
public Transform groundCheck;
public float checkRadius = 0.5f;
public LayerMask whatIsGround;
private int extraJumps;
public int extraJumpsValue = 1;
public Sprite Player1Shoot;
public Sprite Player1idle;
public GameObject Player2;
public GameObject PistolBulletToRight, PistolBulletToLeft;
Vector2 PistolBulletPos;
public float fireRate;
public int remainingBullet = 10;
private void Start()
{
extraJumps = extraJumpsValue;
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
Physics2D.IgnoreLayerCollision(6, 7);
Shoot();
CheckJumps();
Flip();
StartCoroutine(Fire());
moveInput = Input.GetAxis("Horizontal1");
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
if (Input.GetKeyDown(KeyCode.S))
{
Physics2D.IgnoreLayerCollision(3, 6, true);
Invoke("StopCollidingIntoGround", 0.25f);
}
}
void CheckJumps()
{
isGrounded = Physics2D.OverlapCircle(groundCheck.position, checkRadius, whatIsGround);
if (isGrounded == true)
{
extraJumps = extraJumpsValue; ;
}
if (Input.GetKeyDown(KeyCode.W) && extraJumps > 0)
{
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
extraJumps--;
Physics2D.IgnoreLayerCollision(3, 6, true);
Invoke("StopCollidingIntoGround", 0.48f);
}
else if (Input.GetKeyDown(KeyCode.W) && extraJumps == 0 && isGrounded == true)
{
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
}
}
void Flip()
{
if (facingRight == false && moveInput > 0)
{
facingRight = !facingRight;
Vector3 Scaler = transform.localScale;
Scaler.x *= -1;
transform.localScale = Scaler;
}
else if (facingRight == true && moveInput < 0)
{
facingRight = !facingRight;
Vector3 Scaler = transform.localScale;
Scaler.x *= -1;
transform.localScale = Scaler;
}
}
void StopCollidingIntoGround()
{
Physics2D.IgnoreLayerCollision(3, 6, false);
}
void Shoot()
{
if (Input.GetKeyDown(KeyCode.Z))
{
this.gameObject.GetComponent<SpriteRenderer>().sprite = Player1Shoot;
}
if (Input.GetKeyUp(KeyCode.Z))
{
this.gameObject.GetComponent<SpriteRenderer>().sprite = Player1idle;
}
}
IEnumerator Fire()
{
PistolBulletPos = transform.position;
if (remainingBullet < 1)
{
yield return new WaitForSeconds(2);
remainingBullet = 10;
}
if (Input.GetKeyDown(KeyCode.Z) && remainingBullet > 0)
{
if (facingRight)
{
PistolBulletPos += new Vector2(+1f, -0.1f);
Instantiate(PistolBulletToRight, PistolBulletPos, Quaternion.identity);
remainingBullet--;
yield return new WaitForSeconds(fireRate);
}
else
{
PistolBulletPos += new Vector2(-1f, -0.1f);
Instantiate(PistolBulletToLeft, PistolBulletPos, Quaternion.identity);
remainingBullet--;
yield return new WaitForSeconds(fireRate);
}
}
}
}
Code of bomb:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bomb : MonoBehaviour
{
Collider2D[] inExplosionRadius = null;
[SerializeField] private float ExplosionForceMulti = 5;
[SerializeField] private float ExplosionRadius = 5;
private void Update()
{
if(Input.GetKeyDown(KeyCode.X))
{
Explode();
}
}
void Explode()
{
inExplosionRadius = Physics2D.OverlapCircleAll(transform.position, ExplosionRadius);
foreach(Collider2D o in inExplosionRadius)
{
Rigidbody2D o_rigidbody = o.GetComponent<Rigidbody2D>();
if (o_rigidbody != null)
{
Vector2 distanceVector = o.transform.position - transform.position;
if(distanceVector.magnitude > 0)
{
float explosionForce = ExplosionForceMulti / distanceVector.magnitude;
o_rigidbody.AddForce(distanceVector.normalized * explosionForce);
}
}
}
}
private void OnDrawGizmos()
{
Gizmos.DrawWireSphere(transform.position, ExplosionRadius);
}
}
Code of bullet:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PistolBullet : MonoBehaviour
{
public float velX = 5f;
float velY = 0f;
Rigidbody2D rb;
Collider2D[] inShootRadius = null;
[SerializeField] public float ShootForceMulti = 5;
[SerializeField] public float ShootRadius = 5;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
}
private void Update()
{
rb.velocity = new Vector2(velX, velY);
Destroy(gameObject, 3f);
Shoot();
}
public void Shoot()
{
inShootRadius = Physics2D.OverlapCircleAll(transform.position, ShootRadius);
foreach (Collider2D o in inShootRadius)
{
Rigidbody2D o_rigidbody = o.GetComponent<Rigidbody2D>();
if (o_rigidbody != null)
{
Vector2 distanceVector = o.transform.position - transform.position;
if (distanceVector.magnitude > 0)
{
float explosionForce = ShootForceMulti / distanceVector.magnitude;
o_rigidbody.AddForce(distanceVector.normalized * explosionForce);
}
}
}
}
private void OnCollisionEnter(Collision collision)
{
Destroy(gameObject);
}
}
If I understand correctly: When getting hit by a bullet or explosion the player is not flung as expected?
I would argue this is the culprit: rb.velocity = new Vector2(moveInput * speed, rb.velocity.y); as you are overriding the player velocity every frame without taking in account the current velocity, unless moveInput has that calculated into.
As to why it works when GroundCheck is unassigned, because the script stops executing due to the missing reference beforehand and the Rigidbody will only be modified from the other scripts.
I Am trying to add a swinging system to my game but whenever my player does the swinging animation it goes back to the same place how would I fix something like that? here is a video showing what it does: https://streamable.com/7jxgqx
I Use a character controller to move the player so does anyone know how to prevent the player from snapping back to the place it came from
Problem: https://streamable.com/7jxgqx
my codes: 1)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Swinging : MonoBehaviour
{
[SerializeField]Animator m_Animator;
CharacterController cc;
[SerializeField]GameObject jumpArea;
PlayerController playerController;
private void Start()
{
cc = GetComponent<CharacterController>();
playerController = GetComponent<PlayerController>();
playerController.enabled = true;
cc.enabled = true;
}
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Collider"))
{
StartCoroutine(StartSwinging());
}
}
IEnumerator StartSwinging()
{
m_Animator.SetTrigger("swing");
cc.enabled = false;
playerController.enabled = false;
yield return new WaitForSeconds(2.3f);
m_Animator.SetBool("afterSwing", true);
Destroy(jumpArea);
playerController.enabled = true;
cc.enabled = true;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
CharacterController cc;
public Transform groundCheck;
public LayerMask groundLayer;
float wallJumpVelocity;
public Animator m_Animator;
private Vector3 direction;
public float speed = 5f;
public float jumpForce = 8f;
public float gravity = -20f;
public bool canDoubleJump = true;
public bool isGrounded;
void Start()
{
cc = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update()
{
float horizontalInput = Input.GetAxis("Horizontal");
direction.x = horizontalInput * speed;
m_Animator.SetFloat("run", Mathf.Abs(horizontalInput)); // Mathf.Abs i igivea rac modulebi anu |-5| = 5
isGrounded = Physics.CheckSphere(groundCheck.position, 0.2f, groundLayer);
m_Animator.SetBool("isGrounded", isGrounded);
Jump();
if (horizontalInput != 0)
{
Quaternion flip = Quaternion.LookRotation(new Vector3(0, 0, horizontalInput));
transform.rotation = flip;
}
cc.Move(direction * Time.deltaTime);
}
void Jump()
{
// es kodi anichebs chvens motamashes axtomis funqicas
if (isGrounded)
{
canDoubleJump = true;
if (Input.GetButtonDown("Jump"))
{
direction.y = jumpForce;
}
}
else
{
if (canDoubleJump && Input.GetButtonDown("Jump"))
{
m_Animator.SetTrigger("doubleJump");
direction.y = jumpForce;
canDoubleJump = false;
}
}
direction.y += gravity * Time.deltaTime;
}
}
I Tried applying root motion too but it did not work i am using animations from mixamo.
Thanks <3
I have another issue with my animator in 2D.
Currently i have only few slopes in game, but it annoys me, because i don't know how to make animation work properly on them. This is one example:
As you can see, there is little slope. Now how my Animator looks like:
The code now looks like it:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using System;
public class PlayerMovementScript : MonoBehaviour
{
[SerializeField] float runSpeed;
[SerializeField] float jumpSpeed;
[SerializeField] float climbSpeed;
Vector2 moveInput;
Rigidbody2D playerRigidbody;
Animator playerAnimator;
CapsuleCollider2D playerCapsuleCollider;
float gravityScaleAtStart;
void Start()
{
playerRigidbody = GetComponent<Rigidbody2D>();
playerAnimator = GetComponent<Animator>();
playerCapsuleCollider = GetComponent<CapsuleCollider2D>();
gravityScaleAtStart = playerRigidbody.gravityScale;
}
void Update()
{
Run();
FlipSprite();
ClimbLadder();
Falling();
}
void OnMove(InputValue value)
{
moveInput = value.Get<Vector2>();
Debug.Log(moveInput);
}
void OnJump(InputValue value)
{
if (!playerCapsuleCollider.IsTouchingLayers(LayerMask.GetMask("Ground"))) { return; }
if (value.isPressed)
{
playerRigidbody.velocity += new Vector2(0f, jumpSpeed);
}
}
void Run()
{
Vector2 runVelocity = new Vector2(moveInput.x * runSpeed, playerRigidbody.velocity.y);
playerRigidbody.velocity = runVelocity;
bool playerHasHorizontalSpeed = Math.Abs(playerRigidbody.velocity.x) > Mathf.Epsilon;
if (playerCapsuleCollider.IsTouchingLayers(LayerMask.GetMask("Ground")))
{
playerAnimator.SetBool("isRunning", playerHasHorizontalSpeed);
} else
{
playerAnimator.SetBool("isRunning", false);
}
}
void FlipSprite()
{
bool playerHasHorizontalSpeed = Math.Abs(playerRigidbody.velocity.x) > Mathf.Epsilon;
if (playerHasHorizontalSpeed)
{
transform.localScale = new Vector2(Mathf.Sign(playerRigidbody.velocity.x), 1f);
}
}
void ClimbLadder()
{
if (!playerCapsuleCollider.IsTouchingLayers(LayerMask.GetMask("Climb"))) {
playerRigidbody.gravityScale = gravityScaleAtStart;
playerAnimator.SetBool("isClimbing", false);
playerAnimator.SetBool("isClimbingIdle", false);
return;
}
Vector2 climbVelocity = new Vector2(playerRigidbody.velocity.x, moveInput.y * climbSpeed);
playerRigidbody.velocity = climbVelocity;
playerRigidbody.gravityScale = 0;
bool playerHasVerticalSpeed = Math.Abs(playerRigidbody.velocity.y) > Mathf.Epsilon;
playerAnimator.SetBool("isClimbing", playerHasVerticalSpeed);
playerAnimator.SetBool("isClimbingIdle", !playerHasVerticalSpeed);
}
void Falling()
{
if (
playerCapsuleCollider.IsTouchingLayers(LayerMask.GetMask("Climb"))
|| playerCapsuleCollider.IsTouchingLayers(LayerMask.GetMask("Ground"))
) {
playerAnimator.SetBool("isJumping", false);
playerAnimator.SetBool("isLanding", false);
return;
}
bool playerHasVerticalSpeed = Math.Abs(playerRigidbody.velocity.y) > Mathf.Epsilon;
if (playerRigidbody.velocity.y >= 0)
{
playerAnimator.SetBool("isJumping", playerHasVerticalSpeed);
playerAnimator.SetBool("isLanding", false);
} else
{
playerAnimator.SetBool("isJumping", false);
playerAnimator.SetBool("isLanding", playerHasVerticalSpeed);
}
}
}
If my player went on slope, Animator shows my animations switch quickly between Run, Jump and Land. How to fix it to save correct jump animation?
I created a movable 2D ball character but when it stops moving the ball continues spinning for a bit without moving, how can I fix this?
Here is the existing code:
public class Controller : MonoBehaviour
{
public float TotalJumpForce;
public float TotalDropForce;
public float jumps;
public float speed;
public float jumpForce;
public float dropforce;
bool isGrounded = false;
public Transform isGroundedChecker;
public float checkGroundRadius;
public LayerMask groundLayer;
Rigidbody2D rb;
void Start()
{
stalltimer = 1000;
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
TotalJumpForce = rb.velocity.y + jumpForce;
TotalDropForce = rb.velocity.y + dropforce;
CheckIfGrounded();
Move();
Jump();
Drop();
}
void Move()
{
float x = Input.GetAxisRaw("Horizontal");
float moveBy = x * speed;
rb.velocity = new Vector2(moveBy, rb.velocity.y);
}
void Jump()
{
if (Input.GetKeyDown("w"))
{
if (jumps > 0)
rb.velocity = new Vector2(rb.velocity.x, TotalJumpForce);
jumps = jumps - 1;
}
}
void Drop()
{
if (Input.GetKeyDown("s"))
{
rb.velocity = new Vector2(rb.velocity.x, TotalDropForce);
}
}
void CheckIfGrounded()
{
Collider2D collider = Physics2D.OverlapCircle(isGroundedChecker.position, checkGroundRadius, groundLayer);
if (collider != null)
{
isGrounded = true;
jumps = 2;
stalls = 3;
}
else
{
isGrounded = false;
}
}
}
Changing angular and linear drag doesn't make a difference. Changing the gravity scale doesnt seem to make a diffrence either.
You could check for input and reset the rb.angularVelocity in case there is no input
void Move()
{
var x = Input.GetAxisRaw("Horizontal");
var moveBy = x * speed;
rb.velocity = new Vector2(moveBy, rb.velocity.y);
if(Mathf.Approximately(move, 0f))
{
rb.angularVelocity = 0;
}
}