animator image
so im new in unity and im trynig to make my first game. so i made a code for flipping the player and it worked good, but when i added animations to the player it just stopped working! here is everything in my code relatable to the topic:
public bool facingLeft = false;
void flip()
{
facingLeft = !facingLeft;
facingRight = !facingRight;
Vector3 Scaler = transform.localScale;
Scaler.x *= -1;
transform.localScale = Scaler;
}
void FixedUpdate()
{
if (facingLeft == true && moveInput < 0)
{
flip();
}
if (facingRight == true && moveInput > 0)
{
flip();
}
}
pls help, thx
This is because you do define your animator but dont use it in the flip, you could or make it so that in the animation that the player moves and rotates accordingly to your stuff. like set the animation position itself.
Related
I have added the jumping animation to my player. When my player jumps, the animation plays. However when the player lands, the jump animation becomes stuck. When I check the animator tab, the jump animation is just being played on a loop.
This is the Code for the Jumping stuff - Animation/actual movement:
void Update()
{
horizontal = Input.GetAxisRaw("Horizontal");
animator.SetFloat("Speed", Mathf.Abs(horizontal));
if (Input.GetButtonDown("Jump") && IsGrounded())
{
rb.velocity = new Vector2(rb.velocity.x, jumpingPower);
jump = true;
animator.SetBool("isJumping", true);
}
if (Input.GetButtonUp("Jump") && rb.velocity.y > 0f)
{
rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y * 0.5f);
}
if (Input.GetButtonUp("Jump") && IsGrounded())
{
animator.SetBool("isJumping", false);
animator.SetBool("isGrounded", true);
jump = false;
}
Flip();
}
This should check whether the player is grounded or not:
private bool IsGrounded()
{
return Physics2D.OverlapCircle(groundCheck.position, 0.2f, groundLayer);
}
This statement does not what you think it does
if (Input.GetButtonUp("Jump") && IsGrounded())
GetButtonUp returns true the first frame the button is released (see docs).
But it will return false again if the button has been released. This is not made that clear in the docs. Or to put it in other words: GetButtonUp returns true in that frame where the button has been released but in the frame before it was still pressed.
You could just detect the moment the player lands to switch animations:
if (jump && IsGrounded()) { // player just landed
animator.SetBool("isJumping", false);
animator.SetBool("isGrounded", true);
jump = false;
}
I am trying to prevent the player to double jump, for that I am using Raycast to check if the player is in the layer Floor. My solution works sometimes, but sometimes it allows the player to double jump.
This is my code:
void Movement()
{
float movement = Input.GetAxis("Horizontal");
Vector3 playerVelocity = new Vector3(movement*speed, myRigidbody.velocity.y, speed);
myRigidbody.velocity = playerVelocity;
if (Input.GetKeyDown("space") && isGrounded)
{
Vector3 jumpVelocity = new Vector3(0f, jumpSpeed, 0f);
myRigidbody.velocity += jumpVelocity;
isGrounded = false;
Debug.Log("floor:"+isGrounded);
anim.SetInteger("AnimationPar", 3);
myAudioSource.Stop();
AudioSource.PlayClipAtPoint(jumpSound,transform.position, volumeSoundEffects);
}
else if (isGrounded && !myAudioSource.isPlaying && !levelFinished)
{
myAudioSource.Play();
}
if (!isGrounded)
{
IsGrounded();
}
}
void IsGrounded()
{
RaycastHit hit;
int mask = 1 << LayerMask.NameToLayer("Floor");
if (Physics.Raycast(transform.position, Vector3.down, out hit, 0.01f, mask))
{
//Debug.Log("Is touching floor");
isGrounded = true;
Debug.Log("floot:" + isGrounded);
anim.SetInteger("AnimationPar", 1);
if (!myAudioSource.isPlaying)
{
myAudioSource.Play();
}
}
}
The Movement method is called in Update. I think that maybe the IsGrounded method is called to fast and the player is still to close to the floor.
An easy way to prevent double jump is using a counter instead of raycast, it really makes everything easy. put a counter in this portion of the code:
if (Input.GetKeyDown("space") && isGrounded && counter <2)
{
Vector3 jumpVelocity = new Vector3(0f, jumpSpeed, 0f);
counter++;
Im unable to debug your code at this time, but another way you could do it is using OnCollisionEnter and OnCollisionExit
You can detect all things your players collides with, if one of them is the Floor then its likely hes grounded. But it would be possible to touch the floor on the side of the player while falling, to avoid this use the grounded method agian. You said it does work but sometimes fails. So try something like:
void OnCollisionEnter (Collision col)
{
if(col.gameobject.layer == LayerMask.NameToLayer("Floor") && IsGrounded())
{
isGrounded = true;
}
}
void OnCollisionExit (Collision col)
{
if(col.gameobject.layer == LayerMask.NameToLayer("Floor") && !IsGrounded())
{
isGrounded = false;
}
}
Thats untested code so im not 100% sure if it will work. The Exit may not work since IsGrounded may still be able to raycast to the ground. But if you handle your layers/collision in your levels right then you can remove the IsGrounded calls entirely.
This isnt the perfect solution by far but it might work.
I have a small script that causes an object to bounce back and forth. It is a bird for an upwards scrolling endless runner. So it represents its flight path. This script moves it from one end to the other and when it reaches the end it flips the 2D sprite and travels in the opposite direction. It works most of the time. But the problem is that sometimes the image flips twice so now it looks like its flying backwards until it does it again. Each time it does it it appears to be random.
public class Fly : MonoBehaviour {
private bool dirRight = false;
public float speed;
public bool facingRight = false;
void Start (){
speed = Random.Range (15.0f, 22.0f);
}
void Update () {
if(transform.position.x >= 25.0f) {
dirRight = false;
Flip();
}
if(transform.position.x <= -25.0f) {
dirRight = true;
Flip();
}
if (dirRight)
transform.Translate (Vector2.right * speed * Time.deltaTime);
else
transform.Translate (-Vector2.right * speed * Time.deltaTime);
}
void Flip()
{
// Switch the way the player is labelled as facing
facingRight = !facingRight;
// Multiply the player's x local scale by -1
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
I modified the if statements and use my bools as well as the position as such:
if(transform.position.x >= 25.0f && dirRight == true) {
dirRight = false;
Flip();
}
if(transform.position.x <= -25.0f && dirRight == false) {
dirRight = true;
Flip();
}
I am running it now and waiting to see if it works.
you are calling Flip() method based on position. and position is updated per frame. So it takes time to Lerp from >=25 to <25 so in every frame when position is >= 25 or <= -25 it calls to Flip(). So you need to add another check for calling Flip(). May be facingright == true will work.
Please keep in mind that I'm new to Unity. I have 2 script that I want to "combline" but when I try then it don't Work.
I have a Script (Name : RobotController). This script controls the movement of the player. Up/Jump, Down, Left and Right. (This Works with Keyboard keys only atm)
This script Works just fine but now I want to add the feature of touch keys for phone. With this I mean that if a person click on the "up-Arrow" the player shall jump.
The Up-Arrow is an object.
This is were I get my problem. I have created the Up-Arrow with a collider and a script.
Up-Arrow script:
public class NewJumpScript : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnMouseOver()
{
if ((Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began) || (Input.GetMouseButtonDown(0)))
{
Debug.Log("test");
}
}
}
Here is the RobotController script´, with ground check and so on.
public class RobotController : MonoBehaviour {
//This will be our maximum speed as we will always be multiplying by 1
public float maxSpeed = 2f;
public GameObject player;
public GameObject sprite;
//a boolean value to represent whether we are facing left or not
bool facingLeft = true;
//a value to represent our Animator
Animator anim;
//to check ground and to have a jumpforce we can change in the editor
bool grounded = true;
public Transform groundCheck;
public float groundRadius = 1f;
public LayerMask whatIsGround;
public float jumpForce = 300f;
private bool isOnGround = false;
void OnCollisionEnter2D(Collision2D collision) {
isOnGround = true;
}
void OnCollisionExit2D(Collision2D collision) {
anim.SetBool ("Ground", grounded);
anim.SetFloat ("vSpeed", rigidbody2D.velocity.y);
isOnGround = false;
}
// Use this for initialization
void Start () {
player = GameObject.Find("player");
//set anim to our animator
anim = GetComponent <Animator>();
}
void FixedUpdate () {
//set our vSpeed
//set our grounded bool
grounded = Physics2D.OverlapCircle (groundCheck.position, groundRadius, whatIsGround);
//set ground in our Animator to match grounded
anim.SetBool ("Ground", grounded);
float move = Input.GetAxis ("Horizontal");//Gives us of one if we are moving via the arrow keys
//move our Players rigidbody
rigidbody2D.velocity = new Vector3 (move * maxSpeed, rigidbody2D.velocity.y);
//set our speed
anim.SetFloat ("Speed",Mathf.Abs (move));
//if we are moving left but not facing left flip, and vice versa
if (move > 0 && !facingLeft) {
Flip ();
} else if (move < 0 && facingLeft) {
Flip ();
}
}
void Update(){
if ((isOnGround == true && Input.GetKeyDown (KeyCode.UpArrow)) || (isOnGround == true && Input.GetKeyDown (KeyCode.Space))) {
anim.SetBool("Ground",false);
rigidbody2D.AddForce (new Vector2 (0, jumpForce));
}
if (isOnGround == true && Input.GetKeyDown (KeyCode.DownArrow))
{
gameObject.transform.localScale = new Vector3(transform.localScale.x, 0.2f, 0.2f);
}
if (isOnGround == true && Input.GetKeyUp (KeyCode.DownArrow))
{
gameObject.transform.localScale = new Vector3(transform.localScale.x, 0.3f, 0.3f);
}
}
//flip if needed
void Flip(){
facingLeft = !facingLeft;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
What needs to happen is that when The "Up-arrow" in the game is clicked then The person shall jump on the same tearms as in the RobotController script.
I hope you understand my question.
Thanks for your time and help.
I posted this same answer to both of the questions, because they are so similar. You can easily modify the code to your needs.
This is only one way to do it. There are probably many more, but this is the best I have encountered so far.
On the QUI button, script like this is needed:
private Mover playerMover;
void Start()
{
playerMover = GameObject.Find("Character").GetComponent<Mover>();
}
void OnMouseOver()
{
if (Input.GetMouseButton(0))
{
Debug.Log("pressed");
playerMover.MoveButtonPressed();
}
}
Notice that find is only done ones in start function, because it is computationally heavy.
And on the Character gameobject, script component like this is needed:
using UnityEngine;
using System.Collections;
public class Mover : MonoBehaviour {
public void MoveButtonPressed()
{
lastPressedTime = Time.timeSinceLevelLoad;
}
public double moveTime = 0.1;
private double lastPressedTime = 0.0;
void Update()
{
if(lastPressedTime + moveTime > Time.timeSinceLevelLoad)
{
// Character is moving
rigidbody.velocity = new Vector3(1.0f, 0.0f, 0.0f);
}
else
{
rigidbody.velocity = new Vector3(0.0f, 0.0f, 0.0f);
}
}
}
Hi there fellow Overflowers!
I have recently dived into C# in Unity, because I believe that it has more functionality than UnityScript, and I come from a C++ background. Referencing some code from a 2D script in the Sample Assets, I have tried to create my own. The code is below:
using UnityEngine;
public class PlayerControl : MonoBehaviour {
//Variables
[HideInInspector]
public bool facingForward = true; //for Flip() Function
bool isGround = true; //for Grounded() Function
public float maxSpeed = 5.0f; //Terminal sideways velocity
public float HorizonAxis; //Checks for a/d movement
public float jumpFloat = 1000.0f; //Modular, use Unity Editor
public float moveFloat = 400.0f; // " "
void Start() {
//transform.position(0,0,0);
}
void Flip() {
facingForward = !facingForward; //switches boolean
Vector3 theScale = transform.localScale; //assigns vector to localscale of Player
theScale.x *= -1; //if x = 1, position becomes -1 and thus flips
transform.localScale = theScale; //reassigns the localscale to update theScale
}
bool Grounded() {
if (transform.position.y > 1) { //if position of gameObject is greater that 1, not grounded
isGround = false;
} else {
isGround = true;
}
return isGround; //function returns true or false for isGround
}
void Update() {
HorizonAxis = /*UnityEngine.*/Input.GetAxis ("Horizontal"); //assigns HorizonAxis to a/d movement from UnityEngine.Input
if (HorizonAxis * rigidbody2D.velocity.x > maxSpeed) { // if Input a/d by current x velocity of gameObject is greater than maxSpeed
rigidbody2D.velocity = new Vector2 (Mathf.Sign (rigidbody2D.velocity.x) * maxSpeed, rigidbody2D.velocity.y); //1 or -1 times the max speed, depending on direction
}
else if (HorizonAxis * rigidbody2D.velocity.x < maxSpeed) { //if Input a/d is less than terminal velocity
rigidbody2D.AddForce(Vector2.right * HorizonAxis * moveFloat); //add force to the right equivilant to Input by scalar moveFloat
}
if (Input.GetButtonDown ("Jump")) { //If Space
if(isGround) { //and isGround returns true
rigidbody2D.AddForce(new Vector2(0.0f, jumpFloat)); //add upwards force to bottom of rigidbody2D
isGround = false; //Resets isGround value
}
}
if (HorizonAxis > 0 && !facingForward) {//if UnityEngine.Input is to the right and facing left
Flip (); //execute
}
else if (HorizonAxis < 0 && facingForward) { //else
Flip (); //execute
}
}
}
Unfortunately, the code just doesn't work. I get no compile errors, but any Input does not effect the current position of the character. Should I be using transform.Translate to change the position, or stick with AddForce to a Vector2 until the character hits a maxSpeed?
Thanks heaps :)
I (kinda) fixed the jerky jumping issue, basically you look for the input in the Update() function which switches a Bool in FixedUpdate()
void Update () {
if (Input.GetKeyDown (KeyCode.Space) && playerGrounded) {
playerJumped = true;
}
}
Then in FixedUpdate() I looked for this Bool and did my AddForce
void FixedUpdate () {
if (playerJumped) {
playerJumped = false;
rigidbody2D.AddForce (new Vector2 (0, jumpForce),ForceMode2D.Impulse);
playerGrounded = false;
}
}
Setting playerJumped to false makes sure it doesn't run several times and the player can't jump again because I also set the grounded to false. grounded gets set back to true when the player collides with things tagged "ground".
I'm still new to Unity and C# overall so I can't guarantee this is the best (or even a good) way. Hope I could help somehow though ;)