So I have a script for my player where I have disabled diagonal move. I then created a script for his dog companion that follows him in the world and it's almost perfected except when I do a direction change from left/right to up/down or vice versa the dog will follow at a diagonal and looks really weird since there is no animations and he basically slides there. I tried to disable diagonal like how I did for the player but it doesn't work. Is there a way to go about this or would it be better to just add in a diagonal animation for just the dog?
public class Bowser : MonoBehaviour
{
public float speed;
private Transform target;
private Vector2 move;
private Animator anim;
private void Awake()
{
anim = GetComponent<Animator>();
}
// Start is called before the first frame update
void Start()
{
target = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();
}
// Update is called once per frame
void Update()
{
move.x = Input.GetAxisRaw("Horizontal");
move.y = Input.GetAxisRaw("Vertical");
if (Vector2.Distance(transform.position, target.position) > 1.5)
{
// Code attempt to get rid of diagonal movement
if (move.x != 0) move.y = 0;
if (move != Vector2.zero)
{
anim.SetFloat("moveX", move.x);
anim.SetFloat("moveY", move.y);
anim.SetBool("moving", true);
}
transform.position = Vector2.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
}
else
anim.SetBool("moving", false);
}
}
Instead of just checking for 0 you could just use the bigger value
if (Mathf.Abs(move.x) > (Mathf.Abs(move.y)) move.y = 0;
else move.x = 0;
it would be better if you just provided diagonal animations for the dog
Thanks for the advice in the end I found that it became a smoother transition to just add this
if (Mathf.Abs(move.x) > .01f)
targetPosition.y = transform.position.y;
if (Mathf.Abs(move.y) > .01f)
targetPosition.x = transform.position.x;
and then change all my target.Position to the targetPosition
Related
So i was trying 3rd character movement in unity an got stuck in here. The player animation is moving in loop but player is moving ahead of camera and than coming back, its doing it every cycle.
Let me provide char_control code and video link.
video link - https://drive.google.com/file/d/15VEIcOqy7yhQfACT4Pjxh-BZoVsrYdFS/view?usp=sharing
code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class char_control : MonoBehaviour
{
public GameObject Player;
//variable - type of variable
public bool isRunning;
public float horizontal_move;
public float vertical_move;
// Update is called once per frame
void Update()
{
if (Input.GetButton("Horizontal") || Input.GetButton("Vertical"))
{
Player.GetComponent<Animation>().Play("Running");
horizontal_move = Input.GetAxis("Horizontal") * Time.deltaTime * 100;
vertical_move = Input.GetAxis("Vertical") * Time.deltaTime * 1;
isRunning = true;
transform.Rotate(0, horizontal_move, 0);
transform.Translate(0, 0, vertical_move);
}
else
{
Player.GetComponent<Animation>().Play("Idle");
isRunning = false;
}
}
}
You should use Animator and Animator Controller for your purpose. To fix your problem you could probably disable root motion in your animation (Bake Into Pose on Root Transform Position (XZ), setting up Mask should work too) but still you will end up using Animator Controller so better do that asap
Have you checked that your "Running" animation has both "Loop Time" and "Loop Pose" checked. I know that the pose option is the one which makes my character act the way you described.
Use scripting to control character movement and movement animations:
[System.Serializable]
public class Anim//Game control animation
{
public AnimationClip idle;
public AnimationClip runForward;
public AnimationClip runBackward;
public AnimationClip runRight;
public AnimationClip runleft;
}
public class playermove : MonoBehaviour {
public float h = 0.0f;
public float v = 0.0f;
//assign the variable,
private Transform tr;
//move speed variable
public float movespeed = 10.0f;
//Rotate can use the Rotate function,
public float rotSpeed = 100.0f;
//The animation class variable to display to the inspector
public Anim anim;
//To access the variables of the following 3d model animation component objects
public Animation _animation;
// Use this for initialization
void Start () {
//Assign the Tr component to the initial part of the script
tr = GetComponent<Transform>();
// Find the anim component that is subordinate to itself and assign it to a variable.
_animation = GetComponentInChildren<Animation>();
_animation.clip = anim.idle;
_animation.Play();
}
// Update is called once per frame
void Update() {
h = Input.GetAxis("Horizontal");
v = Input.GetAxis("Vertical");
Debug.Log("H=" + h.ToString());
Debug.Log("V="+ v.ToString());
//Calculate the moving direction vector of left, right, front and rear.
Vector3 moveDir = (Vector3.forward * v) + (Vector3.right * h);
//translate (movement direction *time.deltatime*movespeed, space.self)
tr.Translate(moveDir.normalized *Time.deltaTime*movespeed , Space.Self);
//vector3.up axis as the benchmark, rotate at rotspeed speed
tr.Rotate(Vector3.up * Time.deltaTime * rotSpeed * Input.GetAxis("Mouse X"));
if (v >= 0.1f)
{
//forward animation
_animation.CrossFade(anim.runForward.name, 0.3f);
}
else if (v <= -0.1f)
{
//back animation
_animation.CrossFade(anim.runBackward.name, 0.3f);
}
else if (h >= 0.1f)
{
//right animation
_animation.CrossFade(anim.runRight.name, 0.3f);
}
else if (h <= -0.1f)
{
//left animation
_animation.CrossFade(anim.runleft.name, 0.3f);
}
else
{
_animation.CrossFade(anim.idle.name, 0.3f);
}
//Based on the keyboard input value, execute the animation to be operated
}
}
hope it helps you.
whenever the player uses its jetpack or when there's a lot of velocity, the player stutters. I tried using interpolate and other things like that but the only outcome was even more stutter. If anyone knows what the cause for the stuttering is, please tell me and if you want to, maybe even explain your answer :)
here is what i mean by the player stuttering :
https://www.youtube.com/watch?v=k6q3vvQtwjM
here is my player code :
using UnityEngine;
using UnityEngine.SceneManagement;
public class Player : MonoBehaviour
{
//basic variables
[SerializeField]
private float speed = 5f;
[SerializeField]
private float Jumpforce = 5f;
[SerializeField]
private float JetPackForce = 5f;
[SerializeField]
public bool canUseJetpack = true;
[SerializeField]
private Rigidbody2D rb;
[SerializeField]
private Animator animator;
private bool isFacingRight = true;
//runs when game starts
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
//runs every frame
void Update()
{
//applies force thus making player to move left or right
var move = Input.GetAxis("Horizontal");
transform.position = transform.position + new Vector3(move * speed * Time.deltaTime, 0, 0);
//changes player animation state
animator.SetFloat("Speed", Mathf.Abs(move));
//flip the player if facing right or left
if (move < 0 && isFacingRight)
{
flip();
}
else if (move > 0 && !isFacingRight)
{
flip();
}
//checks if the space key is pressed and that the player velocity on the y axis is smaller than 0.001
if(Input.GetKeyDown("space") && Mathf.Abs(rb.velocity.y) < 0.001f)
{
//adds force from below the player thus making the player jump
rb.AddForce(new Vector2(0, Jumpforce), ForceMode2D.Impulse);
}
//checks for the key 'Q' to be pressed and that there is enough fuel in the jetpack
if (Input.GetKey(KeyCode.Q) && canUseJetpack == true)
{
//ads force from below the player thus making the player fly using its jetpack
rb.AddForce(Vector2.up * JetPackForce);
//decreases the fuel in the jetpack
JetpackBar.instance.UseFuel(0.1f);
//makes the player run the using jetpack animation
animator.SetBool("UsingJetpack", true);
}
else
{
//if the player isn't using the jetpack, switch to the idle animation or the run animation depending if the player is moving or not
animator.SetBool("UsingJetpack", false);
}
//checks if the player health is less than 0
if (HealthBar.instance.currentHealth <= 0)
{
//if so, restart the game
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
//checks if someting collided with the player
private void OnCollisionEnter2D(Collision2D collision)
{
//if the thing collided with the player has a tag of 'Enemy'
if (collision.gameObject.CompareTag("Enemy"))
{
//then, make the player take damage
HealthBar.instance.takeDamage(25);
}
}
//flip the player
void flip()
{
isFacingRight = !isFacingRight;
transform.Rotate(0f, 180f, 0f);
}
}
Thanks :D
First of all whenever dealing with Rigidbodies you do not want to use the Transform component to move an object. You rather want to only move it via the Rigidbody/Rigidbody2D component!
Then there is a general issue. You can either move your object hard based on the input or use the physics and forces. Both at the same time is not possible because both transform.position or the actually "correct" Rigidbody2D.MovePosition will overrule the forces so these two systems are clashing all the time.
Therefore I would rather simply overwrite the velocity directly like e.g.
void Update()
{
// Store the current velocity
var velocity = rb.velocity;
var move = Input.GetAxis("Horizontal");
// Only overwrite the X component
// We don't need Time.deltaTime since a velocity already
// moves the object over time
velocity.x = move * speed;
animator.SetFloat("Speed", Mathf.Abs(move));
if (move < 0 && isFacingRight)
{
flip();
}
else if (move > 0 && !isFacingRight)
{
flip();
}
if(Input.GetKeyDown("space") && Mathf.Abs(rb.velocity.y) < 0.001f)
{
// simply overwrite the Y velocity
// You'll have to adjust that value of course
// and might want to rename it ;)
velocity.y = Jumpforce;
}
if (Input.GetKey(KeyCode.Q) && canUseJetpack)
{
// Here we want to use Time.deltaTime since the jetpack
// shall increase the Y velocity over time
// again you'll have to adjust/rename that value
velocity.y += JetPackForce * Time.deltaTime;
// Also adjust this value!
// To be frame-rate independent you want to use Time.deltaTime here
JetpackBar.instance.UseFuel(0.1f * Time.deltaTime);
animator.SetBool("UsingJetpack", true);
}
else
{
animator.SetBool("UsingJetpack", false);
}
// After having calculated all changes in the velocity now set it again
rb.velocity = velocity;
if (HealthBar.instance.currentHealth <= 0)
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
hi there Iam trying learn how to use unity animation system i create function in my code to control animation triggers i only have two walk and attack its work good in 4 normal directions plus i create avatar to mix animation with layers and all works good from my perspective
my problem is when the character face a diagonal direction the attack animation wont trigger as you can see in the gif i attached and whats make me really wonder is when the character face a specific direction which is the up arrow + right arrow the trigger work with this diagonal direction otherwise the attack animation is never work with any other diagonal direction
i tried to create diagonal bool to control this but its not work i tried also to create double transitions on the animation its also not work
public class MovementController : MonoBehaviour
{
Vector3 _CharacterDirection;
Quaternion _CharacterRotation=Quaternion.identity;
Animator _CharacterAnim;
Rigidbody _CharacterRigidbody;
[SerializeField]
public float TurnSpeed;
bool _IsWalking, Isdiagonal;
void Start()
{
_CharacterAnim = GetComponent<Animator>();
_CharacterRigidbody = GetComponent<Rigidbody>();
}
void Update()
{
CharacterActions();
}
void FixedUpdate()
{
CharacterMovement();
}
void CharacterMovement()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
_CharacterDirection.Set(h, 0, v);
_CharacterDirection.Normalize();
bool _IsHorizontalChange = !Mathf.Approximately(h, 0f);
bool _IsVerticalChange = !Mathf.Approximately(v, 0);
_IsWalking = _IsHorizontalChange || _IsVerticalChange;
//Isdiagonal = _IsHorizontalChange && _IsVerticalChange ? true : false;
_CharacterAnim.SetBool("IsWalking", _IsWalking);
Vector3 _DesairdForward = Vector3.RotateTowards(this.transform.forward, _CharacterDirection, TurnSpeed * Time.deltaTime, 0);
_CharacterRotation = Quaternion.LookRotation(_DesairdForward);
_CharacterRigidbody.MovePosition(_CharacterRigidbody.position + _CharacterDirection * Time.deltaTime);
_CharacterRigidbody.MoveRotation(_CharacterRotation);
}
void CharacterActions()
{
if (Input.GetKeyDown(KeyCode.Space))
{
_CharacterAnim.SetTrigger("SpellCast");
}
else if(Input.GetKeyDown(KeyCode.Space) && _IsWalking)
{
_CharacterAnim.SetTrigger("SpellCast");
}
}
I'm trying to write a script for my enemy movements. Here is my code:
public class EnemiesMovement : MonoBehaviour
{
private bool isFacingRight = false;
public float speed = 10f;
private float startPoint;
private float endPoint;
public float unitMovement = 2f;
private Rigidbody2D enemy;
private Animator anim;
bool moveRight;
// Start is called before the first frame update
void Start()
{
enemy = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
startPoint = enemy.position.x;
endPoint = startPoint + unitMovement;
}
// Update is called once per frame
void Update()
{
if (enemy.position.x >= endPoint)
moveRight = false;
if (enemy.position.x <= startPoint)
moveRight = true;
if (moveRight)
{
enemy.velocity = new Vector2(-transform.localScale.x, 0) * speed;
if (!isFacingRight)
Flip();
}
if (!moveRight)
{
enemy.velocity = new Vector2(transform.localScale.x, 0) * speed;
if (isFacingRight)
Flip();
}
}
void Flip()
{
isFacingRight = !isFacingRight;
Vector3 scale = transform.localScale;
scale.x *= -1;
transform.localScale = scale;
}
}
The movement of the enemy is right, but after the enemy flips its sprites, it doesn't change the direction of its movement. Basically, it continues to the right, even though its sprite has turned left. Can someone show me how I can fix this?
My enemy spite has a positive scale facing to the left.
Velocity is affected by the scale property.
So if you change the scale negative, everything on this GameObject flips, it's not necessary to change the velocity direction.
Are you getting bewildered? You can try another method to flip the sprite.
GetComponent<SpriteRenderer>().flipX = true;
This only flips the sprite renderer, other things are working as normal in its world space.
Another suggests as Unity documented it's better to change Rigidbody's property in the FixedUpdate.
When I use transform.Translate on my cube's x and z axis it moves according to pressing keys. But I want the cube to move back slowly to it's original position when user stops pressing keys and default axis are x=0 ,z=0.
public float move = 1f;
void Update ()
{
this.transform.Translate (Input.GetAxis ("Horizontal") / move, 0f, Input.GetAxis ("Vertical") / move);
}
So your best bet is to store the original position
private Vector3 _intialPosition;
private float _duration = 0.4f;
private float _startTime;
void Awake()
{
_initialPosition = transform.position;
}
void Start() {
_startTime = Time.time;
}
And then check if the key has been pressed, and if not, have it move back towards the initial position
void Update()
{
if(Input.GetAxis("Horizontal") != 0 || Input.GetAxis("Vertical") != 0)
{
//Logic here to move via arrows...
}
else
{
transform.position = Vector3.Lerp(transform.position, _initialPosition, (Time.time - _startTime ) / _duration);
}
}
Unity Documentation
Lerp
You could use Vector3.MoveTowards to slowly move your current transform to a target or original transform position.
private Transform original;
public float speed = 0.5f;
void Awake()
{
original = transform;
}
void Update() {
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, original.position, step);
}
Unity3d documention - Vector3.MoveTowards