(3d游戏编程第二次作业)简答题与牧师与魔鬼

5 篇文章 0 订阅
4 篇文章 0 订阅

代码

简答题

问题一

游戏对象运动的本质是什么
游戏对象运动的本质是游戏对象transform属性的position、rotation和scale等属性的变化。

问题二

请用三种以上的方法实现物体的抛物运动。
1.使用Vector3.MoveTowards方法
完整代码

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

public class movewithMoveTowards : MonoBehaviour {
    private Vector3 g;
    private Vector3 vy;
    private Vector3 vx;
    private float step;
    // Use this for initialization
    void Start () {
        step = Time.deltaTime;
        g = new Vector3(0, 9.8f, 0);
        vy = new Vector3(0, 50, 0);
        vx = new Vector3(0, 0, 30);
    }

    // Update is called once per frame
    void FixedUpdate () {
        Vector3 target;
        target = this.transform.position + (vy + vx) * step; 
        this.transform.position=Vector3.MoveTowards(this.transform.position, target, step);
        vy -= g * step;
        Debug.Log(transform.position.ToString());
    }
}

2.使用transform.Translate方法

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

public class movewithTranslate : MonoBehaviour {
    private Vector3 g;
    private Vector3 vy;
    private Vector3 vx;
    private float step;
    // Use this for initialization
    void Start()
    {
        step = Time.deltaTime;
        g = new Vector3(0, 9.8f, 0);
        vy = new Vector3(0, 50, 0);
        vx = new Vector3(0, 0, 3);
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        Vector3 target = (vy + vx) * step;
        transform.Translate(target);
        vy -= g * step;
        Debug.Log(transform.position.ToString());
    }
}

3.使用rigidbody

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

public class movewithGravity : MonoBehaviour {

    Rigidbody rb;
    // Use this for initialization
    void Start () {
        Physics.gravity = new Vector3(0, -9.8f, 0);
        rb = this.GetComponent<Rigidbody>();
        rb.velocity = new Vector3(0, 20, 10);
    }

    // Update is called once per frame
    void FixedUpdate () {
        Debug.Log(transform.position.ToString());
    }
}

问题三

写一个程序,实现一个完整的太阳系,其他星球围绕太阳的转速必须不一样,且不在一个法平面上。
碰到了一个问题:rotateAround的原理与预期目标不太相符合。rotateAround接受三个参数:原点坐标origin,法线向量axis和环绕速度,其行为本质是以物体所在的点作一个与法线向量正交的平面,以法线向量在该平面的垂点作圆周运动。这样就有一个问题:圆周运动的点与原点坐标不重合。
我所使用的方法是先压缩维度,将变化维度局限在xy平面上;再作一条向量与法线向量垂直,通过计算直接算出以原点坐标为圆周运动圆心所需要的物体坐标,然后变化物体。
同时出于科学考虑,使用开普勒第三定律来决定行星物体的运动速度。
主体部分代码(planetMove.cs)

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

public class planetMove : MonoBehaviour {

    public Transform origin;
    public float speed;
    float ry,rx;
    float px,py;
    const int Kepler = 8000;//利用开普勒第三定律算得物体线速度的平方与半径的乘积是一个常数

    // Use this for initialization
    void Start () {
        origin = GameObject.Find ("sun").transform;
        rx = Random.Range (10, 50);
        ry = Random.Range (10, 50);
        Debug.Log (this.transform.name.ToString()+":"+rx.ToString()+" "+ry.ToString());

        float nx,ny;
        nx = 1;
        ny = -1 * rx / ry;
        float dist = Vector3.Distance (origin.position, this.transform.position);
        float ratio = dist / Mathf.Sqrt (ny * ny + 1);
        px = 1 * ratio;
        py = ny * ratio;
        this.transform.position = new Vector3 (px, py, 0);

        speed = Mathf.Sqrt (Kepler / dist);
    }

    // Update is called once per frame
    void Update () {
        Vector3 axis = new Vector3 (rx, ry, 0);
        this.transform.RotateAround (origin.position, axis, speed * Time.deltaTime);
        this.transform.Rotate (0,50 * Time.deltaTime, 0);
    }
}

牧师与魔鬼

问题描述

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!

