Sunday, July 12, 2015

Unity 2D Platformer Tutorial - Part 4 - Enemy Movment

See the previous parts here:
Check out the code below the videos




In part 4 of this Unity3D tutorial we add Enemy AI. The enemy will walk from edge to edge of a platform as long as it's alive. This sort of enemy movement can be seen in many 2D Platformer games like Mario.

Google+ Community: https://plus.google.com/communities/108584850180626452949
Twitter: https://twitter.com/Devination3D
Facebook: https://www.facebook.com/unity3Dtutorialsbydevin

Time Breakdown:
0:30 - Updating API from Unity 4.6 to Unity 5
1:45 - Setting up the enemy sprites
2:38 - Locking Layers to avoid accidentally selecting the Canvas
3:40 - Setting up the Enemy walk anim
4:38 - Begin Enemy script
6:56 - Explanation of why we need myWidth for Linecast
9:10 - Setting up isGrounded Linecast check
12:35 - Use isGrounded check to flip the enemy if he gets to an edge
15:52 - Changing move direction to be in local space to the enemy
16:45 - Adding an isBlocked check for hitting walls
17:21 - Using ExtensionMethod .toVector2() to add a Vector2 and a Vector3: https://www.youtube.com/watch?v=D3_r7088dJ4
20:20 - Using myHeight to Linecast from middle left of enemy instead of bottom left corner
22:24 - Demonstration of enemy movement fully working



Support Further Tutorial Development
Comments?
Check out the videos above to hear the explanation and see the code in action
/*/
* Script by Devin Curry
* www.Devination.com
* www.youtube.com/user/curryboy001
* Please like and subscribe if you found my tutorials helpful :D
* Google+ Community: https://plus.google.com/communities/108584850180626452949
* Twitter: https://twitter.com/Devination3D
* Facebook Page: https://www.facebook.com/unity3Dtutorialsbydevin
/*/
using UnityEngine;
using System.Collections;

public class Enemy : MonoBehaviour
{
 public LayerMask enemyMask;
 public float speed = 1;
 Rigidbody2D myBody;
 Transform myTrans;
 float myWidth, myHeight;

 void Start ()
 {
  myTrans = this.transform;
  myBody = this.GetComponent<Rigidbody2D>();
  SpriteRenderer mySprite = this.GetComponent<SpriteRenderer>();
  myWidth = mySprite.bounds.extents.x;
  myHeight = mySprite.bounds.extents.y;
 }
 
 void FixedUpdate ()
 {
  //NOTE: This script makes use of the .toVector2() extension method.
  //Be sure you have the following script in your project to avoid errors
  //http://www.devination.com/2015/07/unity-extension-method-tutorial.html

  //Use this position to cast the isGrounded/isBlocked lines from
  Vector2 lineCastPos = myTrans.position.toVector2() - myTrans.right.toVector2() * myWidth + Vector2.up * myHeight;
  //Check to see if there's ground in front of us before moving forward
  //NOTE: Unity 4.6 and below use "- Vector2.up" instead of "+ Vector2.down"
  Debug.DrawLine(lineCastPos, lineCastPos + Vector2.down);
  bool isGrounded = Physics2D.Linecast(lineCastPos, lineCastPos + Vector2.down, enemyMask);
  //Check to see if there's a wall in front of us before moving forward
  Debug.DrawLine(lineCastPos, lineCastPos - myTrans.right.toVector2() * .05f);
  bool isBlocked = Physics2D.Linecast(lineCastPos, lineCastPos - myTrans.right.toVector2() * .05f, enemyMask);

  //If theres no ground, turn around. Or if I hit a wall, turn around
  if(!isGrounded || isBlocked)
  {
   Vector3 currRot = myTrans.eulerAngles;
   currRot.y += 180;
   myTrans.eulerAngles = currRot;
  }

  //Always move forward
  Vector2 myVel = myBody.velocity;
  myVel.x = -myTrans.right.x * speed;
  myBody.velocity = myVel;
 }
}