Simple Solar System and Priests and Devils

3D game homework 3

1. Use Unity to realize a complete solar system

Requirements : The rotational speeds of the planets around the sun must be different and not on the same normal plane.

Process : First find the textures of the planets in the solar system and load them into the assets of the project. [URL of Planet Textures]( Solar Textures | Solar System Scope )

  1. Create several Spheres and name them the names of each planet in the solar system, and then drag each texture to the corresponding planet, thus forming the prefab of each planet.

insert image description here

  1. Drag each planet to its corresponding position in the solar system with the sun as the center, and set the size.

insert image description here

  1. Add a light source effect to the sun, that is, add a Point Light at the position of the sun to achieve the light source effect, and adjust the color of the light to orange-yellow.

insert image description here

  1. The sun looks a bit dark at this point, so we need to make the surface of the sun glow.

Check the Emission of the sun's texture component and set the color to orange red.

insert image description here
insert image description here

  1. Use code to make the planets orbit the sun and the moon orbit the earth.

It should be noted that if the rotation around a rotating planet will be affected by the rotation of the planet , it is necessary to clone a sun and the earth and make these two cloned planets not rotate, and set the objects of other planets to revolve around these two non-rotating planets .

  1. In order to be able to display the trajectory of the planet, it is necessary to add a component Trial Render to each planet, the specific location is Component->Effects->Trial Render.

The running effect diagram after adding is as follows

insert image description here

It can be seen that the planets orbit in different normal planes.

code show as below.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Rotate : MonoBehaviour {
	public Transform mercury;
	public Transform venus;
	public Transform earth;
	public Transform mars;
	public Transform jupiter;
	public Transform saturn;
	public Transform uranus;
	public Transform neptune;
	public Transform moon;
	public Transform earthclone;
	public Transform sun;
	// Use this for initialization
	void Start () {
        mercury = this.transform.Find("Mercury");
		venus = this.transform.Find("Venus");
		earth = this.transform.Find("Earth");
		mars = this.transform.Find("Mars");
		jupiter = this.transform.Find("Jupiter");
		saturn = this.transform.Find("Saturn");
		uranus = this.transform.Find("Uranus");
		neptune = this.transform.Find("Neptune");
		earthclone = this.transform.Find("EarthClone");
		moon = earthclone.Find("Moon");
		sun = this.transform.Find("Sun");
	}
	
	// Update is called once per frame
	void Update () {
		sun.Rotate(Vector3.up * Time.deltaTime * 30);
		mercury.RotateAround(this.transform.position, new Vector3(1, 5, 0), 24 * Time.deltaTime);
		mercury.Rotate(Vector3.up * Time.deltaTime * 300);
		venus.RotateAround(this.transform.position, new Vector3(2, 12, 0), 33 * Time.deltaTime);
		venus.Rotate(Vector3.up * Time.deltaTime * 280);
		earth.RotateAround(this.transform.position, new Vector3(1, 10, 0), 19 * Time.deltaTime);
		earth.Rotate(Vector3.up * Time.deltaTime * 250);
		mars.RotateAround(this.transform.position, new Vector3(2, 11, 0), 24 * Time.deltaTime);
		mars.Rotate(Vector3.up * Time.deltaTime * 220);
		jupiter.RotateAround(this.transform.position, new Vector3(1, 10, 0), 13 * Time.deltaTime);
		jupiter.Rotate(Vector3.up * Time.deltaTime * 180);
		saturn.RotateAround(this.transform.position, new Vector3(1, 11, 0), 10 * Time.deltaTime);
		saturn.Rotate(Vector3.up * Time.deltaTime * 160);
		uranus.RotateAround(this.transform.position, new Vector3(2, 7, 0), 18 * Time.deltaTime);
		uranus.Rotate(Vector3.up * Time.deltaTime * 150);
		neptune.RotateAround(this.transform.position, new Vector3(3, 10, 0), 22 * Time.deltaTime);
		neptune.Rotate(Vector3.up * Time.deltaTime * 140);
		earthclone.RotateAround(this.transform.position, new Vector3(1, 10, 0), 30 * Time.deltaTime);
		moon.transform.RotateAround (earthclone.transform.position, new Vector3(1, 12, 0), 50 * Time.deltaTime);
	}
}

