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)

    • 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;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
日落时间-海滩日落-适用于您的浏览器的美丽日落壁纸 LovelyTab的Beautiful Sunset扩展程序。 安装它以获得最大的浏览体验。 免费打开有趣的新闻,事实并玩游戏,同时享受自己喜欢的高清主题和壁纸。 使用方法:-这个美丽的HD Sunset墙纸扩展程序非常简单,只需单击“添加到镶边”,它将自动添加。 -在左上角,单击设置以根据需要自定义所有选项。 -浏览时享受最佳的墙纸和免费小部件单击“添加到Chrome”,即表示我接受并同意安装日落墙纸和日落时间主题(墙纸扩展名)并将“新标签”设置为https://search.lovelytab.com,由服务,使用条款和隐私政策。 使用条款:https://faq.lovelytab.com/page/eula隐私政策:https://faq.lovelytab.com/page/privacy功能:-本地时间选项–无论您身在何处都可以更改-天气会也可以匹配您当前的目的地-使用我们新的日落背景壁纸扩展程序,只需单击一下即可为喜欢的网站添加书签。 -单击左上角的操纵杆可免费玩游戏-阅读相关新闻和有趣的事实-日落高清壁纸和背景扩展程序可让您自定义和添加/删除这些选项。在此扩展程序中,您将找到几乎所有相关背景您可以享受自己喜欢的主题,同人作品,全高清图像,甚至4K素材的浏览。 日落海滩和日出日落如何卸载:-单击Chrome浏览器右上角的水平三个点,转到设置,单击“扩展名”,然后找到要安装的扩展名。 单击垃圾箱图标即是,或-只需右键单击工具栏上的心形按钮,然后单击“从Chrome删除”免责声明:夕阳的墙纸和背景是粉丝为粉丝制作的扩展名,版权属于给材料的各自所有者。 这是非官方的,如果有任何问题,请提醒我们,我们将予以解决。 在https://lovelytab.com上下载具有超赞全高清壁纸的更多免费扩展程序 支持语言:Bahasa Melayu,Deutsch,English,English (UK),English (United States),Français,Nederlands,Norsk,Tiếng Việt,Türkçe,català,dansk,eesti,español,hrvatski,italiano,latviešu,lietuvių,magyar,polski,português (Brasil),português (Portugal),română,slovenský,slovenščina,suomi,svenska,čeština,Ελληνικά,Српски,български,русский,українська,עברית,فارسی‎,हिन्दी,ไทย,‫العربية,中文 (简体),中文 (繁體),日本語,한국어

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值