Unity-Small Game Priest and Demon

Unity-Small Game Priest and Demon

game introduction

When the game starts, three priests and three demons are on one side of the river. The object of the game is to help them cross the river to the other side, and the number of priests cannot be less than the number of demons on either side, otherwise the demons will attack the priests. The rules of the game are as follows:

Characters and props:
  • Priest (P): There are three priests in the game, represented by P.
  • Devil (D): There are three demons in the game, represented by D.
  • Ship (B): There is a ship in the game, represented by B. The maximum capacity of the boat is two people.
Initial state:
  • Initially, three priests (PPP), three demons (DDD) and the boat (B) are on one side of the river.
Target status:
  • The goal of the game is to get all priests and demons safely to the other side of the river, and there can be no more demons than priests on any side (e.g. PD or PDD are legal on either side of the river) status, but DD is an illegal status).
Movement rules:
  • A boat can carry up to two characters (clerics, demons, or a mixture of the two) across the river at a time.
  • There cannot be more demons than priests on any side, otherwise the demons will attack the priests and the game is lost.
  • Both clerics and demons can operate the ship, but no more than two characters can be on board.
game over:

The game ends in two situations:

  • When all priests and demons have safely crossed to the other side of the river and meet the conditions (the number of demons is no more than the number of priests), the game is won.
  • If there are more demons than priests on either side, the demons will attack the priests and the game is lost.

"Priests and Demons" is a classic intellectual game that requires players to cleverly arrange the positions of characters and passengers on the boat according to the rules to ensure that all characters can cross the river safely. It is a game that tests logical thinking and planning skills. .

Design architecture (MVC)

Using the MVC (Model-View-Controller) idea, the game structure is clearer.

1. Class introduction
  • Director class: Implemented using single instance mode, responsible for global game settings, scene management, etc.

  • SceneManager class: Implements game model management and game logic, conforms to the MVC framework, and separates the logic of the user view and the game scene model.

  • Human-computer interaction (IUserAction) interface: Describes the operations corresponding to the game rules and defines the user interaction behavior in the game.

2. MVC framework workflow
  1. Director object settings: The director class is responsible for the global settings of the game, including initializing game scenes, characters and other information.

  2. Scene switching: The scene manager is responsible for managing game scenes, including switching between different game scenes to ensure the smooth progress of the game process.

  3. User operation processing: User operations are processed by classes that implement the IUserAction interface, which defines operations corresponding to game rules, such as player Move, attack, etc.

3. Advantages
  • Clear structure: The MVC framework makes the game structure clearer and separates the data model, user view and control logic.

  • Modular development: Different modules (Model, View, Controller) can be developed and tested independently, which improves the maintainability and scalability of the code.

  • Logical separation: Through MVC, the logical separation of the user view and the game scene model is achieved, reducing the coupling.

  • Unified scene control: A unified scene control interface has been established to support different business logic in different scenarios, increasing flexibility.

Insert image description here

The specific design plan is as follows:
Insert image description here

Specific code implementation

IUserAction
public interface IUserAction
{
    // 移动船
    void moveBoat();
    // 处理角色点击事件
    void characterIsClicked(MyCharacterController characterCtrl);
    // 重新开始游戏
    void restart();
}

InterfaceIUserAction defines three methods for game operations: moveBoat() for moving the ship, characterIsClicked(MyCharacterController characterCtrl) for processing Character click event, restart() is used to restart the game.

ISceneController
// ISceneController 接口,定义了游戏场景控制器的方法契约。
public interface ISceneController
{
    
    
    // 加载游戏资源的方法,由实现接口的类负责具体实现。
    void loadResources();
}

Code analysis:

  1. ISceneControllerIt is an interface that defines the contract of the game scene controller. An interface is an abstract data type that only contains declarations of methods, properties, events, or indexers, but does not provide implementation of methods. Interfaces provide a specification that allows multiple classes to implement according to the same standards, thereby enabling code organization and collaboration.

  2. loadResources()The function of the method is to load the resources required by the game. The specific implementation will be completed by a class that implements the ISceneController interface. This method allows the game scene controller to load the required resources at the start of the game so that the game can run correctly.

UserGUI
// UserGUI 类,继承自 MonoBehaviour,负责游戏界面的显示和用户输入的处理。
public class UserGUI : MonoBehaviour
{
    
    
    // 用户操作接口。
    private IUserAction action;
    // 游戏状态,0 表示游戏进行中,1 表示游戏结束(失败),2 表示游戏结束(胜利)。
    public int status = 0;
    GUIStyle style;
    GUIStyle buttonStyle;