The priest and the devil mini game

game instructions

Priests and Devils
Priests and Devils is a puzzle game in which you will help the Priests and Devils " to cross the river within the time limit . There are 3 priests and 3 devils at one side of the river . They all want to get to the other Side of this river but there is only one boat and this boat can only carry two persons each time . And there must be one person steering the boat from one side to the other side . In the flash game . you can click on them to move them and click the go button to move the boat to the other direction . If the priests are out numbered by the devils on either side of the river , they get killed and the game is over . You can try it in many ways . Keep all priests alive ! Good luck !

  1. things mentioned in the game

The priest, the devil, the boat, the river, the banks on both sides.

  1. List the player's actions in a table
action Effect condition
The player clicks on the shore character character on board 1. The ship has a position 2. The characters are on the same shore 3. No other characters are moving
The player clicks on the character on the boat character disembark 1. The boat has reached shore 2. No other characters are moving
player clicks on ship boat moves to opposite shore 1. Any character on board 2. No other characters are moving
Player clicks to restart All characters reset
  1. Make each character object a prefab.

Use a ball with a priest texture to represent a priest, and a square with a demon texture to represent a demon.

insert image description here

  1. Load the objects in the game in the scene controller LoadResources method

scene controller

insert image description here

The corresponding LoadResources code is as follows

public void LoadResources(){
        //由于有重新开始按钮,所以如果不是第一次加载得把之前的物体摧毁
        if(flag){
            for(int i = 0; i < 6; i++){
                if(roleCtrl_list[i] != null){
                    Destroy(roleCtrl_list[i].GetModelGameObject());
                }
            }
            for(int i = 0; i < 2; i++){
                if(landCtrl_list[i] != null){
                    Destroy(landCtrl_list[i].GetModelGameObject());
                }
            }
            if(BoatCtrl != null){
                Destroy(BoatCtrl.GetModelGameObject());
            }
        }
        // 加载控制器和模型
        BoatCtrl = new BoatController();
        BoatCtrl.CreateModel();
        water1=new Water(new Vector3(0,-3.5f,12));
        for(int i = 0; i < 6; i++){
            int roleType = (i < 3) ? PRIEST : DEVIL;
            RoleController tmp=new RoleController(roleType, rolesID[i]);
            roleCtrl_list.Add(tmp);
            roleCtrl_list[i].CreateModel();
        }
        LandController tmp1 = new LandController(LEFTLAND, rolesID);
        landCtrl_list.Add(tmp1);
        LandController tmp2 = new LandController(RIGHTLAND, rolesID);
        landCtrl_list.Add(tmp2);
        landCtrl_list[0].CreateModel();
        landCtrl_list[1].CreateModel();
        MoveCtrl = new MoveController();
        flag=true;
        flag1=false;
        //开始游戏
        gameState = PLAYING;
    }

    //将角色的ID转换成数组的下标
    int IDToNumber(int ID){
        for(int i = 0; i < 6; i++){
            if(rolesID[i] == ID){
                return i;
            }
        }
        return -1;
    }

    //点击船时执行
    public void MoveBoat(){
        if(BoatCtrl.getEmptySeat()==0)
        {
            flag1=true;
        }
        else{
            if(gameState != PLAYING || MoveCtrl.IsMoving()) return;
            CheckAndSetGameState();
            if(BoatCtrl.onLeftside){
                MoveCtrl.SetMove(BoatCtrl.GetModelGameObject(), Position.boatRightPos);
                for(int i = 0; i < 2; i++){
                    if(BoatCtrl.seat[i] != -1){
                        RoleController r = roleCtrl_list[IDToNumber(BoatCtrl.seat[i])];
                        MoveCtrl.SetMove(r.GetModelGameObject(), Position.seatRightPos[i]);
                    }
                }
            }
            else{
                MoveCtrl.SetMove(BoatCtrl.GetModelGameObject(), Position.boatLeftPos);
                for(int i = 0; i < 2; i++){
                    if(BoatCtrl.seat[i] != -1){
                        RoleController r = roleCtrl_list[IDToNumber(BoatCtrl.seat[i])];
                        MoveCtrl.SetMove(r.GetModelGameObject(), Position.seatLeftPos[i]);
                    }
                } 
            }
            BoatCtrl.onLeftside = !BoatCtrl.onLeftside;
        }
    }
  1. Organize objects using the List collection type

    For example, use the list below to organize the character control class and shore control class.