牧师与魔鬼是一个十分有趣的益智游戏。你需要帮助牧师与魔鬼在规定的时间限制内过河。在河的一边有三个牧师和三个魔鬼,他们都想要到河的对岸去。但是河里只有一艘船,而且一次只能够运送两个人。并且,每次都必须有一个人将船从河的一头开到另一头。在实际游戏中,你可以通过点击来移动它们上传并且点击go按钮来将船移动到对岸。如果牧师的数量少于魔鬼,它们就会被吃掉。你可以进行多次尝试。记得保证所有的牧师存活。祝你好运!

玩家动作表

| 玩家动作 | 效果 |
|—|—|
点击魔鬼/点击牧师| 上岸 或者 上船,有可能导致游戏胜利
点击船 | 移动,可能会改变游戏状态
点击restart按钮 | 重新开始游戏

参考资料

MVC结构的实现参考了博客:https://www.jianshu.com/p/07028b3da573

具体代码说明

1.初始化:通过FirstController实现接口类ISceneController的方法来进行资源加载

    void Awake()
    {
        //导演单例模式加载
        SSDirector director = SSDirector.getInstance();
        director.currentSceneController = this;
        userInterface = gameObject.AddComponent<UserInterface>() as UserInterface;
        this.LoadResources();
    }

    public void LoadResources()
    {
        GameObject water = Instantiate(Resources.Load("Prefabs/water",typeof(GameObject))) as GameObject;
        fromCoast = new CoastController(0,new Vector3(0,0,0));
        toCoast = new CoastController(1, new Vector3(12, 0, 0));
        boat = new BoatController();

        characters = new ICharacterController[6];
        for(int i=0;i<3;i++)
        {
            characters[i] = new ICharacterController(i,"priest",new Vector3((float)2.5-i,(float)1.25,0));
        }
        for(int i=3;i<6;i++)
        {
            characters[i] = new ICharacterController(i, "devil", new Vector3((float)2.5 - i, (float)1.25, 0));
        }
        fromCoast.initStorage(characters);
        /*
        Debug.Log("check whether:" + (fromCoast.storage.characterStorage[0] == fromCoast.storage.characterStorage[1]));
        for(int i=0;i<6;i++)
        {
            Debug.Log(fromCoast.storage.characterStorage[i].character.name);
        }*/
    }

2.点击事件实现:点击物体、船的时候会有移动,会伴随着数据的改变。
使用接口类IUserAction来规范类协议,然后使用在类UserClick中实现接口类

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

public class UserClick : UnityEngine.EventSystems.EventTrigger {
    IUserAction action;
    ICharacterController characterController;
    public void setController(ICharacterController character)
    {
        characterController = character;
    }

    private void Start()
    {
        action = SSDirector.getInstance().currentSceneController as IUserAction;
    }

    private void OnMouseDown()
    {


        //Debug.Log("onmousedown!");
        if (characterController==null)
        {
            action.moveBoat();
        }
        else
        {
            action.clickCharacter(characterController);
        }
    }
}

具体实现在FirstController中

    public void moveBoat()
    {
        if (userInterface.status != 0)
            return;

        //Debug.Log("boat");
        boat.move();
        if(boat.boatStatus == 0)//需要检查船移动是否造成游戏结束
        {
            if(fromCoast.check_over(boat) || toCoast.check_over())
            {
                userInterface.status = 1;
            }
        }
        else
        {
            if(fromCoast.check_over()|| toCoast.check_over(boat))
            {
                userInterface.status = 1;
            }

        }
    }
    public void clickCharacter(ICharacterController charctrl)
    {
        //legal check
        if((charctrl.place == "from" && boat.boatStatus == 1) || (charctrl.place == "to" && boat.boatStatus == 0))
        {
            return;
        }
        if (userInterface.status != 0)
            return;
        if (boat.boatFull()&&charctrl.onBoat == false)
            return;

        //Debug.Log(charctrl.character.name);
        CoastController whichCoast;
        if (boat.boatStatus == 0)
        {
            whichCoast = fromCoast;
        }
        else
        {
            whichCoast = toCoast;
        }
        //Debug.Log("check coastcontroller " + whichCoast.coast.name);
        //Debug.Log("check boatcontroller " + boat.boat.name);

        //检查是否合法

        //备注:上船与下船不对称,上船时船负责提供运动终点,下船时岸负责提供运动终点
        if (charctrl.onBoat == false)//上船的过程
        {
           // Debug.Log("function clickCharacter ready to go on boat with parameter:" + charctrl.character.name);
            whichCoast.OffCoast(charctrl);//离岸
            boat.OnBoat(charctrl);
        }
        else
        {
           // Debug.Log("function clickCharacter ready to go off boat with parameter:" + charctrl.character.name);
            whichCoast.OnCoast(charctrl,boat.boatStatus);//下船上岸
            boat.OffBoat(charctrl);
        }

        int flag = checkGameOver();
        Debug.Log("check game over:" + flag);
        if(flag == 1)
        {
            userInterface.status = 2;
        }
        else if(flag == -1)
        {
            userInterface.status = 1;
        }
    }