    // 在 Start 方法中进行初始化操作。
    void Start()
    {
    
    
        // 获取用户操作接口。
        action = SSDirector.getInstance().currentSceneController as IUserAction;

        // 设置文本样式。
        style = new GUIStyle();
        style.fontSize = 40;
        style.alignment = TextAnchor.MiddleCenter;

        // 设置按钮样式。
        buttonStyle = new GUIStyle("button");
        buttonStyle.fontSize = 30;
    }

    // 在 OnGUI 方法中绘制游戏界面和处理用户输入。
    void OnGUI()
    {
    
    
        // 根据游戏状态显示不同的界面。
        if (status == 0)
        {
    
    
            // 游戏进行中,显示“Restart”按钮,点击按钮可以重新开始游戏。
            if (GUI.Button(new Rect(Screen.width - 160, 10, 140, 70), "Restart", buttonStyle))
            {
    
    
                status = 0;
                action.restart();
            }
        }
        else if (status == 1)
        {
    
    
            // 游戏结束(失败),显示“Gameover!”文本和“Restart”按钮,点击按钮可以重新开始游戏。
            GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 2 - 85, 100, 50), "Gameover!", style);
            if (GUI.Button(new Rect(Screen.width / 2 - 70, Screen.height / 2, 140, 70), "Restart", buttonStyle))
            {
    
    
                status = 0;
                action.restart();
            }
        }
        else if (status == 2)
        {
    
    
            // 游戏结束(胜利),显示“You win!”文本和“Restart”按钮,点击按钮可以重新开始游戏。
            GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 2 - 85, 100, 50), "You win!", style);
            if (GUI.Button(new Rect(Screen.width / 2 - 70, Screen.height / 2, 140, 70), "Restart", buttonStyle))
            {
    
    
                status = 0;
                action.restart();
            }
        }
    }
}

Code analysis:

  1. UserGUIThe class is a class inherited from MonoBehaviour and is used to handle the display and user input of the game interface.

  2. actionThe variable is used to store the instance of the user operation interface, which is obtained through SSDirector.getInstance().currentSceneController.

  3. statusThe variable represents the game status, 0 means the game is in progress, 1 means the game is over (failure), and 2 means the game is over (win).

  4. Perform initialization in the Start() method and set the styles of text and buttons.

  5. OnGUI()Methods are used to draw text and buttons on the game interface and handle user click events. Depending on the game state, different interface elements are displayed.

  6. If the game status is in progress (status == 0), the "Restart" button will be displayed. Click the button to restart the game.

  7. If the game status is failed (status == 1), the text "Gameover!" and the "Restart" button are displayed. Click the button to restart the game.

  8. If the game status is victory (status == 2), the text "You win!" and the "Restart" button are displayed. Click the button to restart the game.

SSDirector
// SSDirector 类,继承自 System.Object,实现了单例模式,用于管理当前场景的场景控制器。
public class SSDirector : System.Object
{
    
    
    // 静态变量,用于保存唯一的 SSDirector 实例。
    private static SSDirector _instance;
    // 当前场景的场景控制器,实现了 ISceneController 接口。
    public ISceneController currentSceneController {
    
     get; set; }

    // 获取单例实例的静态方法。
    public static SSDirector getInstance()
    {
    
    
        // 如果实例为空,创建一个新的 SSDirector 实例。
        if (_instance == null)
        {
    
    
            _instance = new SSDirector();
        }
        // 返回唯一的实例。
        return _instance;
    }
}

Code analysis:

  1. SSDirectorClass is a singleton class used to manage the scene controller of the current scene.

  2. currentSceneControllerThe attribute is used to save the scene controller instance of the current scene. The controller class must implement the ISceneController interface.

  3. getInstance()The method is a static method that obtains an instance of SSDirector. In this method, if _instance is empty (that is, it has not been instantiated), create a new SSDirector instance and then return this instance. This ensures that only one instance of the SSDirector class exists in the entire application, avoiding the overhead of multiple instantiations, while also ensuring data consistency and security.

  4. Through the singleton mode, the SSDirector class provides a globally unique access point, so that other classes can obtain it through SSDirector.getInstance()< an instance of i=3> to access and manage the scene controller of the current scene. SSDirector

FirstController

Since there is too much code, I will extract some iconic parts to show below.

Code comments and text analysis:

// FirstController 类,继承自 MonoBehaviour,实现了 ISceneController 和 IUserAction 接口,
// 用于控制游戏场景的初始化、游戏规则和用户操作。

public class FirstController : MonoBehaviour, ISceneController, IUserAction
{
    
    
    // 水面的位置。
    readonly Vector3 water_pos = new Vector3(0, 0.5F, 0);
    // 用户界面管理器。
    UserGUI userGUI;
    // 岸边的控制器。
    public CoastController fromCoast;
    public CoastController toCoast;
    // 船的控制器。
    public BoatController boat;
    // 角色控制器数组。
    private MyCharacterController[] characters;

