Unity game production

3D games and programming Homework 6

Experimental content

  1. Intelligent patrol
    • Submission requirements:
    • Game design requirements:
      • Create a map and several patrols (using animation);
      • Each patrol takes a convex polygon with 3 ~ 5 sides, and the position data is the relative address. That is, determine the next target position each time and calculate with your current position as the origin;
      • If the patrol collides with an obstacle, it will automatically select the next point as the target;
      • The patrolman will automatically chase the player if he senses the player within the set range;
      • After losing the player's target, continue patrolling;
      • Scoring: players will score one point each time they lose a patrol and collide with the patrol. The game ends;
    • Program design requirements:
      • You must use subscription and publish mode to deliver messages
        • subject: OnLostGoal
        • Publisher: ?
        • Subscriber: ?
      • Factory mode production patrol
    • Friendly tip 1: generate a convex polygon with 3 ~ 5 edges
      • Randomly generated rectangle
      • By randomly finding points on each edge of the rectangle, a convex polygon of 3 - 4 can be obtained
      • 5 ?
    • Friendly tip 2: refer to previous blogs and give your new play

Experimental environment

  • Windows
  • Unity 2020.3.18

Technical diary

Model and animation

1. Basic knowledge of model and animation

  • Model
    • The combination of object objects, Unity is mapped to the game object tree
    • Each object contains a Mesh and skin settings
    • Contains the textures, materials, and one or more animation clips used
    • The model is created by 3D designers using 3D Max, etc
  • Animation Clip
    • The time series of attributes such as the position of objects or bones in keyframes
    • The position or attribute of the object in each frame is calculated by interpolation algorithm

2. Mecanim animation state machine (CrowAnimatorController)

The design of state machine controller includes four parts: state, transition, parameters and conditions.

Properties of observation status:

  • Motion animation clip
  • Speed (magnification)
  • Foot IK?
  • ...
  • Transtions
    • Default: detect effective transfers in order
    • Solo: priority detection transfer
    • Mute: transfer prohibited
  • With quality
  • With center
  • With centroid (regardless of shape)
    • Hypothesis 1: the object is homogeneous
    • Hypothesis 2: the center coincides with the center of mass
  • The object force is decomposed into:
    • Force acting on the center point (force)
    • Moment of rotation around the center point (Torque)

Set transition:

  • Pay attention to the order of changes
  • Set solo or mute
  • Set each transition
    • Name the change for easy control
    • Use animation end condition
    • Transition animation blending (smoothing process)
    • Transition conditions, such as:
      • Fly - > exit condition is live
      • Not live transition from any state to death

Control transition conditions:

  • Use transfer control variables
    • Float, Int, Bool type
    • Trigger type
  • Planning transfer variables and conditions of transition events
    • Transfer variable design
      • It is recommended to use more trigger type variables
      • Ensure that the transition conditions are unique and avoid using sequence to determine the transition (bit operation is usually OK)
      • Use mute to close unused transfers
  • Conditional design, for example:
    • live = false turn into death
    • fly_attack_trigger OK to enter attack

3. Intermediate knowledge of humanoid animation and animation

Avatar means incarnation (in Hinduism and Buddhism, a god transformed into a human or animal). Needless to say, animals turn into human shapes. Even plants and grasses have the anthropomorphic action of nodding. Therefore, Unity's animation system has special functions to deal with human characters. Because humanoid characters are common in games, Unity provides a special workflow and extended toolset for humanoid animation.

  • Humanoid skeleton is a very common special case and is widely used in games
  • The similarity of human skeleton structure makes it possible to map animation from one humanoid skeleton to another.
    • As long as the sub object name of the model is the same
    • If the names are different, you need to map

2, Experimental part

1. Project configuration process

Create a new 3D unit file, and then directly replace the Assets folder on gitee with the Assets folder of the new project. At the same time, drag myScene from scenes, and directly click Run to start the game.

2. Implementation ideas and core algorithms

1)PatrolAction.cs

Defines the behavior and movement of patrolmen:

  • Each patrol takes a convex polygon with 3 ~ 5 sides, and the position data is the relative address. That is, determine the next target position each time and calculate with your current position as the origin;
  • If the patrol collides with an obstacle, it will automatically select the next point as the target;

