永久免费无代码开发平台网站,wordpress文章索引,wordpress 分类目录导航,寮步网站仿做3D游戏第3次作业#xff08;牧师与魔鬼#xff09;
1.游戏对象运动的本质是什么#xff1f;
对象位置属性#xff0c;方向属性等的变化。
2.请用三种方法以上方法#xff0c;实现物体的抛物线运动。#xff08;如#xff0c;修改Transform属性#xff0c;使用向量Ve…3D游戏第3次作业牧师与魔鬼
1.游戏对象运动的本质是什么
对象位置属性方向属性等的变化。
2.请用三种方法以上方法实现物体的抛物线运动。如修改Transform属性使用向量Vector3的方法
用导数的方法不断用当前position加上一个位移向量 例如y-x^23x)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class NewBehaviourScript : MonoBehaviour
{public float speed;// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){float dxTime.deltaTime*speed;Vector3 dirnew Vector3(dx,(-2*this.transform.position.x3)*dx,0);this.transform.positiondir;}
}用lerp法
void Update(){float dxTime.deltaTime*speed;Vector3 dirnew Vector3(dx,(-2*this.transform.position.x3)*dx,0);this.transform.positionVector3.Lerp(this.transform.position,this.transform.positiondir,1);}用transl函数法 void Update(){float dxTime.deltaTime*speed;Vector3 dirnew Vector3(dx,(-2*this.transform.position.x3)*dx,0);this.transform.Translate(dir)}结果抛物线一样。
3.编程实践《牧师与魔鬼》
游戏规则
1.你要运用智慧帮助3个牧师圆球和3个魔鬼方块渡河。 2.船最多可以载2名游戏角色。 3.船上有游戏角色时你才可以点击这个船让船移动到对岸。 4.当有一侧岸的魔鬼数多余牧师数时包括船上的魔鬼和牧师魔鬼就会失去控制吃掉牧师如果5.这一侧没有牧师则不会失败游戏失败。 6.当所有游戏角色都上到对岸时游戏胜利。
游戏截图
开始游戏
游戏失败
游戏胜利
游戏架构 使用了MVC架构。
场景中的所有GameObject就是Model它们受到Controller的控制比如说牧师和魔鬼受到MyCharacterController类的控制船受到BoatController类的控制河岸受到CoastController类的控制。 View就是UserGUI和ClickGUI它们展示游戏结果并提供用户交互的渠道点击物体和按钮。 Controller除了刚才说的MyCharacterController、BoatController、CoastController以外还有更高一层的ControllerFirstController场景控制器FirstController控制着这个场景中的所有对象包括其加载、通信、用户输入。 最高层的Controller是Director类一个游戏中只能有一个实例它控制着场景的创建、切换、销毁、游戏暂停、游戏退出等等最高层次的功能。 Director Director的定义
public class Director : System.Object {private static Director _instance;public SceneController currentSceneController { get; set; }public static Director getInstance() {if (_instance null) {_instance new Director ();}return _instance;}
}Director是最高层的控制器运行游戏时始终只有一个实例它掌控着场景的加载、切换等也可以控制游戏暂停、结束等等。
虽然Director控制着场景但是它并不控制场景中的具体对象控制场景对象的任务交给了SceneController场景控制器我们等一下会谈到。
Director类使用了单例模式。第一次调用Director.getInstance()时会创建一个新的Director对象保存在_instance此后每次调用getInstance都回返回_instance。也就是说Director最多只有一个实例。这样我们在任何Script中的任何地方通过Director.getInstance()都能得到同一个Director对象也就可以获得同一个currentSceneController这样我们就可以轻易实现类与类之间的通信比如说我在其他控制器中就可以使用Director.getInstance().somethingHappen()来告诉导演某一件事情发生了导演就可以在somethingHappen()方法中做出对应的反应。
SceneController接口 SceneController接口定义
public interface SceneController {void loadResources ();
}interface接口不能直接用来创建对象必须先有一个类实现继承它在我的这个游戏中就是FirstController类。 SceneController 是用来干什么的呢它是导演控制场景控制器的渠道。在上面的Director 类中currentSceneController FirstController类就是SceneController的实现所以Director可以调用SceneController接口中的方法来实现对场景的生杀予夺。在这个游戏中SceneController的定义非常简单因为这个游戏做得并不完整。我们刚才说过导演可以加载、切换、销毁场景、暂停游戏所以SceneController 还可以规定void switchScene()、void destroyScene()、void pause()这些方法供给导演来调用。
Moveable Moveable是一个可以挂载在GameObject上的类
public class Moveable: MonoBehaviour {readonly float move_speed 20;// change frequentlyint moving_status; // 0-not moving, 1-moving to middle, 2-moving to destVector3 dest;Vector3 middle;void Update() {if (moving_status 1) {transform.position Vector3.MoveTowards (transform.position, middle, move_speed * Time.deltaTime);if (transform.position middle) {moving_status 2;}} else if (moving_status 2) {transform.position Vector3.MoveTowards (transform.position, dest, move_speed * Time.deltaTime);if (transform.position dest) {moving_status 0;}}}public void setDestination(Vector3 _dest) {dest _dest;middle _dest;if (_dest.y transform.position.y) { // boat movingmoving_status 2;}else if (_dest.y transform.position.y) { // character from coast to boatmiddle.y transform.position.y;} else { // character from boat to coastmiddle.x transform.position.x;}moving_status 1;}public void reset() {moving_status 0;}
}GameObject挂载上Moveable以后Controller就可以通过setDestination()方法轻松地让GameObject移动起来。
在这里我没有让物体直接移动到目的地dest因为那样可能会直接穿过河岸物体。我用middle来保存一个中间位置让物体先移动到middle再移动到dest这就实现了一个折线的移动不会穿越河岸。moving_status记录着目前该物体处于哪种移动状态。
MyCharacterController MyCharacterController封装了一个GameObject表示游戏角色牧师或恶魔。
public class MyCharacterController {readonly GameObject character;readonly Moveable moveableScript;readonly ClickGUI clickGUI;readonly int characterType; // 0-priest, 1-devil// change frequentlybool _isOnBoat;CoastController coastController;public MyCharacterController(string which_character) {if (which_character priest) {character Object.Instantiate (Resources.Load (Perfabs/Priest, typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;characterType 0;} else {character Object.Instantiate (Resources.Load (Perfabs/Devil, typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;characterType 1;}moveableScript character.AddComponent (typeof(Moveable)) as Moveable;clickGUI character.AddComponent (typeof(ClickGUI)) as ClickGUI;clickGUI.setController (this);}public void setName(string name) {character.name name;}public void setPosition(Vector3 pos) {character.transform.position pos;}public void moveToPosition(Vector3 destination) {moveableScript.setDestination(destination);}public int getType() { // 0-priest, 1-devilreturn characterType;}public string getName() {return character.name;}public void getOnBoat(BoatController boatCtrl) {coastController null;character.transform.parent boatCtrl.getGameobj().transform;_isOnBoat true;}public void getOnCoast(CoastController coastCtrl) {coastController coastCtrl;character.transform.parent null;_isOnBoat false;}public bool isOnBoat() {return _isOnBoat;}public CoastController getCoastController() {return coastController;}public void reset() {moveableScript.reset ();coastController (Director.getInstance ().currentSceneController as FirstController).fromCoast;getOnCoast (coastController);setPosition (coastController.getEmptyPosition ());coastController.getOnCoast (this);}
}UserAction 这个接口实际上使用了门面模式。 FirstController必须要实现这个接口才能对用户的输入做出反应。
public interface UserAction {void moveBoat();void characterIsClicked(MyCharacterController characterCtrl);void restart();
}在这个游戏中对用户输入做出反应有这三个方法就够了。 UserAction是如何得到用户的输入的呢原来在ClickGUI和UserGUI这两个类中都保存了一个UserAction的引用。当ClickGUI监测到用户点击GameObject的时候就会调用这个引用的characterIsClicked方法这样FirstController就知道哪一个游戏角色被点击了。UserGUI同理只不过它监测的是“用户点击Restart按钮”的事件。
ClickGUI ClickGUI类是用来监测用户点击并调用SceneController进行响应的
public class ClickGUI : MonoBehaviour {UserAction action;MyCharacterController characterController;public void setController(MyCharacterController characterCtrl) {characterController characterCtrl;}void Start() {action Director.getInstance ().currentSceneController as UserAction;}void OnMouseDown() {if (gameObject.name boat) {action.moveBoat ();} else {action.characterIsClicked (characterController);}}
}我们可以看到UserAction action实际上是FirstController的对象它实现了UserAction接口。ClickGUI与FirstController打交道就是通过UserAction接口的API。ClickGUI不知道这些API是怎么被实现的但它知道FirstController类一定有这些方法。
项目代码
项目源码