I'm trying to solve an issue in Unity 2d game creation.
So, my issue is when the subject is idle, the 2d player object should be idle and when I move the character, it must animate like walking.
But in my case, the walking animation is not working but the character is moving.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
[SerializeField]
private float jumpmovement = 11f;
[SerializeField]
private float movement = 10f;
private float movementx;
[SerializeField]
private Rigidbody2D mybody;
private Animator anim;
[SerializeField]
private string Walk_Ani = "Player is walking";
private SpriteRenderer sr;
private void Awake()
{
mybody = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
sr = GetComponent<SpriteRenderer>();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Playerkeymove();
animateplayer1();
}
void Playerkeymove()
{
movementx = Input.GetAxisRaw("Horizontal");
// Debug.Log(movementx);
transform.position += new Vector3(movementx, 0f, 0f) * movement * Time.deltaTime;
// Debug.Log(transform.position);
}
void animateplayer1()
{
// anim.SetBool(Walk_Ani , true);
// we are going to the right side
if (movementx > 0)
{
anim.SetBool(Walk_Ani, true);
sr.flipX = false;
}
else if (movementx < 0)
{
// we are going to the left side
anim.SetBool(Walk_Ani, true);
sr.flipX = true;
}
else
{
anim.SetBool(Walk_Ani, false);
}
}
}
I can't understand, why I have a warning issue with boolean part where I guess that's where my animation takes part.
You are trying to set a boolean parameter in the Animator that doesn't exists. The code is correct. Check what name you choose for the bool parameter to active correctly the animation.
Related
I assigned the spacebar as jump key in my game but it doesn't seem to work 100% of the time. Also there is a slight delay when the character jumps and button is pressed. The jump key is like a gamble in the game. Here's the script that i attached to the character.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MonsterScript : MonoBehaviour
{
[SerializeField] private float walkStrength = 10f;
[SerializeField] private float jumpStrength = 11f;
private float movementX;
private bool onCloud = true;
private string CLOUD_TAG = "Cloud";
private string WALK_ANIMATION = "walk";
private Rigidbody2D mybody;
private SpriteRenderer sr;
private Animator anim;
private void Awake()
{
mybody = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
sr = GetComponent<SpriteRenderer>();
}
// Update is called once per frame
void Update()
{
monsterWalk();
}
private void FixedUpdate()
{
monsterJump();
}
void monsterWalk()
{
movementX = Input.GetAxisRaw("Horizontal");
transform.position += walkStrength * Time.deltaTime * new Vector3(movementX, 0f, 0f);
}
void monsterJump()
{
if (Input.GetKeyUp(KeyCode.Space) && onCloud == true)
{
mybody.AddForce(new Vector3(0, jumpStrength,0), ForceMode2D.Impulse);
onCloud = false;
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag(CLOUD_TAG))
{
onCloud = true;
Debug.Log("Landed!");
}
}
}
I tried changing the collider of my player thinking it might have got stuck with other collider. Again I trying changing the key thinking it was a problem of my keyboard but wasn't.
In general: get single event input in Update!
If you check GetKeyUp within FixedUpdate - which is not called every frame - you might miss an Input.
So you should do e.g.
private bool isJump;
private void Update ()
{
...
if(Input.GetKeyUp(KeyCode.Space) && onCloud)
{
isJump = true;
}
}
private void FixedUpdate ()
{
...
if(isJump)
{
mybody.AddForce(new Vector3(0, jumpStrength,0), ForceMode2D.Impulse);
onCloud = false;
isJump = false;
}
}
However, further
transform.position += walkStrength * Time.deltaTime * new Vector3(movementX, 0f, 0f);
is a problem as well when using a Rigidbody/Rigidbody2D since you completely overwrite the position here => the physics has no effect whatsoever so your adding force is good for nothing.
You also want to shift this into FixedUpdate and only go through the myBody here as well
private void FixedUpdate ()
{
var movementX = Input.GetAxisRaw("Horizontal") * walkStrength * Time.deltaTime;
// Keep Y velocity untouched and only overwrite X
var vel = mybody.velocity;
vel.x = movementX;
mybody.velocity = vel:
}
as soon as physics is involved you do not want to get or set anything through the Transform component.
https://www.youtube.com/watch?v=gB1F9G0JXOo&t=11865s
I'm watching this tutorial and I did everything the same as the guy in the video did until the "Player Jumping" part, when his character can jump whenever he presses the space button, but for me it doesn't work the same way. Can somebody help or tell me what is the problem?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
[SerializeField]
private float moveForce = 10f;
[SerializeField]
private float jumpForce = 11f;
private float movementX;
private Rigidbody2D myBody;
private SpriteRenderer sr;
private Animator anim;
private string WALK_ANIMATION = "Walk";
private void Awake()
{
myBody = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
sr = GetComponent<SpriteRenderer>();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
PlayerMoveKeyboard();
AnimatePlayer();
}
private void FixedUpdate()
{
PlayerJump();
}
void PlayerMoveKeyboard()
{
movementX = Input.GetAxisRaw("Horizontal");
transform.position += new Vector3(movementX, 0f, 0f) * moveForce * Time.deltaTime;
}
void AnimatePlayer()
{
// we are going to the right side
if (movementX > 0)
{
anim.SetBool(WALK_ANIMATION, true);
sr.flipX = false;
}
// we are going to the left side
else if (movementX < 0)
{
anim.SetBool(WALK_ANIMATION, true);
sr.flipX = true;
}
else
{
anim.SetBool(WALK_ANIMATION, false);
}
}
void PlayerJump()
{
if (Input.GetButtonDown("Jump"))
{
myBody.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
}
}
} // class
Try moving your jump function from the FixedUpdate into the normal Update Function.
That should fix it.
Update gets called every frame and thus captures every input while FixedUpdate gets called in a fixed offset to update the physics logic of the engine. Now when you are looking for keyboard input, you want to always do that in Update, never in FixedUpdate because you'll miss input that was given to the player between the fixed update frames.
But since you want to do physics related changes only in FixedUpdate, you want to split the code between the two methods.
bool shouldJump = false;
void Update()
{
if (Input.GetButtonDown("Jump"))
shouldJump = true;
}
void FixedUpdate()
{
if (shouldJump)
{
myBody.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
shouldJump = false;
}
}
I have looked into the code in the video and he does the jump-logic in FixedUpdate. It seems weird to me and this is definitely bad practice. But one of the comments below addresses your issue as well and proposes a similar solution.
Im throwing a bomb using physics made by code. For some reason it doesnt detect collision unless my physics stop applying force to the object. in order to bypass it I cancelled the applied force and applied gravity to it on collision enter and put the movement of the bomb to LateUpdate so it will trigger after the OnCollisionEnter but the bomb collides only most of the time with the floor (mesh collision, the floor made with ProBuilder) and not all of the time. the bomb collision detection is set to continuous
Will appreciate all the help, Thanks!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BombBehavior : MonoBehaviour
{
[SerializeField] float ExplosionForce = 300;
[SerializeField] float ExplosionRadius;
[SerializeField] float LaunchForceX;
[SerializeField] float LaunchForceY;
[SerializeField] float Delay;
float countdown;
Rigidbody rigidbodyy;
float gravity = 1;
Player player;
bool HasExploded = false;
// Start is called before the first frame update
void Start()
{
rigidbodyy = GetComponent<Rigidbody>();
player = Player.p;
GetLaunchForceX();
countdown = Delay;
}
private void GetLaunchForceX()
{
if (transform.position.x > player.transform.position.x)
{
LaunchForceX *= 1;
}
else if (transform.position.x < player.transform.position.x)
{
LaunchForceX *= -1;
}
}
private void LateUpdate()
{
ThrowBomb();
}
private void Update()
{
countdown -= Time.deltaTime;
if (countdown <= 0 && !HasExploded)
{
ExplodeNearEnemy();
}
}
private void ThrowBomb()
{
if (rigidbodyy.useGravity == false)
{
Vector3 ThrowDirection = new Vector3(LaunchForceX, LaunchForceY, 0);
LaunchForceY -= gravity;
ThrowDirection.y = LaunchForceY;
transform.Translate(ThrowDirection * Time.deltaTime);
}
}
private void ExplodeNearEnemy()
{
Collider[] colliders = Physics.OverlapSphere(transform.position, ExplosionRadius);
foreach (Collider collider in colliders)
{
if (collider.gameObject.CompareTag("Enemy"))
{
Rigidbody enemyRB = collider.GetComponent<Rigidbody>();
if (enemyRB != null)
{
enemyRB.useGravity = true;
enemyRB.AddExplosionForce(ExplosionForce, transform.position, ExplosionRadius);
Destroy(enemyRB.gameObject,1);
}
}
}
//Destroy(gameObject);
}
private void OnCollisionEnter(Collision collision)
{
LaunchForceY = 0;
LaunchForceX = 0;
gravity = 0;
rigidbodyy.useGravity = true;
}
}
I don't exactly understand the problem but it looks like you want to make a Bomb/Granate so why dont you just write a function and use AddForce()?
void Thow(Vector3 direction, float strength)
{
rigidbodyy.AddForce(direction * strength, ForceMode.Impulse);
}
something like this should help as you only need to get the throwing direction and apply a strength then Unity will handle the rest
Or maybe if your bomb doesn't collide with the ground give the ground a rigidbody and set kinematic to true
Use the MovePosition() to move a rigid body if you want colliders etc to work. Teleporting a rigid body by altering the transform directly messes up the physics.
I'm trying to make the value in the text not to flickering when the player is moving but not sure ho to do it.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerSpeedDistanceController : MonoBehaviour
{
public GameObject target;
public GameObject speedArea;
public float speed;
public Animator animator;
public Text movementSpeedUiText;
public Text distanceFormTargetUiText;
public Text playerDirectionUiText;
private float distance;
private Rigidbody rigidbody;
private Vector3 lastPosition;
private bool isMoving;
// Start is called before the first frame update
void Start()
{
lastPosition = transform.position;
isMoving = false;
rigidbody = GetComponent<Rigidbody>();
movementSpeedUiText.text = animator.GetFloat("Forward").ToString();
distanceFormTargetUiText.text = Vector3.Distance(transform.position, target.transform.position).ToString();
playerDirectionUiText.text = transform.forward.ToString();
}
// Update is called once per frame
void Update()
{
if (isMoving == false)
{
movementSpeedUiText.text = "0";
}
else
{
movementSpeedUiText.text = animator.GetFloat("Forward").ToString();
}
distanceFormTargetUiText.text = Vector3.Distance(transform.position, target.transform.position).ToString();
playerDirectionUiText.text = transform.forward.ToString();
if (transform.position != lastPosition)
isMoving = true;
else
isMoving = false;
lastPosition = transform.position;
}
}
It's flickering on this line when the player is moving :
movementSpeedUiText.text = animator.GetFloat("Forward").ToString();
It didn't flicker before but since I added the movement check in the Update it's start flickering.
What is flickering is the value in the text.
I tried to change the Update to LateUpdate but it didn't fix the flickering only when changed it to FixedUpdate then it's working but is it a good idea to put it all in FixedUpdate ? And I see now that sometimes the value in the text is minus negative why and what should I do ?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerSpeedDistanceController : MonoBehaviour
{
public GameObject target;
public GameObject speedArea;
public float speed;
public Animator animator;
public Text movementSpeedUiText;
public Text distanceFormTargetUiText;
public Text playerDirectionUiText;
private float distance;
private Rigidbody rigidbody;
private Vector3 lastPosition;
private bool isMoving;
// Start is called before the first frame update
void Start()
{
lastPosition = transform.position;
isMoving = false;
rigidbody = GetComponent<Rigidbody>();
movementSpeedUiText.text = animator.GetFloat("Forward").ToString();
distanceFormTargetUiText.text = Vector3.Distance(transform.position, target.transform.position).ToString();
playerDirectionUiText.text = transform.forward.ToString();
}
// Update is called once per frame
void FixedUpdate()
{
if (isMoving == false)
{
movementSpeedUiText.text = "0";
}
else
{
movementSpeedUiText.text = animator.GetFloat("Forward").ToString("F3");
}
distanceFormTargetUiText.text = Vector3.Distance(transform.position, target.transform.position).ToString();
playerDirectionUiText.text = transform.forward.ToString();
if (transform.position != lastPosition)
isMoving = true;
else
isMoving = false;
lastPosition = transform.position;
}
}
You are using a Rigidbody to move your object. The Physics system works together with the FixedUpdate which is executed in (as the name suggests) fixed time intervals - by default every 0.02 seconds.
So what happens if you put your code in Update might look somewhat like
u u u u u u u u
f f f f f
where u stands for Update call and f stands for FixedUpdate call.
So since the Physics are applied a bit desync to Update if hard check the values of transform.position it might just happen that your object is not yet moved or stoped by the Physics system.
So yes, either put your stuff in FixedUpdate - nothing speaks against it.
Or instead of transform.position rather use rigidbody.position
Rigidbody.position allows you to get and set the position of a Rigidbody using the physics engine.
which is the correct position of the object in the physics engine, also between FixedUpdate calls.
Or actually there is a way better method for getting the current movement of a Rigidbody which doesn't require storing and comparing any previous frame values:
Rigidbody.velocity
The velocity vector of the rigidbody. It represents the rate of change of Rigidbody position.
So you can shrink down your code to
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerSpeedDistanceController : MonoBehaviour
{
public GameObject target;
public GameObject speedArea;
public float speed;
public Text movementSpeedUiText;
public Text distanceFormTargetUiText;
public Text playerDirectionUiText;
private float distance;
private Rigidbody rigidbody;
// Start is called before the first frame update
void Start()
{
rigidbody = GetComponent<Rigidbody>();
UpdateDisplay();
}
// Update is called once per frame
void FixedUpdate()
{
UpdateDisplay();
}
private UpdateDisplay()
{
movementSpeedUiText.text = rigidbody.velocity.magnitude.ToString("0.###");
distanceFormTargetUiText.text = Vector3.Distance(rigidbody.position, target.transform.position).ToString();
playerDirectionUiText.text = transform.forward.ToString();
}
}
I'm a beginner at Unity with a problem for which I've not been able to find an answer on any of the boards. Creating a very basic Unity C# script, I have the following lines of code in my Awake() function:
Assert.IsNotNull(sfxJump);
Assert.IsNotNull(sfxDeath);
Assert.IsNotNull(sfxCoin);
The third assertion "
Assert.IsNotNull(sfxCoin) throws as null, even though the coin AudioClip is set in the Inspector:
Inspector script values:
However -- and this is the part that has me baffled -- for some reason sfxCoin is not null when invoked in the same script from an OnCollisionEnter() routine
So it appears Unity does register the object with the code -- eventually -- but the assertions fail with the initial Awake(), Start(), and Update() methods.
And this only is happening with sfxCoin. sfxJump and sfxDeath do not have this issue.
Any help would be appreciated
Entire script is below:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;
public class Player : MonoBehaviour
{
[SerializeField] private float jumpForce = 100f;
[SerializeField] private float forwardMomentum = 5f;
[SerializeField] private AudioClip sfxJump;
[SerializeField] private AudioClip sfxDeath;
[SerializeField] private AudioClip sfxCoin;
private Animator anim;
private Rigidbody Rigidbody;
private bool jump = false;
private AudioSource audioSource;
private void Awake()
{
Assert.IsNotNull(sfxJump);
Assert.IsNotNull(sfxDeath);
Assert.IsNotNull(sfxCoin);
}
// Start is called before the first frame update
void Start()
{
anim = GetComponent<Animator>();
Rigidbody = GetComponent<Rigidbody>();
audioSource = GetComponent<AudioSource>();
}
// Update is called once per frame
void Update()
{
if (!GameManager.instance.GameOver() && GameManager.instance.GameStarted())
{
if (Input.GetMouseButton(0))
{
GameManager.instance.PlayerStartedGame();
anim.Play("Jump");
audioSource.PlayOneShot(sfxJump);
Rigidbody.useGravity = true;
jump = true;
}
}
}
private void FixedUpdate()
{
if (jump)
{
jump = false;
Rigidbody.velocity = new Vector2(0, 0);
Rigidbody.AddForce(new Vector2(forwardMomentum, jumpForce), ForceMode.Impulse);
}
}
private void OnCollisionEnter(Collision collision)
{
switch (collision.gameObject.tag)
{
case "obstacle":
Rigidbody.AddForce(new Vector2(-50, 20), ForceMode.Impulse);
Rigidbody.detectCollisions = false;
audioSource.PlayOneShot(sfxDeath);
GameManager.instance.PlayerCollided();
break;
case "coin":
audioSource.PlayOneShot(sfxCoin);
GameManager.instance.Score(1);
print("GOT COIN");
break;
}
}
}
sorry, I found out what the problem was.
There was a second instance of a game object that was also using the same script that did not have sfxCoin set. It was hidden under a node in the hierarchy so I didn't see it.
Like I said, I'm a beginner at this.