unity2D Horizontal Board Game Tutorial 6-Enemy AI and Striked Animation

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!

 

Tags: Unity Game Development

Posted by helpmeplease2 on Sun, 25 Sep 2022 01:29:50 +0930