3D game programming and design HW 3.5 priests and Demons

3D game programming and design HW 3.5 priests and Demons


1. Introduction to the game

  • Priest and devil is a puzzle game
  • You will help the priest and the devil cross the river within a limited time. There are three priests and three demons on one side of the river. They all wanted to go to the other side of the river, but there was only one boat, which could only carry two people at a time. Someone must turn the boat from one side to the other. If the priests are defeated by the demons on both sides of the river (fewer priests than demons on the shore), they will be killed and the game will be over.
  • In the game, you can click them to move them, and click the go button to move the ship to another direction. You can try it in many ways. Let all priests live! Good luck!

2. Subject requirements



3.MVC structure

  • MVC is the abbreviation of model view controller. It is a software design mode. It organizes code by separating business logic, data and interface display, and gathers business logic into one component. It does not need to rewrite business logic while improving and customizing interface and user interaction.
  • MVC basic structure diagram:

  • In the game design of priest and devil, it can be divided into
    ① SSDirector: the manager of the whole structure, which controls the switching and coordination of various scenes;
    ② ISceneController (Abstract): the manager of each scene, which is the interface used by the Director to pass requirements to the scene controller
    ③ IUserAction (Abstract): it is responsible for managing the interaction between behaviors and generating corresponding response results for each action of the player
  • Through this responsibility based design, we can give different objects specific responsibilities, and make the structure of the game program clearer and more reusable.

4. Game object table, player action table and event table

Game object object type
Reverend Priest Cube
Devil Devil Sphere
Boat boat Cube
River river Cube
Coast river bank Cube
action Trigger event
Click Character character People get on and off the ship
Click Boat Ships cross the river
event result
There are more demons on one side than priests (including those on board and on shore) Player failed
All the priests and Demons went to the other side Player success

5. Class design

Based on responsibility design, use object-oriented technology to design games.
The program code of the project adopts MVC structure, and the code files are put into the folders of controllers, models and views according to the functions.

(1) Models

① Boat

  • It has the attribute of location, starting point and ending point. In addition, it also needs to maintain the empty position coordinates and role information on the ship

② Coast

  • As with Boat, it is necessary to maintain the vacancy coordinates and role information on shore

③ Character

  • There are name, location and isOnBoard attributes; Name is used to distinguish whether the character is a priest or a devil, and IsOnBoat is used to distinguish whether it is on the ship or not

(2) Views

① UserGUI

  • The Start function initializes and obtains the current field record CurrentSecnController by obtaining a single instance of the Director
        // Get GameController
	    void Start () {
            status = 0;
            action = Director.GetInstance().CurrentSecnController as IUserAction;
        }
  • OnGUI function, rendering game interface;
	    void OnGUI () {
            textStyle = new GUIStyle {
                fontSize = 40,
                alignment = TextAnchor.MiddleCenter
            };
            hintStyle = new GUIStyle {
                fontSize = 15,
                fontStyle = FontStyle.Normal
            };
            btnStyle = new GUIStyle("button") {
                fontSize = 30
            };
            // Print title and rule tips
            GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 2 - 195, 100, 50), 
                "Priest And Devil", textStyle);
            GUI.Label(new Rect(Screen.width / 2 - 400, Screen.height / 2 - 125, 100, 50), 
                "White Cube: Periest\n Red Sphere: Devil\n\n" + rule, hintStyle);
            
            // Button to print game results and restart the game
            if (status == 1) {
                // Lose
                GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 2 - 85, 100, 50), "You Lose!", textStyle);
                if (GUI.Button(new Rect(Screen.width / 2 - 70, Screen.height / 2, 140, 70), "Restart", btnStyle)) {
                    status = 0;
                    action.Restart();
                }
            } else if (status == 2) {
                // Win
                GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 2 - 85, 100, 50), "You Win!", textStyle);
                if (GUI.Button(new Rect(Screen.width / 2 - 70, Screen.height / 2, 140, 70), "Restart", btnStyle)) {
                    status = 0;
                    action.Restart();
                }
            }
	    }
  • OnMouseDown function, which monitors and captures the click action of the user and transfers it to the Controller for processing
        void OnMouseDown() {
            if (gameObject.name == "boat") {
                action.MoveBoat();
            } else {
                action.CharacterClicked(characterCtrl);
            }
        }

