- Home /
How do I make my enemy have animations for directions during movemvent
I’m new to programming and still learning C# as I go. So, I was following a youtube series on making a 2D RPG top down-ish game. The player has movement in every direction with direction specific animations, as I want. As it got to making the enemy, the YouTuber’s enemy doesn’t have any direction specific animations and that’s now how my enemy is. Can I get help being lead in the right direction here? I have animations going up, down, left, and right. I have my animations made but need help with the script here. Also if someone can help adjust it for me so that the enemy only moves up down left and right instead of diagonally that would be great and much appreciated! (So over all, I want the enemy to be like the player with animations, but randomized movement and no player control) Here’s the current script.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AnimalMovement : MonoBehaviour {
private Animator anim;
public float moveSpeed;
private Rigidbody2D myRigidbody;
private bool moving;
public float timeBetweenMove;
private float timeBetweenMoveCounter;
public float timeToMove;
private float timeToMoveCounter;
private Vector3 moveDirection;
// Use this for initialization
void Start () {
anim = GetComponent<Animator> ();
myRigidbody = GetComponent<Rigidbody2D> ();
timeBetweenMoveCounter = timeBetweenMove;
timeToMoveCounter = timeToMove;
}
// Update is called once per frame
void Update () {
if (moving)
{
timeToMoveCounter -= Time.deltaTime;
myRigidbody.velocity = moveDirection;
if (timeToMoveCounter < 0f)
{
moving = false;
timeBetweenMoveCounter = timeBetweenMove;
}
}
else
{
timeBetweenMoveCounter -= Time.deltaTime;
myRigidbody.velocity = Vector2.zero;
if (timeBetweenMoveCounter < 0f)
{
moving = true;
timeToMoveCounter = timeToMove;
moveDirection = new Vector3(Random.Range(-1f, 1f) * moveSpeed, Random.Range(-1f, 1f) * moveSpeed, 0f);
}
}
}
}
Answer by TachyonBlast · Aug 30, 2018 at 06:47 PM
If you followed a youtube tutorial, I suppose you are using blend trees for this kind of animations (if not, I highly sugest using one for the enemy animation controller). You need to create a blend tree for Idle animations and another one for Walking aniamtions. The transition between them will be managed by a boolean "isWalking". Make the blend trees 2D cartesian and go from 0 to 1/-1 in each axis.
So when it's time to move, you only need to change this parameters accordingly. The "move" part of the update function would be like this:
if (moving)
{
timeToMoveCounter -= Time.deltaTime;
myRigidbody.velocity = moveDirection;
anim.SetBool("isWalking", true);
anim.SetFloat("xMov", moveDirection.normalized.x);
anim.SetFloat("yMov", moveDirection.normalized.y);
if (timeToMoveCounter < 0f)
{
moving = false;
anim.SetBool("isWalking", false);
timeBetweenMoveCounter = timeBetweenMove;
}
}
If you need help seting up the blend trees let me know.
Edit: The page wouldn't let me post a comment and this is basically part 2 of the answer so here it goes: Here's your update function to only allow movement in one axis (only one direction each time they start moving).
void Update()
{
if (moving)
{
timeToMoveCounter -= Time.deltaTime;
myRigidbody.velocity = moveDirection;
anim.SetBool("isWalking", true);
anim.SetFloat("xMov", moveDirection.normalized.x);
anim.SetFloat("yMov", moveDirection.normalized.y);
if (timeToMoveCounter < 0f)
{
moving = false;
anim.SetBool("isWalking", false);
timeBetweenMoveCounter = timeBetweenMove;
}
}
else
{
timeBetweenMoveCounter -= Time.deltaTime;
myRigidbody.velocity = Vector2.zero;
if (timeBetweenMoveCounter < 0f)
{
moving = true;
timeToMoveCounter = timeToMove;
if (Random.value >= 0.5f) //random boolean
{
moveDirection = new Vector3(Random.Range(-1f, 1f) * moveSpeed, 0f, 0f);
}
else
{
moveDirection = new Vector3(0, Random.Range(-1f, 1f) * moveSpeed, 0f);
}
}
}
}
However, if you want them to move to a point which would require diagonal movement, but executing first the movement in one axis and after that the other one, your Update would be this one (I defined a new float called axisChangeTime and a new bool called verticalGoesFirst). This is probably what you want:
private float axisChangeTime;
private bool verticalGoesFirst;
void Update () {
if (moving)
{
timeToMoveCounter -= Time.deltaTime;
axisChangeTime -= Time.deltaTime;
anim.SetBool("isWalking", true);
anim.SetFloat("xMov", moveDirection.normalized.x);
anim.SetFloat("yMov", moveDirection.normalized.y);
if (verticalGoesFirst)
{
myRigidbody.velocity = moveDirection.y;
}
else
{
myRigidbody.velocity = moveDirection.x;
}
if (axisChangeTime <= 0f)
{
verticalGoesFirst = !verticalGoesFirst;
}
if (timeToMoveCounter < 0f)
{
moving = false;
anim.SetBool("isWalking", false);
timeBetweenMoveCounter = timeBetweenMove;
}
}
else
{
timeBetweenMoveCounter -= Time.deltaTime;
myRigidbody.velocity = Vector2.zero;
if (timeBetweenMoveCounter < 0f)
{
moving = true;
timeToMoveCounter = timeToMove;
moveDirection = new Vector3(Random.Range(-1f, 1f) * moveSpeed, Random.Range(-1f, 1f) * moveSpeed, 0f);
verticalGoesFirst = Random.value >= 0.5f;
if (verticalGoesFirst)
{
axisChangeTime = (moveDirection.y / (moveDirection.x + moveDirection.y)) * timeToMove;
}
else
{
axisChangeTime = (moveDirection.x / (moveDirection.x + moveDirection.y)) * timeToMove;
}
}
}
}
Should work fine if I didn't miss anything.
Yeah, I have an animator controller with blend trees. Anyway after using that, I get "Assets/Scripts/Animal$$anonymous$$ovement.cs(34,27): error CS0103: The name `movement' does not exist in the current context" in the console.
Also does this code still allow the enemy to randomly move around in random directions?
Sorry, movement should be called moveDirection (your movement vector). And yes this still allows for diagonal movement. Assu$$anonymous$$g you want to choose any vector around the enemy and make it move there only one axis at a time (ins$$anonymous$$d of diagonally, first vertical and then horizontal without any wait time) you can create a new Vector2 which only contains the Y movement, and apply that to the velocity. After the correct time, flip a flag and start the X movement applying a new Vector2 with the X value to velocity. To calculate the time you should be moving in each direction, just sum the x + y values of the original moveDirection Vector2. Then, divide the x coordinate by that value ( x/(x+y) ) to find out what percentage of the total time should take up the movement in that axis. So multiply timeTo$$anonymous$$oveCounter by that number and, when that time has passed, start moving in the other axis using an if condition. You can also randomize which axis you should start to move in. Right now I can't provide code, but hope it helps.
Once I applied your code from the previous comment, my enemy completely stopped moving. Can you provide more code to help me out? Also more help with making it only move randomly left orright would be much appreciated.
Okay I fixed the movement , so it's back to moving. But I'd still like to make it only move left or right, randomly. And thank you for all of your help so far it's already looking better with the animations! But the diagonal movement throws it off.
@$$anonymous$$Blast I get "Cannot implicitly convert type float' to
UnityEngine.Vector2'" on the lines "myRigidbody.velocity = moveDirection.y;" and "myRigidbody.velocity = moveDirection.x;"
Oops, ins$$anonymous$$d of asigning that asign a new Vector2: myRigidbody.velocity = new Vector2(0, moveDirection.y); myRigidbody.velocity = new Vector2(moveDirection.x, 0);
It's been a week, maybe it didn't notify you of my edit?
Yeah, it never notified me of the edit. But alright I did that, and it's working great now. Now this one isn't part of your script or anything, it was already like this, but movement speed is pretty randomized too and I was wondering what to do to fix that? Because sometimes the enemy will run dead slow, and sometimes ultra fast. And thank you thank you! I appreciate you