3.维护岸上成员的数据结构
随便写了个数组

   //用于河岸控制器的储存结构
    public class CoastStorage
    {
        public ICharacterController[] characterStorage;
        public CoastStorage()
        {
            characterStorage = new ICharacterController[6];
        }

        public bool isFull()
        {
            int counter = 0;
            for(int i=0;i<6;i++)
            {
                if (characterStorage[i] != null)
                    counter++;
            }
            if (counter == 6)
                return true;
            else
                return false;
        }
        //返回值是插入的位置
        public int insert(ICharacterController element)
        {/*
            Debug.Log("class storage in function insert");
            Debug.Log("output all element");
            for(int i=0;i<6;i++)
            {
                if (characterStorage[i] == null)
                    Debug.Log("null");
                else
                {
                    Debug.Log(element.character.name);
                }
            }*/

            if (this.isFull())
                return -1;

            for(int i=0;i<6;i++)
            {
                if(characterStorage[i]==null)
                {
                    characterStorage[i] = element;
                    return i;
                }
            }
            return -1;
        }

        public ICharacterController getCharacter(int pos)
        {
            if (pos < 0 || pos >= 6)
                return null;
            else
            {
                return characterStorage[pos];
            }
        }
        public bool remove(int pos)
        {
            if(characterStorage[pos]!=null)
            {
                characterStorage[pos] = null;
                return true;
            }
            else
                return false;
        }
        public void delete(ICharacterController character)
        {
            //Debug.Log("class CoastStorage in function delete with parameter:" + character.ToString());
            for(int i=0;i<6;i++)
            {
                if (characterStorage[i] == null)
                    continue;
                else if(characterStorage[i] == character)
                {
                    characterStorage[i] = null;
                    return;
                }
            }
        }
        public void clear()
        {
            characterStorage = new ICharacterController[6];
        }

        public bool check_over(BoatController boat)
        {
            int priest_num = 0, devil_num = 0;
            for(int i = 0;i<characterStorage.Length;i++)
            {
                if (characterStorage[i] == null)
                    continue;
                else if(characterStorage[i].race == "priest")
                {
                    priest_num++;
                }
                else
                {
                    devil_num++;
                }
            }
            if(boat.frontCharacter!=null)
            {
                if(boat.frontCharacter.race == "priest")
                {
                    priest_num++;
                }
                else
                {
                    devil_num++;
                }
            }
            if(boat.backCharacter!=null)
            {
                if (boat.backCharacter.race == "priest")
                {
                    priest_num++;
                }
                else
                {
                    devil_num++;
                }
            }
            Debug.Log("Coast check with " + priest_num + " priests and " + devil_num + " devils");
            if (devil_num > priest_num && priest_num != 0)
                return true;
            else
                return false;
        }
        public bool check_over()
        {
            int priest_num = 0, devil_num = 0;
            for (int i = 0; i < characterStorage.Length; i++)
            {
                if (characterStorage[i] == null)
                    continue;
                else if (characterStorage[i].race == "priest")
                {
                    priest_num++;
                }
                else
                {
                    devil_num++;
                }
            }
            Debug.Log("Coast check with " + priest_num + " priests and " + devil_num + " devils");
            if (devil_num > priest_num && priest_num != 0)
                return true;
            else
                return false;
        }
    }