The main functions and code analysis are as follows:

//Define the direction of patrol
private enum Dirction { EAST, NORTH, WEST, SOUTH };
//Define the location of the patrol
private float pos_x, pos_z;
//Defines the distance the patrol moves
private float move_length;
//Defines the speed at which the patrol moves
private float move_speed = 1.2f;
//Defines whether the patrol moves
private bool move_sign = true;
//Define the initial movement direction of the patrol
private Dirction dirction = Dirction.EAST;
private PatrolData data;

//Through move_sign judges whether the patrol can move. If it can move, it judges whether it reaches one of the four corners of the square (encounters an obstacle). If it does, it recalculates the moving position of the next step with itself as the origin position.
void Gopatrol(){
        if (move_sign){
            switch (dirction){
                case Dirction.EAST:
                    pos_x -= move_length;
                    break;
                case Dirction.NORTH:
                    pos_z += move_length;
                    break;
                case Dirction.WEST:
                    pos_x += move_length;
                    break;
                case Dirction.SOUTH:
                    pos_z -= move_length;
                    break;
            }
            move_sign = false;
        }
        this.transform.LookAt(new Vector3(pos_x, 0, pos_z));
        float distance = Vector3.Distance(transform.position, new Vector3(pos_x, 0, pos_z));

        if (distance > 0.9){
            transform.position = Vector3.MoveTowards(this.transform.position, new Vector3(pos_x, 0, pos_z), move_speed * Time.deltaTime);
        }
        else{
            dirction = dirction + 1;
            //Turned around and turned back
            if(dirction > Dirction.SOUTH)
            {
                dirction = Dirction.EAST;
            }
            move_sign = true;
        }
    }
2) PatrolFollowAction.cs

Defines the tracking of patrols:

  • The patrolman will automatically chase the player if he senses the player within the set range;
void Follow(){
      //The patrol moves in the direction of the player
      transform.position = Vector3.MoveTowards(this.transform.position, player.transform.position, speed * Time.deltaTime);
        this.transform.LookAt(player.transform.position);
    }
3)PatrolFollowAction.cs

Defines the collision of patrols - player:

  • If the patrol chases the player, it will kill the player and the game will end;
public class PlayerCollideDetection : MonoBehaviour {
    void OnCollisionEnter(Collision other){
        if (other.gameObject.tag == "Player")
        {
            other.gameObject.GetComponent<Animator>().SetBool("death",true);
            this.GetComponent<Animator>().SetTrigger("shoot");
            Singleton<GameEventManager>.Instance.PlayerGameover();
        }
    }
}

Here, the state machine of Animator is called. Set the state machine to "death" state and the trigger to "shot".

4)PlayerInDetection.cs

Defines the chase between the patrolman and the player:

  • The patrolman will automatically chase the player if he senses the player within the set range;
  • After losing the player's target, continue patrolling;
public class PlayerInDetection : MonoBehaviour{
    void OnTriggerEnter(Collider collider){
        //Player enters patrol range
        if (collider.gameObject.tag == "Player"){
            this.gameObject.transform.parent.GetComponent<PatrolData>().follow_player = true;
            this.gameObject.transform.parent.GetComponent<PatrolData>().player = collider.gameObject;
            //Patrolmen track players
            this.gameObject.transform.parent.GetComponent<Animator>().SetTrigger("shock");
        }
    }
    void OnTriggerExit(Collider collider){
        //Players leave the patrol range and stop tracking
        if (collider.gameObject.tag == "Player"){
            this.gameObject.transform.parent.GetComponent<PatrolData>().follow_player = false;
            this.gameObject.transform.parent.GetComponent<PatrolData>().player = null;
        }
    }
}
5)FirstSceneController.cs

Load preset resources: patrol, scoreboard, player, map, etc

