This section achieves enemy AI effects
To ensure code reuse, we create an enemy parent here, which all enemy classes then inherit
First create an enemy parent script named Enemy
Then write down the Enemy code briefly
A virtual function is used here, preceded by a visual to indicate that the function is virtual. Here's a quick overview of what virtual functions are
Virtual functions are an important implementation of polymorphism in object-oriented languages. When a function method is declared with the virtual keyword in front, it is a virtual function. The main difference between it and non-virtual functions is that its implementation can be override in derived classes (non-mandatory). Overridden functions are also virtual functions. Non-virtual functions with the same name, return value and number of parameter types are not allowed when virtual functions exist in a class or its base class.
If you want to understand it carefully, you can find some articles to read, which will not be repeated here.
Then we'll create enemies after we've created a parent to play with them
First we create an empty component named Enemies in the Hierarchy bar to represent the enemy collection, and then we create an empty subcomponent named Enemy_Frog, let's not go into the rest of this, just like creating a character, let's pick the frog in the character material bag
But remember to change its layer to the Enemy you created before or it won't show up
Add collider and Rigidbody as well
Then let the enemy move
Let's add an animation to the enemy. Like the characters, let's not repeat it here. To make it easier to manage, we create a new folder in the Animation folder, Enemy, to save our enemy's animation resources
Here we just animate idle and run, and then we set the conversion between animations in Animator
Controlled by a bool variable, run switches to run animation when true and run switches to idle animation when false
Then we set the boundaries of the enemy's movement, which is the same as checkground ing a character if it touches the ground. We give Enemy_Frog adds two empty components, named left and right, that represent the left and right boundaries a frog can move, and then we adjust the position
Then we give Enemy_Frog writes a script to control its actions, creates a new C#file and drags it directly to Enemy_Frog is OK
Open the script, get references to collider, rigidbody, etc., as usual, and note Enemy_Frog inherits the Enemy class and overloads the virtual function Start, so the Start function is preceded by override
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Enemy_Frog : Enemy { private Collider2D coll; private Rigidbody2D rb; public int speed; //----------------------------------- public Transform left, right;//Reference to left boundary private float leftMargin, rightMargin;//Frog Movable Left and Right Boundaries private bool faceRight=true;//Frogs are right-facing at first protected override void Start() { base.Start();//Call Start function of parent class coll = GetComponent<Collider2D>(); rb = GetComponent<Rigidbody2D>(); //Obtain the size of the x-axis at the left and right boundaries, respectively leftMargin = left.position.x; rightMargin = right.position.x; //Prevent the left border from following the enemy's movement and destroy it directly after acquisition Destroy(left.gameObject); Destroy(right.gameObject); } void Update() { Movement(); } //Base Move void Movement() { //If facing right if(faceRight) { anim.SetBool("run", true); rb.velocity = new Vector2(speed, rb.velocity.y); //When the enemy crosses the right border if (transform.position.x > rightMargin) { rb.velocity = new Vector2(0, 0); transform.localScale = new Vector3(-1, 1, 1); faceRight = false; } } else { anim.SetBool("run", true); rb.velocity = new Vector2(-speed, rb.velocity.y); //When the enemy crosses the left border if(transform.position.x<leftMargin) { rb.velocity = new Vector2(0, 0); transform.localScale = new Vector3(1, 1, 1); faceRight = true; } } } }
The focus of the code has been commented out and it is important to note that the left and right boundaries follow the enemy as they move, so we let them destroy when we get the left and right boundaries.
Then when we click and run, the enemy will move left and right, but when the enemy touches a person, the enemy will fly up. This is because the enemy and the character are all round colliders, so they will slide out, but they cannot use box colliders. So here we can turn the enemy's weight a little higher, here we can turn it to 5
Then when a character encounters an enemy, the character should have an animation to be hit, so we can achieve the effect when the character hits the enemy
Let's add a hit animation to the character, and then create a new bool conditional hurt from the Animator to see if the character is hit, adjust it a little
Where run, idle and jump can all switch to hurt state, provided that hurt is true, hurt can fall back to idle state, and hurt is false
Then we need to determine whether a character is attacked or not. First, we create a Boolean variable to determine whether a character is attacked or not. When a character is not attacked, we execute the Movement function. Here, we modify the contents of the FixedUpdate function a little. When a character is not attacked, we execute the Movement function.
We don't use triggers here, because if you use the enemy as a trigger, the enemy will fall, because Rigidbody was added, so let's use tags here, let's create an Enemy tag and put Enemy_Frog's tag changed to Enemy
Then we determine if the tag of the object the character encounters is Enemy, and then we do the following
The toggle animation has not been set yet, so modify it in the SwchAnim function. Note that this hit code should be placed in front of the ground code, otherwise the character's actions on the ground will be preferred, and the character's actions on the ground will not be performed.
When we click Run, we find that people can't stop because we add smooth physical material to the character's round collider, so people can't stop. In order for people to stop, we add a box Collider to the character, cancel the physical material of the round collider, add it to the box collider, and then adjust the position so that the box collider is on and the round collider is on
That's ok ay. Let's just set up a few more simple actions for people to jump over the enemy and kill it and skip it
Because all enemies have this action, we put this function into the enemy general class to achieve
Then perform this function from the people
This achieves the function of jumping over the enemy to destroy it, but it's not perfect yet. We'll modify it later.
Last Paste Code
Enemy
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Enemy : MonoBehaviour { protected Animator anim; protected virtual void Start() { anim = GetComponent<Animator>(); } public void Death() { Destroy(gameObject); } }
Enemy_Frog
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Enemy_Frog : Enemy { private Collider2D coll; private Rigidbody2D rb; public int speed; //----------------------------------- public Transform left, right;//Reference to left boundary private float leftMargin, rightMargin;//Frog Movable Left and Right Boundaries private bool faceRight=true;//Frogs are right-facing at first protected override void Start() { base.Start();//Call Start function of parent class coll = GetComponent<Collider2D>(); rb = GetComponent<Rigidbody2D>(); //Obtain the size of the x-axis at the left and right boundaries, respectively leftMargin = left.position.x; rightMargin = right.position.x; //Prevent the left border from following the enemy's movement and destroy it directly after acquisition Destroy(left.gameObject); Destroy(right.gameObject); } void Update() { Movement(); } //Base Move void Movement() { //If facing right if(faceRight) { anim.SetBool("run", true); rb.velocity = new Vector2(speed, rb.velocity.y); //When the enemy crosses the right border if (transform.position.x > rightMargin) { rb.velocity = new Vector2(0, 0); transform.localScale = new Vector3(-1, 1, 1); faceRight = false; } } else { anim.SetBool("run", true); rb.velocity = new Vector2(-speed, rb.velocity.y); //When the enemy crosses the left border if(transform.position.x<leftMargin) { rb.velocity = new Vector2(0, 0); transform.localScale = new Vector3(1, 1, 1); faceRight = true; } } } }
playercontroller
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class playercontroller : MonoBehaviour { private Rigidbody2D rb;//Get the Rigidbody2D component private Collider2D coll;//Get the Collider2D component private Animator anim;//Get Animation Components public float speed, jumpForce;//Open, set speed and jumping force public LayerMask ground;//Get Ground Layers public Transform groundCheck;//Detect if the character touches the ground private bool isJump, isGround;//Determine if the space bar is pressed and whether it is on the ground private int jumpCount;//How many jumps are used to set the character private int cherries;//Count variable public Text cherryText;//UI component for cherry count private bool isHurt;//Hit judgment //Initialization void Start() { rb = GetComponent<Rigidbody2D>(); coll = GetComponent<Collider2D>(); anim = GetComponent<Animator>(); } void Update() { //If you press the space bar and are on the ground if (Input.GetKeyDown(KeyCode.Space) && jumpCount > 0) { isJump = true; } } private void FixedUpdate() { isGround = Physics2D.OverlapCircle(groundCheck.position, 0.1f, ground); if(!isHurt) { Movement(); } Jump(); SwitchAnim(); } //Base Move void Movement() { float horizontal = Input.GetAxisRaw("Horizontal"); rb.velocity = new Vector2(horizontal * speed, rb.velocity.y);//Set the movement of the x-axis //Set up role transition issues if (horizontal != 0) { transform.localScale = new Vector3(horizontal, 1, 1); anim.SetBool("run", true); } else anim.SetBool("run", false); } //jump void Jump() { //If two jumps are set on the ground if (isGround) { jumpCount = 2; } //Press the skip key and on the ground if (isJump && isGround) { rb.velocity = new Vector2(rb.velocity.x, jumpForce); jumpCount--; isJump = false; } //Press the skip key and it is not on the ground and the jumpCount is greater than 0 else if (isJump && !isGround && jumpCount > 0) { rb.velocity = new Vector2(rb.velocity.x, jumpForce); jumpCount--; isJump = false; } } //Toggle Animation void SwitchAnim() { //If in drop state if (rb.velocity.y < 0 && !isGround) { anim.SetBool("fall", true); anim.SetBool("jump", false); } //If in a skip state if (!isGround && rb.velocity.y > 0) { anim.SetBool("jump", true); } //If a character is hit else if (isHurt) { anim.SetBool("hurt", true); if (Mathf.Abs(rb.velocity.x) < 0.1f) { anim.SetBool("hurt", false); isHurt = false; } } //If on the ground else if (coll.IsTouchingLayers(ground)) { anim.SetBool("fall", false); } } //Determine whether or not an item has been touched private void OnTriggerEnter2D(Collider2D collision) { if(collision.tag=="Collection") { Destroy(collision.gameObject); cherries++; cherryText.text = "Cherry:" + cherries; } } //wipe out the enemy private void OnCollisionEnter2D(Collision2D collision) { //Judging whether or not an enemy has been encountered if(collision.gameObject.tag=="Enemy") { //wipe out the enemy Enemy enemy = collision.gameObject.GetComponent <Enemy>();//Get enemy parent references if(anim.GetBool("fall"))//Judging whether to fall on the enemy and destroy it { enemy.Death();//Call parent function rb.velocity = new Vector2(rb.velocity.x, jumpForce); anim.SetBool("jump", true); } //If the character is on the left side of the enemy else if(transform.position.x<collision.gameObject.transform.position.x) { rb.velocity = new Vector2(-8, rb.velocity.y); isHurt = true; } //If the character is on the right side of the enemy else if(transform.position.x>collision.gameObject.transform.position.x) { rb.velocity = new Vector2(8, rb.velocity.y); isHurt = true; } } } }
If there are any mistakes or omissions, please correct them!