insert image description here

  1. Object generated by code

    before the game

    insert image description here

    after the game starts

insert image description here

  1. Introduce the MVC framework used in this game

    7.1 Models model

    ​ 7.1.1 Click script

    ​ The Click class mainly provides a functional component for other object classes that need to be clicked.

    public class Click : MonoBehaviour
    {
        IObjectController clickAction;
        public void setClickAction(IObjectController clickAction) {
            this.clickAction = clickAction;
        }
        void OnMouseDown() {
            clickAction.DealClick();
        }
    }
    

    7.1.2 Postion class

    ​ The member variables of the Position class are used to store the positions of other objects. To modify the positions of other objects, you only need to modify the member variables in Positon.

    ​ 7.1.3 Other object classes like land and role.

    ​ These classes are mainly for loading prefabricated objects. If the object needs to be clicked, add the above-mentioned Click component, and the events that occur after the click will be defined in detail in the subsequent control. Here we take the Boat class as an example.

    public class Boat
    {
        public GameObject boat;//船对象
        public Boat(Vector3 initPos){
            boat = GameObject.Instantiate(Resources.Load("Prefabs/boat", typeof(GameObject))) as GameObject;
            boat.transform.position = initPos;
            boat.AddComponent<Click>();
        }
    }
    

    7.2 Controller controller

    7.2.1 Director object

    ​ The single instance mode is adopted here, and the Director class is mainly used to obtain the current game scene, manage the global state of the game, and so on. A new Director object will be created at the first call, and no new object will be created at subsequent calls, but the object created at the first call will be returned, so there will only be one Director globally, which is convenient for global management.

public class SSDirector : System.Object
{
    static SSDirector _instance;
    public ISceneController CurrentSceneController {get; set;}
    public static SSDirector GetInstance() {
        if (_instance == null) {
            _instance = new SSDirector();
        }
        return _instance;
    }
}

​ 7.2.2 IUserAction

​ IUserAction is a user object interface for receiving player actions, which separates the player's operations from the internal logic of the game for easy management.

public interface IUserAction {
    void MoveBoat();
    void MoveRole(int id);
    int GetGameState();
    void Restart();
}

​ 7.2.3 ISceneController

​ ISceneController is a scene control interface. This interface separates the control of the director and the scene. The director does not need to know how to implement scene control, but only needs to let the scene control class perform a certain task.

public interface ISceneController
{
    void Initialize();
    void LoadResources();
}

7.2.4 Various object control classes like BoatController and LandController

​ These object control classes need to define the properties of each object and use functions to implement the actions that each object needs to complete. The following takes BoatController as an example, and other object control classes can be consulted in the code.

​ The required properties of the BoatController class:

​ 1. The variable onLeftside of bool type is used to determine whether the ship is on the left bank.

​ 2. The array seat of the List type with a length of 2 is used to record the numbers of the characters at two positions on the ship.

​ 3. The boat class object boatmodel, loaded with prefabricated objects.

​ Actions that need to be completed by the BoatController class:

1.Reset() Reset the seats on the boat.

2.embark(int roleID) Embark the role numbered roleID.

​ 3.getEmptySeat() Get the subscript of the empty seat, if not, return -1.

​ 4. disembark(int roleID) Disembark the role numbered roleID.

5.DealClick() handles the click event.

6. GetModelGameObject() returns the boat object.

7.CreateModel() Create a model.

​ 7.2.5 FirstController