public void LoadResources(){
  //Load player
	player = _PatorlFactory.LoadPlayer();
  //Load patrol
	patrols = _PatorlFactory.LoadPatrol();
	for (int i = 0; i < patrols.Count; i++){
    //Bind patrol action
		_PatrolActionManager.GoPatrol(patrols[i]);
	}
  //Load map
	GameObject.Instantiate(Resources.Load("Prefabs/Plane"), new Vector3(0, 0, 0), Quaternion.identity);
 }

Publish and subscribe mode:

  • Pass the change of score and the change of game state
//Publish and subscribe mode
    void OnEnable()
    {
        GameEventManager.ScoreChange += AddScore;
        GameEventManager.GameoverChange += Gameover;
    }
    void OnDisable()
    {
        GameEventManager.ScoreChange -= AddScore;
        GameEventManager.GameoverChange -= Gameover;
    }

Player's movement:

  • If the game is not over, you can control the player.
public void MovePlayer(float translationX, float translationZ){
        if(!game_over){
            if (translationX != 0 || translationZ != 0){
                //run animation
                player.GetComponent<Animator>().SetBool("run", true);
            }
            else
            {
                player.GetComponent<Animator>().SetBool("run", false);
            }
            //Enter the mobile player through the keyboard.
            player.transform.Translate(translationX * player_speed * Time.deltaTime, 0, translationZ * player_speed * Time.deltaTime);

            if (player.transform.position.y != 0){
                player.transform.position = new Vector3(player.transform.position.x, 0, player.transform.position.z);
            }     
        }
    }

Control the player to walk by reading the translationX and translationZ entered by the keyboard in UserGUI.cs.

6)GameEventManager.cs

Control major game events.

public class GameEventManager : MonoBehaviour{
    public delegate void ScoreEvent();
    public static event ScoreEvent ScoreChange;

    public delegate void GameoverEvent();
    public static event GameoverEvent GameoverChange;

    public void PlayerEscape(){
        //Score increases after escape
        if (ScoreChange != null){
            ScoreChange();
        }
    }

    public void PlayerGameover(){
        //After the collision, the game is over
        if (GameoverChange != null){
            GameoverChange();
        }
    }
}
PatrolData.cs

Patrol information.

public class PatrolData : MonoBehaviour{
    public int sign;
    public bool follow_player = false;
    public int wall_sign = -1;
    public GameObject player;
    public Vector3 start_position;
}
7)UserGUI.cs

Game interface and keyboard input:

void Update(){
        //Read keyboard input
        float translationX = Input.GetAxis("Horizontal");
        float translationZ = Input.GetAxis("Vertical");
        action.MovePlayer(translationX, translationZ);
    }

    private void OnGUI(){
        GUI.Label(new Rect(10, 5, 200, 50), "Score:", style);
        GUI.Label(new Rect(70, 5, 200, 50), action.GetScore().ToString(), style);
        if(action.GetScore() == 10){
            GUI.Label(new Rect(Screen.width / 2 - 30, Screen.width / 2 - 220, 100, 100), "Pass!", over_style);
            if (GUI.Button(new Rect(Screen.width / 2 - 50, Screen.width / 2 - 150, 100, 50), "Restart")){
                action.Restart();
                return;
            }
        }   
        else if(action.GetGameover() && action.GetScore() != 20){
            GUI.Label(new Rect(Screen.width / 2 - 70, Screen.width / 2 - 220, 100, 100), "Game Over!", over_style);
            if (GUI.Button(new Rect(Screen.width / 2 - 50, Screen.width / 2 - 150, 100, 50), "Restart")){
                action.Restart();
                return;
            }
        }
    }
8)PatorlFactory.cs,PatorlActionManager.cs,ScoreRecorder.cs,SSDirector.cs ,SSAction.cs ,SSActionManager.cs

There is little difference from the previous assignments, and the analysis will not be repeated.

9) Interface classes: ISenceInterface.cs, ISSActionInterface.cs, IUserInterface.cs

The user interface IUserInterface.cs provides interfaces that users can call directly: MovePlayer(), GetScore(), GetGameover(), Restart().

3, Summary

reference resources: https://blog.csdn.net/C486C/article/details/80153548

Tags: C# Windows Unity

Posted on Thu, 02 Dec 2021 19:17:48 -0500 by gio2k