No class for Week 8, but I have added some videos for a recent lesson developed for another class that feature a simplified character controller, as well as methods for attacking with stomp, melee, and projectile attacks.
Perhaps the most useful component of this is the OnDrawGizmos( ) and OnDrawGizmosSelected( ) method which can be used to draw info in your Editor’s Scene view. These are very useful for visualizing things like areas of effect, especially for those things that use triggers or physics calls. This method is called automatically by the engine just like “Update()” but are even running while the game is not playing, as this is an editor specific tool.
Check out the Unity Script Reference – Gizmos for more…
There has been a request for the player movement and alternate character controller script. These have been posted below.
SideScrollerController.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(Rigidbody2D))] [RequireComponent(typeof(CapsuleCollider2D))] public class SideScrollerController : MonoBehaviour { // public instance variables public float maxSpeed = 1f; public float jumpHeight = 1f; public float gravityScale = 1f; // direction tracking private bool facingLeft = false; // movement states public bool stunned = false; public bool isAttacking = false; // ground check values [Header("Ground Check Values")] public float groundCheckRadius = 0f; public float groundCheckYOffset = 0f; public LayerMask layerMask; [Header("Melee Attack Values")] public float attackXOffset = 0f; public float attackYOffset = 0f; public float attackRadius = 0.1f; public LayerMask attackLayerMask; [Header("Fireball Values")] public GameObject fireballPrefab; public float fireballSpeed; // private instance variables float moveDirection = 0; public bool isGrounded = false; Rigidbody2D r2d; CapsuleCollider2D mainCollider; Animator animator; SpriteRenderer spriteRenderer; // Start is called before the first frame update void Start() { r2d = GetComponent<Rigidbody2D>(); mainCollider = GetComponent<CapsuleCollider2D>(); animator = GetComponent<Animator>(); spriteRenderer = GetComponent<SpriteRenderer>(); // set some properties r2d.freezeRotation = true; r2d.collisionDetectionMode = CollisionDetectionMode2D.Continuous; r2d.gravityScale = gravityScale; } // Update is called once per frame void Update() { // Are we stunned? if (!stunned) { // we can move // are we moving horizontally? Input.GetAxisRaw(H) moveDirection = Input.GetAxisRaw("Horizontal"); // left/right facing logic here if ((moveDirection > 0f) && (facingLeft)) { facingLeft = false; } else if ((moveDirection < 0f) && (!facingLeft)) { facingLeft = true; } if (Input.GetButtonDown("Jump") && isGrounded) { r2d.velocity = new Vector2(r2d.velocity.x, jumpHeight); } if (Input.GetButtonDown("Fire1") && isGrounded) { // sword attack animator.SetTrigger("SwordAttack"); // call the melee function // MeleeAttack(); } if (Input.GetButtonDown("Fire2")) { // shoot a fireball ShootFireball(); } } // update the animator animator.SetBool("Grounded", isGrounded); // tell the animator is this grounded animator.SetFloat("VerticalSpeed", r2d.velocity.y); // get the downward velocity animator.SetFloat("Speed", Mathf.Abs(moveDirection)); // get the horizontal speed // update the direction spriteRenderer.flipX = facingLeft; } private void FixedUpdate() { Collider2D[] colliders = Physics2D.OverlapCircleAll(GetGroundCheckPosition(), groundCheckRadius, layerMask); // Check if any of the overlapping colliders are not player collider, if so, set isGrounded to true isGrounded = false; if (colliders.Length > 0) { for (int i = 0; i < colliders.Length; i++) { if (colliders[i] != mainCollider) { isGrounded = true; break; } } } if (!stunned) { // apply the movement velocity r2d.velocity = new Vector2((moveDirection) * maxSpeed, r2d.velocity.y); } } private Vector3 GetGroundCheckPosition() { Vector3 groundCheckPos = transform.position + new Vector3(0, groundCheckYOffset, 0); return groundCheckPos; } private Vector3 GetAttackPosition() { float direction = 1f; if (facingLeft) { direction = -1f; } Vector3 meleeAttackZone = transform.position + new Vector3(attackXOffset * direction, attackYOffset, 0); return meleeAttackZone; } private void OnDrawGizmosSelected() { Gizmos.color = Color.cyan; Gizmos.DrawWireSphere(GetGroundCheckPosition(), groundCheckRadius); Gizmos.color = Color.yellow; Gizmos.DrawWireSphere(GetAttackPosition(), attackRadius); } private void MeleeAttack() { // what is in our range? Collider2D[] colliders = Physics2D.OverlapCircleAll(GetAttackPosition(), attackRadius, attackLayerMask); // an array of colliders foreach (Collider2D thisCollider in colliders ) { /* Debug.Log(thisCollider); thisCollider.SendMessage("SuccessfulHit"); */ EnemyScript enemy = thisCollider.gameObject.GetComponent<EnemyScript>(); if (enemy) { enemy.SuccessfulHit(); } } } private void ShootFireball() { // instantiate the fireball GameObject fireball = Instantiate(fireballPrefab, transform.position, Quaternion.identity); Vector3 fireballVelocity = Vector3.right * fireballSpeed; if (facingLeft) { // flip the object Vector3 fireballScale = fireball.transform.localScale; fireballScale.x *= -1.0f; fireball.transform.localScale = fireballScale; // put the new vector back // reverse the velocity fireballVelocity.x *= -1.0f; } fireball.GetComponent<Rigidbody2D>().velocity = fireballVelocity; } public void StunIsOver() { // remove the stun from the character stunned = false; } }
PlayerScript.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerScript : MonoBehaviour { Animator animator; Rigidbody2D rb; SideScrollerController controller; public float pushbackForce; // Start is called before the first frame update void Start() { animator = GetComponent<Animator>(); rb = GetComponent<Rigidbody2D>(); controller = GetComponent<SideScrollerController>(); } // Update is called once per frame void Update() { } private void OnCollisionEnter2D(Collision2D collision) { if (collision.gameObject.tag == "Enemy") { EnemyScript enemy = collision.gameObject.GetComponent<EnemyScript>(); if (controller.stunned == false && enemy.isAlive) { controller.stunned = true; // we have been hurt animator.SetTrigger("IsHurt"); // pushback when hurt Vector3 pushback = collision.transform.position - transform.position; Debug.Log("Pushback = " + pushback); Vector3 currentVelocity = rb.velocity; currentVelocity.x = pushback.x * -pushbackForce; rb.velocity = currentVelocity; // change the direction of our object } } } }