    // Awake 方法在对象被创建时调用,用于初始化数据。
    void Awake()
    {
    
    
        // 获取场景总管,将当前场景控制器设置为当前场景。
        SSDirector director = SSDirector.getInstance();
        director.currentSceneController = this;
        // 在游戏对象上添加 UserGUI 组件,用于管理用户界面。
        userGUI = gameObject.AddComponent<UserGUI>() as UserGUI;
        // 初始化角色控制器数组和加载游戏资源。
        characters = new MyCharacterController[6];
        loadResources();
    }

    // 检查游戏是否结束的方法,返回值:0->未结束, 1->失败, 2->胜利
    int check_game_over()
    {
    
    
        // 统计各个岸上的牧师和魔鬼数量。
        int from_priest = 0;
        int from_devil = 0;
        int to_priest = 0;
        int to_devil = 0;

        // 统计 fromCoast 上的角色数量。
        int[] fromCount = fromCoast.getCharacterNum();
        from_priest += fromCount[0];
        from_devil += fromCount[1];

        // 统计 toCoast 上的角色数量。
        int[] toCount = toCoast.getCharacterNum();
        to_priest += toCount[0];
        to_devil += toCount[1];

        // 如果 toCoast 上的牧师和魔鬼总数为 6,则游戏胜利。
        if (to_priest + to_devil == 6)
            return 2;

        // 统计船上的角色数量。
        int[] boatCount = boat.getCharacterNum();
        if (boat.get_to_or_from() == -1)
        {
    
       // 船在 toCoast 上
            to_priest += boatCount[0];
            to_devil += boatCount[1];
        }
        else
        {
    
       // 船在 fromCoast 上
            from_priest += boatCount[0];
            from_devil += boatCount[1];
        }

        // 如果 fromCoast 上的牧师数量小于魔鬼数量并且有牧师,则游戏失败。
        if (from_priest < from_devil && from_priest > 0)
        {
    
           // 失败
            return 1;
        }
        // 如果 toCoast 上的牧师数量小于魔鬼数量并且有牧师,则游戏失败。
        if (to_priest < to_devil && to_priest > 0)
        {
    
    
            return 1;
        }
        // 游戏未结束。
        return 0;
    }

    // 重新开始游戏的方法,用于重置船和岸上的角色。
    public void restart()
    {
    
    
        boat.reset();
        fromCoast.reset();
        toCoast.reset();
        for (int i = 0; i < characters.Length; i++)
        {
    
    
            characters[i].reset();
        }
    }
}

Code analysis:

  1. FirstControllerThe class is the controller of the game scene and implements the ISceneController and IUserAction interfaces.

  2. In the Awake() method, get an instance of the scene manager SSDirector and set the current scene controller to the current scene. At the same time, initialize the user interface UserGUI component and character controller array, and load game resources.

  3. check_game_over()Method used to check if the game is over. If the game is won (the total number of priests and devils on toCoast is 6), return 2; if the game is lost (from

If the number of priests on Coast or toCoast is less than the number of devils and there are priests), return 1; otherwise, return 0 to indicate that the game is not over.

  1. restart()Method is used to restart the game. In this method, the status of the ship and the status of the character on the shore are reset, returning the game to its initial state.

Development summary

In the process of developing this "Priests and Demons" game, I learned many important concepts and skills about game development by drawing on many reference blogs and codes online. Here are some key points from the development summary:

1. Game design and planning

  • Game rules definition: Game rules need to be clearly defined, including character abilities, game victory conditions and failure conditions, etc.
  • Character design: The characters in the game should have clear identities and characteristics, so that the game has sufficient depth and strategy.

2. Programming skills

  • Interface and implementation: Use interfaces to separate game logic and user operations, improving the modularity and maintainability of the code.
  • Single-case mode: Use single-case mode to manage game state to ensure that there is only one instance during the entire game life cycle.
  • GUI Programming: Learn to use Unity’s GUI system to create game interfaces, including buttons, labels and other UI elements.

3. Logical thinking and problem solving

  • Game status judgment: Writing game logic and judging whether the game is successful or failed requires logical thinking and problem-solving skills.
  • Game mechanism design: Designing game rules and character abilities requires in-depth thinking about the balance and fun of the game.

4. User experience and interface design

  • User interface design: Design a user-friendly game interface, including button location, font size, etc., to provide a good user experience.
  • Game feedback: Provide appropriate feedback in the game, such as displaying corresponding prompt information when the game is successful or failed, to increase the interactivity of the game.

Video display

Unity game Priest and Demon

Reference blog

http://t.csdnimg.cn/UbqPT
http://t.csdnimg.cn/T5rqW

Guess you like

Origin blog.csdn.net/helianthus_254/article/details/133849634