4.上船与下船的问题。
考虑到上船的时候位置由船提供,下船的时候位置由岸提供,所以原则上谁提供位置谁调用脚本
BoatController中的上下船

        //OnBoat和OffBoat,负责操控船的数据结构,同时负责管理移动
        public void OnBoat(ICharacterController element)
        {
            if(this.boatFull())
            {
                return;
            }

            if (boatStatus == 0)//从from向to,front为前
            {
                if (frontCharacter == null)
                {
                    //Debug.Log("from->to:front element in boat");
                    frontCharacter = element;
                    element.character.transform.parent = boat.transform;
                    element.moveOnBoat(boat.transform.position, boatStatus, front);
                }
                else
                {
                    //Debug.Log("from->to:back element in boat");
                    backCharacter = element;
                    element.character.transform.parent = boat.transform;
                    element.moveOnBoat(boat.transform.position, boatStatus, back);
                }
            }
            else // 从to开向from,back为前
            {
                if (backCharacter == null)
                {
                    //Debug.Log("to->from:back element in boat");
                    backCharacter = element;
                    element.character.transform.parent = boat.transform;
                    element.moveOnBoat(boat.transform.position, boatStatus, back);
                }
                else
                {
                    //Debug.Log("to->from:front element in boat");
                    frontCharacter = element;
                    element.character.transform.parent = boat.transform;
                    element.moveOnBoat(boat.transform.position, boatStatus, front);
                }
            }
        }

        //下船需要对岸支持
        public void OffBoat(ICharacterController element)
        {
            element.character.transform.parent = null;
            if(frontCharacter == element)
            {
                frontCharacter = null;
            }
            else
            {
                backCharacter = null;
            }
        }

CoastController中的上下船

        public int OnCoast(ICharacterController character,int boatStatus)
        {
            if (storage.isFull())
                return -1;
            else
            {
                int pos=storage.insert(character);
                //Debug.Log("Oncoast with position " + pos.ToString());
                Vector3 relativeVec;
                if(coast.name=="from_coast")
                {
                    relativeVec = new Vector3(2.5f - pos, 1.25f, 0);
                }
                else
                {
                    relativeVec = new Vector3(-2.5f + pos, 1.25f, 0);
                }
                character.moveOffBoat(coast.transform.position,boatStatus,relativeVec);
                return pos;
            }
        }
        public bool OffCoast(int pos)
        {
            //Debug.Log("In function OffCoast with parameter:" + pos.ToString());
            bool flag = storage.remove(pos);
            return flag;
        }
        public void OffCoast(ICharacterController Mycharacter)
        {
            //Debug.Log("In function OffCoast 2 with parameter:" + Mycharacter.character.ToString());
            //Debug.Log("check storage:" + (storage == null));
            storage.delete(Mycharacter);
        }

ICharacterController中的上下船

        //上船的动作,不进行检查
        public void moveOnBoat(Vector3 pos,int boatStatus,Vector3 relativeMove)//type为在船前或船后
        {
            place = "boat";
            //Debug.Log("moveOnBoat");
            onBoat = true;
            if(boatStatus == 0)
            {
                movescript.Move(frontmiddle1);
                movescript.Move(frontmiddle2);
            }
            else
            {
                movescript.Move(backmiddle1);
                movescript.Move(backmiddle2);
            }
            movescript.Move(pos + relativeMove);


        }
        public void moveOffBoat(Vector3 pos, int boatStatus, Vector3 relativeMove)//type为在船前或船后
        {
            //Debug.Log("moveOffBoat");
            onBoat = false;
            if(boatStatus == 0)
            {
                movescript.Move(frontmiddle2);
                movescript.Move(frontmiddle1);
                place = "from";
            }
            else
            {
                movescript.Move(backmiddle2);
                movescript.Move(backmiddle1);
                place = "to";
            }
            movescript.Move(pos+relativeMove);
        }

5.检查胜利

    public int checkGameOver()
    {
        Debug.Log("check for game over");

        if(boat.boatStatus == 0)
        {
            if(fromCoast.check_over(boat)||toCoast.check_over())
            {
                return -1;
            }
        }
        else
        {
            Debug.Log("to coast check");
            if(fromCoast.check_over()||toCoast.check_over(boat))
            {
                return -1;
            }
        }

        if(toCoast.check_win())
        {
            return 1;
        }

        return 0;
    }

        public bool check_over(BoatController boat)
        {
            int priest_num = 0, devil_num = 0;
            for(int i = 0;i<characterStorage.Length;i++)
            {
                if (characterStorage[i] == null)
                    continue;
                else if(characterStorage[i].race == "priest")
                {
                    priest_num++;
                }
                else
                {
                    devil_num++;
                }
            }
            if(boat.frontCharacter!=null)
            {
                if(boat.frontCharacter.race == "priest")
                {
                    priest_num++;
                }
                else
                {
                    devil_num++;
                }
            }
            if(boat.backCharacter!=null)
            {
                if (boat.backCharacter.race == "priest")
                {
                    priest_num++;
                }
                else
                {
                    devil_num++;
                }
            }
            //Debug.Log("Coast check with " + priest_num + " priests and " + devil_num + " devils");
            if (devil_num > priest_num && priest_num != 0)
                return true;
            else
                return false;
        }
        public bool check_over()
        {
            int priest_num = 0, devil_num = 0;
            for (int i = 0; i < characterStorage.Length; i++)
            {
                if (characterStorage[i] == null)
                    continue;
                else if (characterStorage[i].race == "priest")
                {
                    priest_num++;
                }
                else
                {
                    devil_num++;
                }
            }
            //Debug.Log("Coast check with " + priest_num + " priests and " + devil_num + " devils");
            if (devil_num > priest_num && priest_num != 0)
                return true;
            else
                return false;
        }

