Unity3D学习笔记(2) 太阳系仿真(SunSet)、牧师与魔鬼(P&D) 第一版(基础 MVC 实现)

牧师与魔鬼(P&D) 第二版(添加动作管理)

游戏对象运动的本质

游戏对象每帧位置的变化

物体的抛物线运动

方法一 修改Transform属性

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

public class 抛物线 : MonoBehaviour {

    private float speed = 10;

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {
        speed -= (float)(9.8 * Time.deltaTime);
        transform.position += Vector3.left * Time.deltaTime * 2;
        transform.position += new Vector3 (0, Time.deltaTime * speed, 0);
    }
}

方法二 使用transform.Translate

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

public class 抛物线 : MonoBehaviour {

    private float speed = 10;

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {
        speed -= (float)(9.8 * Time.deltaTime);
        transform.Translate (Vector3.left * Time.deltaTime * 2);
        transform.Translate (new Vector3 (0, Time.deltaTime * speed, 0));
    }
}

方法三 使用Vector3.Slerp

using UnityEngine;
using System.Collections;

public class 抛物线 : MonoBehaviour {
    public Transform sunrise;
    public Transform sunset;
    public float journeyTime = 1.0F;
    private float startTime;
    void Start() {
        startTime = Time.time;
    }
    void Update() {
        Vector3 center = (sunrise.position + sunset.position) * 0.5F;
        center -= new Vector3(0, 1, 0);
        Vector3 riseRelCenter = sunrise.position - center;
        Vector3 setRelCenter = sunset.position - center;
        float fracComplete = (Time.time - startTime) / journeyTime;
        transform.position = Vector3.Slerp(riseRelCenter, setRelCenter, fracComplete);
        transform.position += center;
    }
}

方法四 使用Rigidbody组件

利用其useGravity属性给物体添加重力

实现一个完整的太阳系

https://gitee.com/Ernie1/unity3d-learning/tree/master/hw2/太阳系

其他星球围绕太阳的转速必须不一样,且不在一个法平面上。
这里写图片描述

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

public class RoundSun :MonoBehaviour {
    public Transform sun;
    public Transform mercury;
    public Transform venus;
    public Transform earth;
    public Transform earthShadow;
    public Transform moon;
    public Transform mars;
    public Transform jupiter;
    public Transform saturn;
    public Transform uranus;
    public Transform neptune;

    private Vector3 ax1, ax2, ax3, ax4 , ax5, ax6, ax7;

    void Start(){
        ax1 = new Vector3 (Random.Range (-1F, 1F), Random.Range (-1F, 1F), Random.Range (-1F, 1F));
        ax2 = new Vector3 (Random.Range (-1F, 1F), Random.Range (-1F, 1F), Random.Range (-1F, 1F));
        ax3 = new Vector3 (Random.Range (-1F, 1F), Random.Range (-1F, 1F), Random.Range (-1F, 1F));
        ax4 = new Vector3 (Random.Range (-1F, 1F), Random.Range (-1F, 1F), Random.Range (-1F, 1F));
        ax5 = new Vector3 (Random.Range (-1F, 1F), Random.Range (-1F, 1F), Random.Range (-1F, 1F));
        ax6 = new Vector3 (Random.Range (-1F, 1F), Random.Range (-1F, 1F), Random.Range (-1F, 1F));
        ax7 = new Vector3 (Random.Range (-1F, 1F), Random.Range (-1F, 1F), Random.Range (-1F, 1F));
    }
    void Update () {
        mercury.RotateAround (sun.position, ax1, 120 * Time.deltaTime);
        venus.RotateAround (sun.position, ax2, 110 * Time.deltaTime);
        earth.RotateAround(sun.position, new Vector3(0,2,0),100 * Time.deltaTime) ;
        earth.Rotate (Vector3.up * 30 * Time.deltaTime);
        moon.transform.RotateAround(earthShadow.position,Vector3.up,359 * Time.deltaTime);
        mars.RotateAround (sun.position, ax3, 90 * Time.deltaTime);
        jupiter.RotateAround (sun.position, ax4, 80 * Time.deltaTime);
        saturn.RotateAround (sun.position, ax5, 70 * Time.deltaTime);
        uranus.RotateAround (sun.position, ax6, 60 * Time.deltaTime);
        neptune.RotateAround (sun.position, ax7, 50 * Time.deltaTime);
    }
}

需要在组件窗口手动设置其它星球的position和scale,再给每个星球加上Trailer Render组件画出运动轨迹。

编程实践

https://gitee.com/Ernie1/unity3d-learning/tree/master/hw2/牧师与魔鬼%20第一版

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!