​ FirstController is the core controller. Its main task is to manage all game objects, respond to external events, design the internal logic of the game, etc., and define various events at the same time.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FirstController : MonoBehaviour, ISceneController, IUserAction
{

    public static int LEFTLAND = 0;
    public static int RIGHTLAND = 1;
    public static int BOAT = 2;
    public static bool flag = false;
    public static bool flag1=false;
    public static int PRIEST = 0;
    public static int DEVIL = 1;
    public static int PLAYING = 0;
    public static int WIN = 1;
    public static int FAILED = 2;
    Water water1;
    BoatController BoatCtrl;
    public List<RoleController> roleCtrl_list=new List<RoleController>();
    public List<LandController> landCtrl_list=new List<LandController>();
    MoveController MoveCtrl;

    int[] rolesID = new int[6]{0,1,2,3,4,5};
    int gameState;

    void Awake(){
        SSDirector director = SSDirector.GetInstance();
        director.CurrentSceneController = this;
        director.CurrentSceneController.LoadResources();
    }
    public void Initialize()
    {
        LoadResources();
    }
    public void LoadResources(){
        //由于有重新开始按钮,所以如果不是第一次加载得把之前的物体摧毁
        if(flag){
            for(int i = 0; i < 6; i++){
                if(roleCtrl_list[i] != null){
                    Destroy(roleCtrl_list[i].GetModelGameObject());
                }
            }
            for(int i = 0; i < 2; i++){
                if(landCtrl_list[i] != null){
                    Destroy(landCtrl_list[i].GetModelGameObject());
                }
            }
            if(BoatCtrl != null){
                Destroy(BoatCtrl.GetModelGameObject());
            }
        }
        // 加载控制器和模型
        BoatCtrl = new BoatController();
        BoatCtrl.CreateModel();
        water1=new Water(new Vector3(0,-3.5f,12));
        for(int i = 0; i < 6; i++){
            int roleType = (i < 3) ? PRIEST : DEVIL;
            RoleController tmp=new RoleController(roleType, rolesID[i]);
            roleCtrl_list.Add(tmp);
            roleCtrl_list[i].CreateModel();
        }
        LandController tmp1 = new LandController(LEFTLAND, rolesID);
        landCtrl_list.Add(tmp1);
        LandController tmp2 = new LandController(RIGHTLAND, rolesID);
        landCtrl_list.Add(tmp2);
        landCtrl_list[0].CreateModel();
        landCtrl_list[1].CreateModel();
        MoveCtrl = new MoveController();
        flag=true;
        flag1=false;
        //开始游戏
        gameState = PLAYING;
    }

    //将角色的ID转换成数组的下标
    int IDToNumber(int ID){
        for(int i = 0; i < 6; i++){
            if(rolesID[i] == ID){
                return i;
            }
        }
        return -1;
    }

    //点击船时执行
    public void MoveBoat(){
        if(BoatCtrl.getEmptySeat()==0)
        {
            flag1=true;
        }
        else{
            if(gameState != PLAYING || MoveCtrl.IsMoving()) return;
            CheckAndSetGameState();
            if(BoatCtrl.onLeftside){
                MoveCtrl.SetMove(BoatCtrl.GetModelGameObject(), Position.boatRightPos);
                for(int i = 0; i < 2; i++){
                    if(BoatCtrl.seat[i] != -1){
                        RoleController r = roleCtrl_list[IDToNumber(BoatCtrl.seat[i])];
                        MoveCtrl.SetMove(r.GetModelGameObject(), Position.seatRightPos[i]);
                    }
                }
            }
            else{
                MoveCtrl.SetMove(BoatCtrl.GetModelGameObject(), Position.boatLeftPos);
                for(int i = 0; i < 2; i++){
                    if(BoatCtrl.seat[i] != -1){
                        RoleController r = roleCtrl_list[IDToNumber(BoatCtrl.seat[i])];
                        MoveCtrl.SetMove(r.GetModelGameObject(), Position.seatLeftPos[i]);
                    }
                } 
            }
            BoatCtrl.onLeftside = !BoatCtrl.onLeftside;
        }
    }

    //角色被点击
    public void MoveRole(int id){
        flag1=false;
        int num = IDToNumber(id);
        if(gameState != PLAYING || MoveCtrl.IsMoving()) return;
        int seat;
        switch(roleCtrl_list[num].roleState){
            //角色在左岸的情况
            case 0: 
                if(!BoatCtrl.onLeftside) return;
                landCtrl_list[0].LeaveLand(id);
                seat = BoatCtrl.embark(id);
                roleCtrl_list[num].GoTo(BOAT);
                if(seat == -1) return;
                MoveCtrl.SetMove(roleCtrl_list[num].GetModelGameObject(), Position.seatLeftPos[seat]);
                break;
            //角色在右岸的情况
            case 1: 
                if(BoatCtrl.onLeftside) return;
                landCtrl_list[1].LeaveLand(id);
                seat = BoatCtrl.embark(id);
                roleCtrl_list[num].GoTo(BOAT);
                if(seat == -1) return;
                MoveCtrl.SetMove(roleCtrl_list[num].GetModelGameObject(), Position.seatRightPos[seat]);
                break;
            //角色在船上的情况
            case 2:
                if(BoatCtrl.onLeftside){
                    seat = landCtrl_list[0].getEmptySeat();
                    BoatCtrl.disembark(id);
                    landCtrl_list[0].GoOnLand(id);
                    roleCtrl_list[num].GoTo(LEFTLAND);
                    MoveCtrl.SetMove(roleCtrl_list[num].GetModelGameObject(), Position.roleLeftPos[seat]);
                }
                else{
                    seat = landCtrl_list[1].getEmptySeat();
                    BoatCtrl.disembark(id);
                    landCtrl_list[1].GoOnLand(id);
                    roleCtrl_list[num].GoTo(RIGHTLAND);
                    MoveCtrl.SetMove(roleCtrl_list[num].GetModelGameObject(), Position.roleRightPos[seat]);
                }
                break;
            default: break;
        }
    }

    //判断游戏状态
    public void CheckAndSetGameState(){
        if(gameState != PLAYING) return;
        //失败的情况
        int[,] rolePos = new int[2, 3]{
   
   {0, 0, 0}, {0, 0, 0}};
        foreach(RoleController r in roleCtrl_list){
            rolePos[r.roleType, r.roleState]++;
        }
        if((rolePos[0,0]>0 && rolePos[0,0]<rolePos[1,0]) ||  (rolePos[0,1]>0 && rolePos[0,1]<rolePos[1,1]) ||(rolePos[0,2]>0 && rolePos[0,2] < rolePos[1,2])){
            gameState = FAILED;
            return;
        }  
        //成功的情况
        foreach(RoleController r in roleCtrl_list){
            if(r.roleType == 0 && r.roleState != RIGHTLAND){
                return;
            }
        }
        gameState = WIN;
        return;
    }

    //重置
    public void Restart(){
        LoadResources();
        gameState = PLAYING;
    }

    //获取游戏当前状态
    public int GetGameState(){
        return gameState;
    }
}