12个小时,git log日志纪念

吴天扬@LAPTOP-K5CSLAA6 MINGW64 /e/code/homework_for2018/3dGameProgramming/Week4/Priests_and_Devils/Assets/Scripts (master)
$ git log
commit 8f168a15c3a802b287f010277653b0959c97f7b3 (HEAD -> master)
Author: wtysos11 <wtysos11@163.com>
Date:   Mon Apr 2 21:02:04 2018 +0800

    solve a bug with click in one coast will cause game over

commit 9d12dd47cb32680d4caf4ae96daa9bc764af2be9
Author: wtysos11 <wtysos11@163.com>
Date:   Mon Apr 2 20:55:42 2018 +0800

    basically complete

commit 8bf57acc7031a2bc2e3be23b30af1bdb3313612c
Author: wtysos11 <wtysos11@163.com>
Date:   Mon Apr 2 20:42:06 2018 +0800

    init complete with many bugs

commit 2690c161513423d8f927a1afc1bd0cd312e3061d
Author: wtysos11 <wtysos11@163.com>
Date:   Mon Apr 2 20:14:47 2018 +0800

    finish check for gameover and win with still many bugs in moving

commit 8bca6dd9feb8fdf23da40cfbe74da3f6346c0620 (origin/master)
Author: wtysos11 <wtysos11@163.com>
Date:   Mon Apr 2 15:47:32 2018 +0800

    all update

commit f88c85331d92cf9b9eefe5a71161ea735abc6458
Author: wtysos11 <wtysos11@163.com>
Date:   Mon Apr 2 15:39:49 2018 +0800

    finish object clicking motion with many bugs, without any check whether the motion is legal or not, especially for the click from another coast!

commit 7bffd85891499bf97cfd56add2be1dd057aef553
Author: wtysos11 <wtysos11@163.com>
Date:   Sun Apr 1 23:00:02 2018 +0800

    finish boat moving, doing character's onBoat moving(not done yet). Working on finish the data structure of the storage of characters on boat.

commit 6081b64a1f488525104b652d3a2c95815d4dc3da
Author: wtysos11 <wtysos11@163.com>
Date:   Sun Apr 1 22:16:27 2018 +0800

    finish click, ready for move

commit 84bbb248aac0e6e4c0b393121a7916b4c806611e
Author: wtysos11 <wtysos11@163.com>
Date:   Sun Apr 1 22:15:35 2018 +0800

    finish click

commit d127a90633f3f539c4d43a9c17a0e86c9dcebbf7
Author: wtysos11 <wtysos11@163.com>
Date:   Sun Apr 1 20:54:00 2018 +0800

    finish drawing origin scene

commit a977ebb64566e8aaadb674dd301aac1d7164ca29
Author: wtysos11 <wtysos11@163.com>
Date:   Sun Apr 1 20:11:04 2018 +0800

    initial MVC structure

commit 709134f356d03d13c3b53f1e96459b0eef348d17
Author: wtysos11 <wtysos11@163.com>
Date:   Sun Apr 1 16:52:21 2018 +0800

    the original form with all prefab

commit 306ff363c527557de67e70667a756045d0f5d390
Author: wtysos11 <wtysos11@163.com>
Date:   Sun Apr 1 14:51:36 2018 +0800

    finish projection motion

commit ad27b03e327522118e393b2a056ad49a866e6556
Author: wtysos11 <wtysos11@163.com>
Date:   Sat Mar 31 12:57:49 2018 +0800

    finish solar system

commit b51e0efaa692067982f74ede047bc90fd40f5f89
Author: wtysos11 <wtysos11@163.com>
Date:   Tue Mar 27 14:58:33 2018 +0800

    some changes in markdown

commit ae55a625d3d3b6bb3d61a05f6e327caf993b548c
Author: wtysos11 <wtysos11@163.com>
Date:   Tue Mar 27 14:48:42 2018 +0800

    finish the report paper

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值