示例
这里写图片描述

  • 游戏中提及的事物(Objects)

    扫描二维码关注公众号,回复: 1216203 查看本文章
    • bankHere
    • bankThere
    • boat
    • water
    • priest
    • devil
  • 玩家动作表(规则表)

    动作 规则
    上船 船上有空位
    开船 船上有人
    下船 转移到船所在的岸上
  • 面向对象的编程架构
    这里写图片描述

  • 导演的职责

    • 获取当前游戏的场景
    • 控制场景运行、切换、入栈与出栈
    • 暂停、恢复、退出
    • 管理游戏全局状态
    • 设定游戏的配置
    • 设定游戏全局视图
//SSDirector.cs
using System.Collections;  
using System.Collections.Generic;  
using UnityEngine;  

public interface ISceneController  
{  
    void LoadResources();
    void Pause (); 
    void Resume ();
    void Restart ();
    void GameOver ();
}  

public class SSDirector : System.Object  
{  
    private static SSDirector _instance;

    public ISceneController currentScenceController { get; set; }  
    public bool running { get; set; }

    public static SSDirector getInstance()  
    {  
        if (_instance == null)  
        {  
            _instance = new SSDirector();  
        }  
        return _instance;  
    }  

    public int getFPS()  
    {  
        return Application.targetFrameRate;  
    }  

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

}  
  • 场记的职责
    • 管理本次场景所有的游戏对象
    • 协调游戏对象(预制件级别)之间的通讯
    • 响应外部输入事件
    • 管理本场次的规则(裁判)
    • 杂务
//FirstController.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FirstController : MonoBehaviour, ISceneController, IUserAction {

    private GameObject objectClicked;

    bool[] boatSeat;

    private bool someObjectHandling, pausing;
    private int handleNum;
    private int sailTo;

    private SSDirector director;
    private UserGUI userGUI;
    private Model model;

    void Awake () {
        model = Model.getInstance ();

        userGUI = gameObject.AddComponent<UserGUI> ();
        userGUI.action = this;

        director = SSDirector.getInstance ();
        director.currentScenceController = this;
        director.setFPS (60);
        director.currentScenceController.LoadResources ();
    }

    // 对ISceneController的实现
    public void LoadResources () {

        boatSeat = new bool[]{ true, true };
        someObjectHandling = false;

        model.GenGameObjects();

        pausing = false;
        userGUI.status = 2;
    }

    public void Pause () {
        pausing = true;
        userGUI.status = 3;
    }

    public void Resume () {
        pausing = false;
        userGUI.status = 2;
    }

    public void Restart () {
        model.destroy ();
        LoadResources ();
    }

    public void GameOver () {
        pausing = true;
    }

    void Start () {

    }

    void handleClickedObject () {
        handleNum = -1;
        //boat
        if (model.isBoat (ref objectClicked)) {
            if (someoneOnBoat ()) {             
                handleNum = 0;
                sailTo = 1 - model.whereBoat ();
            } else
                someObjectHandling = false;
            return;
        }
        model.setJumpFromObject (ref objectClicked);
        //priest
        int index = model.whichPriest(ref objectClicked);
        if (index != -1) {
            if (model.wherePriest (index) == 2) {
                model.setJumpToPriest (index);
                boatSeat [model.whichSeatByPosition (ref objectClicked)] = true;
                handleNum = 1;
            } else if (model.wherePriest (index) == model.whereBoat () && whereCanSit () != 2) {
                model.setJumpToSeat (whereCanSit ());
                boatSeat [whereCanSit ()] = false;
                handleNum = 2;
            } else
                someObjectHandling = false;
            return;
        }
        //devil
        index = model.whichDevil(ref objectClicked);
        if (index != -1) {
            if (model.whereDevil (index) == 2) {
                model.setJumpToDevil (index);
                boatSeat [model.whichSeatByPosition (ref objectClicked)] = true;
                handleNum = 1;
            }
            else if (model.whereDevil (index) == model.whereBoat () && whereCanSit () != 2) {
                model.setJumpToSeat (whereCanSit ());
                boatSeat [whereCanSit ()] = false;
                handleNum = 2;
            } else
                someObjectHandling = false;
            return;
        }
        //其它不管
        someObjectHandling = false;
    }


    int whereCanSit() {
        if (boatSeat [0])
            return 0;
        if (boatSeat [1])
            return 1;
        return 2;
    }

    bool someoneOnBoat () {
        if(boatSeat[0]&&boatSeat[1])
            return false;
        return true;
    }

    //0 lose 1 win 2 -
    int checkGame () {
        int priestHere = 0, priestThere = 0, devilHere = 0, devilThere = 0;
        for(int i=0;i<3;++i){
            if (model.wherePriest (i) == 0)
                ++priestHere;
            else if (model.wherePriest (i) == 1)
                ++priestThere;
            else if (model.whereBoat () != 2) {
                if (model.whereBoat () == 0)
                    ++priestHere;
                else
                    ++priestThere;
            }
            if (model.whereDevil (i) == 0)
                ++devilHere;
            else if (model.whereDevil (i) == 1)
                ++devilThere;
            else if (model.whereBoat () != 2) {
                if (model.whereBoat () == 0)
                    ++devilHere;
                else
                    ++devilThere;
            }
        }
        if ((priestHere > 0 && priestHere < devilHere) || (priestThere > 0 && priestThere < devilThere))
            return 0;
        if (priestThere == 3 && devilThere == 3)
            return 1;
        return 2;
    }

    // Update is called once per frame
    void Update () {
        if (!pausing) {
            if (!someObjectHandling && userGUI.action.checkObjectClicked ())
                handleClickedObject ();
            if (someObjectHandling) {
                if (handleNum == 0)
                    someObjectHandling = model.sailing (sailTo);
                if (handleNum == 1) {
                    someObjectHandling = model.jumping (ref objectClicked, 0);
                }
                if (handleNum == 2) {
                    someObjectHandling = model.jumping (ref objectClicked, 1);
                }
            }
            userGUI.status = checkGame ();
        }
    }

    void IUserAction.GameOver () {
        director.currentScenceController.GameOver ();
    }

    void IUserAction.Pause () {
        director.currentScenceController.Pause ();
    }

    void IUserAction.Resume () {
        director.currentScenceController.Resume ();
    }

    void IUserAction.Restart () {
        director.currentScenceController.Restart ();
    }

    bool IUserAction.checkObjectClicked(){
        if(Input.GetMouseButton(0)) {
            Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
            RaycastHit hit ;
            if(Physics.Raycast (ray,out hit)) {
                objectClicked = hit.collider.gameObject;
                someObjectHandling = true;
                return true;
            }
        }
        return false;
    }
}
  • 用户界面
    • 显示交互界面
    • 获取交互信息
    • 响应用户操作