7.3 View view

​ UserGUI is the user program interface, which is used to present the game screen and various buttons to the user.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UserGUI : MonoBehaviour
{
    IUserAction userAction;
    GUIStyle msgStyle, titleStyle;
    void Start()
    {
        userAction = SSDirector.GetInstance().CurrentSceneController as IUserAction;

        msgStyle = new GUIStyle();
        msgStyle.normal.textColor = Color.red;
        msgStyle.alignment = TextAnchor.MiddleCenter;
        msgStyle.fontSize = 30;

        titleStyle = new GUIStyle();
        titleStyle.normal.textColor = Color.black;
        titleStyle.alignment = TextAnchor.MiddleCenter;
        titleStyle.fontSize = 40;
    }

    // Update is called once per frame
    void OnGUI() {
        // 重新开始的按钮
        if(GUI.Button(new Rect(Screen.width*0.4f, Screen.height*0.85f, Screen.width*0.2f, Screen.height*0.1f), "重新开始")){
            userAction.Restart();
        }
        // 检查是否正确
        GUI.Label(new Rect(0, 0, Screen.width, Screen.height*0.2f), "牧师与恶魔", titleStyle);
        if(userAction.GetGameState() == FirstController.WIN){
            GUI.Label(new Rect(0, Screen.height*0.2f, Screen.width, Screen.height*0.2f), "成功", msgStyle);
        }     
        else if(userAction.GetGameState() == FirstController.FAILED){
            GUI.Label(new Rect(0, Screen.height*0.2f, Screen.width, Screen.height*0.2f), "失败", msgStyle);
        }
        if(FirstController.flag1==true)
        {
            GUI.Label(new Rect(0, Screen.height*0.2f, Screen.width, Screen.height*0.2f), "船为空,不能行动", msgStyle);
        }
    }
}

game screen

insert image description here
code address my warehouse

Guess you like

Origin blog.csdn.net/weixin_52801288/article/details/127373917
Recommended