(3) Controllers

① Director

  • Get the scene of the current game
  • Manage the global state of the game
    public class Director : System.Object
    {
        // Singlton instance.
        private static Director instance;
        public ISceneController CurrentSecnController { get; set; }

        // get instance anytime anywhere!
        public static Director GetInstance(){
            if (instance == null){
                instance = new Director();
            }
            return instance;
        }

        public int getFPS(){
            return Application.targetFrameRate;
        }
    
        public void setFPS(int fps){
            Application.targetFrameRate = fps;
        }
    }

② ISceneController

  • Interface between GameController and Director
public interface ISceneController
    {
        void LoadResources();
    }

③ IUserAction

  • User interaction interface for players to interact with GameController
    public interface IUserAction {
        void MoveBoat();
        void CharacterClicked(CharacterController characterCtrl);
        void Restart();
    }

④ Moveable

  • SetDestination is used to control the motion of the corresponding game object
        public void SetDestination(Vector3 pos) {
            destination = pos;
            middle = pos;
            if (pos.y == transform.position.y) {          // Mobile ship
                status = 2;
            } else if (pos.y < transform.position.y) {    // Move character from shore to ship
                middle.y = transform.position.y;
            } else {                                      // Move character from ship to shore
                middle.x = transform.position.x;
            }
            status = 1;
        }

⑤ GameController

  • CoastController
    GetEmptyIndex: subscript of onshore vacancy
    GetEmptyPosition: coordinates of onshore vacancy
    GetOnCoast: ashore
    GetOffCoast: Offshore
    GetCharacterNum: calculate the number of shore characters
  • BoatController
    Move: move boat
    GetEmptyIndex: subscript of empty space on board
    IsEmpty: is there a vacant seat on the ship
    GetEmptyPosition: the coordinates of the empty position on the ship
    GetOnBoat: called when the player clicks on the priest or devil to get him on the ship.
    GetOffBoat: called when the player clicks the priest or devil to make it ashore.
    GetCharacterNum: calculate the number of characters on board
  • CharacterController
    Cooperate with BoatController

⑥ FirstController

  • When the scene is loaded with wake, it will automatically inject the director and set the current scene
    void Awake() {
        Director director = Director.GetInstance();
        director.CurrentSecnController = this;
        userGUI = gameObject.AddComponent<UserGUI>() as UserGUI;
        characters = new MyNamespace.CharacterController[6];
        LoadResources();
    }
  • CheckGameOver determines the outcome of the game
    private int CheckGameOver() {
        int rightPriest = 0;
        int rightDevil = 0;
        int leftPriest = 0;
        int leftDevil = 0;
        int status = 0;

        rightPriest += rightCoastCtrl.GetCharacterNum()[0];
        rightDevil += rightCoastCtrl.GetCharacterNum()[1];
        leftPriest += leftCoastCtrl.GetCharacterNum()[0];
        leftDevil += leftCoastCtrl.GetCharacterNum()[1];

        // Win
        if (leftPriest + leftDevil == 6) {
            status = 2; 
        }
        
        if (boatCtrl.boat.Location == Location.right) {
            rightPriest += boatCtrl.GetCharacterNum()[0];
            rightDevil += boatCtrl.GetCharacterNum()[1];
        } else {
            leftPriest += boatCtrl.GetCharacterNum()[0];
            leftDevil += boatCtrl.GetCharacterNum()[1];
        }

        // Lose
        if ((rightPriest < rightDevil && rightPriest > 0) ||
            (leftPriest < leftDevil && leftPriest > 0)) {
            status = 1;
        }

        return status;
    }

6. Game result display

See the following video for the complete game process:

(1) Game interface

(2) Game failure

(3) Game victory

Tags: Game Development

Posted by Imperialdata on Sat, 14 May 2022 17:09:38 +0300