//UserGUI.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface IUserAction
{  
    void Restart ();
    void GameOver ();
    void Pause ();
    void Resume ();
    bool checkObjectClicked ();
}

public class UserGUI : MonoBehaviour {

    public IUserAction action;
    public int status;

    void Awake () {

    }

    void Start () {

    }

    void Update () {

    }

    void OnGUI () {
        float width = Screen.width / 6;
        float height = Screen.height / 12;
        if (status == 0) {
            action.GameOver ();
            if (GUI.Button (new Rect (Screen.width / 2 - width / 2, Screen.height / 2 - height / 2, width, height), "Game Over!\nRestart")) {
                action.Restart ();
            }
        }
        if (status == 1) {
            action.GameOver ();
            if (GUI.Button (new Rect (Screen.width / 2 - width / 2, Screen.height / 2 - height / 2, width, height), "Win!\nRestart")) {
                action.Restart ();
            }
        }
        if (status == 2) {
            if (GUI.Button (new Rect (Screen.width / 2 - width / 2, Screen.height / 2 - height / 2, width, height), "Pause")) {
                action.Pause ();
            }
            if (GUI.Button (new Rect (Screen.width / 2 - width / 2, Screen.height / 2 - height / 2 + height, width, height), "Restart")) {
                action.Restart ();
            }
        }
        if (status == 3) {
            if (GUI.Button (new Rect (Screen.width / 2 - width / 2, Screen.height / 2 - height / 2, width, height), "Resume")) {
                action.Resume ();
            }
            if (GUI.Button (new Rect (Screen.width / 2 - width / 2, Screen.height / 2 - height / 2 + height, width, height), "Restart")) {
                action.Restart ();
            }
        }
    }

}
  • 游戏模型
    • 创建、配置、管理游戏对象
    • 响应场记的请求
//Model.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Model {
    private static Model _instance;

    private GameObject bankHere, bankThere, boat, water;
    private GameObject []priest, devil;

    Vector3[] boatPos, onBoat;
    Vector3[,] priestPos, devilPos;

    Vector3 jumpFrom,jumpTo;

    float dTime;
    Vector3 speed, Gravity;

    public static Model getInstance()  
    {  
        if (_instance == null)  
        {  
            _instance = new Model();  
        }  
        return _instance;  
    }

    public void GenGameObjects () {
        boatPos = new Vector3[]{ new Vector3 (2, 0.1F, 0), new Vector3 (-2, 0.1F, 0) };
        onBoat = new Vector3[]{ new Vector3 (-1.5F, 2, 0), new Vector3 (1.5F, 2, 0) };
        priestPos = new Vector3[3, 2];
        devilPos = new Vector3[3, 2];
        for (int i = 0; i < 3; ++i) {
            priestPos [i, 0] = new Vector3 (3.4F + 0.7F * i, 1, 0);
            priestPos [i, 1] = new Vector3 (-6.9F + 0.7F * i, 1, 0);
            devilPos [i, 0] = new Vector3 (5.5F + 0.7F * i, 1, 0);
            devilPos [i, 1] = new Vector3 (-4.8F + 0.7F * i, 1, 0);
        }
        bankHere = GameObject.Instantiate (Resources.Load ("Prefabs/bank"), new Vector3 (5.25F, 0, 0), Quaternion.identity, null) as GameObject;
        bankHere.name = "bankHere";
        bankThere = GameObject.Instantiate (Resources.Load ("Prefabs/bank"), new Vector3 (-5.25F, 0, 0), Quaternion.identity, null) as GameObject;
        bankThere.name = "bankThere";
        boat = GameObject.Instantiate (Resources.Load ("Prefabs/boat"), boatPos [0], Quaternion.identity, null) as GameObject;
        boat.name = "boat";
        water = GameObject.Instantiate (Resources.Load ("Prefabs/water"), new Vector3 (0, -0.25F, 0), Quaternion.identity, null) as GameObject;
        water.name = "water";
        priest = new GameObject[3];
        devil = new GameObject[3];
        for (int i = 0; i < 3; ++i) {
            priest [i] = GameObject.Instantiate (Resources.Load ("Prefabs/priest"), priestPos [i, 0], Quaternion.identity, null) as GameObject;
            priest [i].name = "priest" + i.ToString ();
            devil [i] = GameObject.Instantiate (Resources.Load ("Prefabs/devil"), devilPos [i, 0], Quaternion.identity, null) as GameObject;
            devil [i].name = "devil" + i.ToString ();
        }
    }

    public void destroy () {
        GameObject.Destroy (bankHere);
        GameObject.Destroy (bankThere);
        GameObject.Destroy (boat);
        GameObject.Destroy (water);
        foreach (GameObject e in priest)
            GameObject.Destroy (e);
        foreach (GameObject e in devil)
            GameObject.Destroy (e);
    }

    // 此岸 0,彼岸 1,否则 2
    public int whereBoat () {
        for (int i = 0; i < 2; ++i)
            if (boat.transform.position == boatPos [i])
                return i;
        return 2;
    }

    public int wherePriest (int e) {
        for (int i = 0; i < 2; ++i)
            if (priest [e].transform.position == priestPos [e, i])
                return i;
        return 2;
    }

    public int whereDevil (int e) {
        for (int i = 0; i < 2; ++i)
            if (devil [e].transform.position == devilPos [e, i])
                return i;
        return 2;
    }

    public int whichPriest (ref GameObject g) {
        return Array.IndexOf (priest, g);
    }

    public int whichDevil (ref GameObject g) {
        return Array.IndexOf (devil, g);
    }

    public int whichSeatByPosition (ref GameObject g) {
        if (g.transform.localPosition == onBoat [0])
            return 0;
        if (g.transform.localPosition == onBoat [1])
            return 1;
        return -1;
    }

    void setJump(){
        float ShotSpeed = 10; // 抛出的速度
        float time = Vector3.Distance (jumpFrom, jumpTo) / ShotSpeed;
        float g = -10;
        dTime = 0;
        speed = new Vector3 ((jumpTo.x - jumpFrom.x) / time, (jumpTo.y - jumpFrom.y) / time - 0.5f * g * time, (jumpTo.z - jumpFrom.z) / time);
        Gravity = Vector3.zero;
    }

    public void setJumpFromObject (ref GameObject Object) {
        jumpFrom = Object.transform.position;
        setJump ();
    }

    public void setJumpToSeat (int seatIndex) {
        jumpTo = boat.transform.TransformPoint (onBoat [seatIndex]);
        setJump ();
    }

    public void setJumpToPriest (int index) {
        jumpTo = priestPos [index, whereBoat ()];
        setJump ();
    }

    public void setJumpToDevil (int index) {
        jumpTo = devilPos [index, whereBoat ()];
        setJump ();
    }

    public bool sailing (int sailTo){
        float speed = 1.5F;
        boat.transform.position = Vector3.MoveTowards (boat.transform.position, boatPos [sailTo], speed * Time.deltaTime);
        if (boat.transform.position == boatPos [sailTo])
            //someObjectHandling = false;
            return false;
        return true;
    }

    // mode: 0 ashore 1 aboard
    public bool jumping (ref GameObject Object, int mode) {
        float g = -10;
        Gravity.y = g * (dTime += Time.fixedDeltaTime);// v=gt
        Object.transform.position += (speed + Gravity) * Time.fixedDeltaTime;//模拟位移
        if (Object.transform.position.x - jumpTo.x < 0.5) {
            Object.transform.position = jumpTo;
            if (mode == 0)
                Object.transform.parent = null;
            else
                Object.transform.parent = boat.transform;
            return false;
        }
        return true;
    }

    public bool isBoat (ref GameObject Object) {
        return Object == boat;
    }
}

猜你喜欢

转载自blog.csdn.net/z_j_q_/article/details/79777086