3D游戏编程

    科技2022-08-08  193

    3D游戏编程_作业三_牧师与魔鬼

    1、简答并用程序验证2.编程实践:牧师与魔鬼:1:列出游戏中提及的事物(Objects)2:用表格列出玩家动作表(规则表),注意,动作越少越好。3:编程:1.MVC编程结构:2.创建预制:3.代码:3.1 以下的代码都在文件 controller.cs中的同一个命名空间controller下:1.Director:2.接口:3.牧师以及魔鬼游戏对象的controller,以及它们的运动组件:4.boat对象的控制函数和运动模块:5.河岸的控制函数: 3.2 User_GUI负责处理玩家动作;在游戏结束时点击按键重新游戏:3.3scen_controller `在这里插入代码片`场记:创建初始化游戏对象,切换各游戏对象以及游戏的状态,负责管理各游戏对象的交换动作。3.4 处理游戏对象点击的类 Click_GUI 4.游戏运行:1:运行截图:2:演示视频: 项目链接地址

    1、简答并用程序验证

    游戏对象运动的本质是什么? 游戏对象运动的本质是,在每次帧刷新时,对象的坐标位置发生变化,即对象的transform.postion属性变化;

    public class Move : MonoBehaviour { public int speed = 2; // Use this for initialization void Start () { } // Update is called once per frame void Update () { this.transform.position = Vector3.MoveTowards (this.transform.position, new Vector3(7,7,0), 2 * Time.deltaTime); } }

    请用三种方法以上方法,实现物体的抛物线运动。(如,修改Transform属性,使用向量Vector3的方法…)

    方法一:修改Transform属性: 定义两个方向上的速度,水平速度恒定,垂直方向速度匀加速:

    public class Move_para : MonoBehaviour { public int x_speed = 3; public int y_speed = 0; // Use this for initialization void Start () { } // Update is called once per frame void Update () { this.transform.position += Vector3.down *Time.deltaTime *(y_speed/100) ; this.transform.position += Vector3.left *Time.deltaTime * x_speed; y_speed ++; } }

    方法二:使用向量Vector3:

    每次更新都加一个Vector3向量,该向量x轴上的值不变,y轴上的取值持续增长:

    public class Move_para : MonoBehaviour { public int x_speed = 3; public int y_speed = 80; // Use this for initialization void Start () { } // Update is called once per frame void Update () { this.transform.position += new Vector3(Time.deltaTime * x_speed,Time.deltaTime *(y_speed/100),0); y_speed --; } }

    三:使用translate

    public class Move_para : MonoBehaviour { public int x_speed = 3; public int y_speed = 80; // Use this for initialization void Start () { } // Update is called once per frame void Update () { this.transform.Translate(new Vector3(Time.deltaTime * x_speed,Time.deltaTime *(y_speed/100),0)); --y_speed; } }

    写一个程序,实现一个完整的太阳系, 其他星球围绕太阳的转速必须不一样,且不在一个法平面上。

    1:使用圆球制作太阳系行星的预制: 2:为每个行星编写运行代码: 比如太阳的代码:太阳只需要自转;因此只使用了函数Rotate;

    using System.Collections; using System.Collections.Generic; using UnityEngine; public class Sun : MonoBehaviour { public Transform sun; // Start is called before the first frame update void Start() { sun.position = Vector3.zero; } // Update is called once per frame void Update() { sun.Rotate(Vector3.up*10*Time.deltaTime); } }

    i地球和其他行星除了需要自转外,还需要绕着太阳公转;因此有两个动作分别对应Rotate()和Rotate Around():依次为其它行星编写运行代码:

    using System.Collections; using System.Collections.Generic; using UnityEngine; public class Earth : MonoBehaviour { public Transform earth; // Start is called before the first frame update void Start() { earth.position = new Vector3 (8, 0, 0); } // Update is called once per frame void Update() { earth.RotateAround (Vector3.zero, Vector3.up, 10 * Time.deltaTime); earth.Rotate (Vector3.up * 30 * Time.deltaTime); } }

    3:将预制添加成游戏对象,并为它们添加相应的脚本,运行:

    2.编程实践:牧师与魔鬼:

    1:列出游戏中提及的事物(Objects)

    牧师、恶魔、船、水、左河岸、右河岸

    2:用表格列出玩家动作表(规则表),注意,动作越少越好。

    状态玩家动作结果角色在岸边,船上有空位玩家点击角色角色上船角色在船上,船靠岸玩家点击角色角色上岸游戏结束点击restart游戏重新开始

    3:编程:

    1.MVC编程结构:

    按照要求,本次编程我们需要使用MVC架构。MVC架构即就是Model,View和Controller。在牧师与魔鬼游戏中,我们的所有GameObject可以说就是Model,包括 牧师、魔鬼、船等。每个Model就由对应的Controller控制。例如船就受到控制船的Controller的控制。在脚本文件中,我们定义了Boat_controller、Bank_controller等多个controller。而View就是展示给用户的游戏界面,以及可供用户操作的各种方式。比如船点击就能动,牧师和魔鬼一点击就可以上船或下船等。这些功能在User_GUI和Click_GUI文件中实现。 本次编程的代码文件: 所有的游戏对象都由代码动态生成,我们进需要创建一个空的游戏对象,然后将脚本Click_GUI、User_GUI、scen_controller文件添加到空游戏对象中即可运行。

    2.创建预制:

    在Resources文件夹下创建预制:

    3.代码:

    3.1 以下的代码都在文件 controller.cs中的同一个命名空间controller下:

    1.Director:

    我们需要一名导演来获取游戏场景;以及控制场景的切换,管理游戏状态:

    public class Director : System.Object{ private static Director _instance; public ISceneController currentSceneController {get ;set ;} public static Director getInstance() { if (_instance == null) { _instance = new Director (); } return _instance; } }
    2.接口:
    public interface ISceneController { void load_resource (); } public interface IUserAction { void S_Boating(); void Click_char(chara_controller characterCtrl); void Restart(); }
    3.牧师以及魔鬼游戏对象的controller,以及它们的运动组件:
    //charact_move //牧师和魔鬼的运动模块: public class charact_move : MonoBehaviour{ int char_moveable; //运动使能,为1时才运动 int status; //0 ->移动到起始点,1->移动到船上,2-》移动到终点 Vector3 free; //要移动到的目标位置 void Update() { if(char_moveable == 1){ if(status == 1){ if(transform.position.x > 0){ //从出发点移动到船上 if(transform.position.x > 7) transform.position = Vector3.MoveTowards (transform.position, new Vector3(7,3,0), 2 * Time.deltaTime); else { transform.position = Vector3.MoveTowards (transform.position, free , 2 * Time.deltaTime); } if(transform.position == free){ char_moveable = 0; } } else{ //从终点移动到船上 if(transform.position.x < -7) transform.position = Vector3.MoveTowards (transform.position, new Vector3(-7,3,0), 2 * Time.deltaTime); else { transform.position = Vector3.MoveTowards (transform.position, free , 2 * Time.deltaTime); } if(transform.position == free){ char_moveable = 0; } } } else{ if(transform.position.x > 0){ //移动到起始岸边 if(transform.position.x < 7) transform.position = Vector3.MoveTowards (transform.position, new Vector3(7,3,0), 2 * Time.deltaTime); else { transform.position = Vector3.MoveTowards (transform.position, free , 2 * Time.deltaTime); } if(transform.position == free){ char_moveable = 0; } } else{ //移动到终点岸边 if(transform.position.x > -7) transform.position = Vector3.MoveTowards (transform.position, new Vector3(-7,3,0), 2 * Time.deltaTime); else { transform.position = Vector3.MoveTowards (transform.position, free , 2 * Time.deltaTime); } if(transform.position == free){ char_moveable = 0; } } } } } public void set_char_mov(int istatus,Vector3 t_free) { char_moveable = 1 ; status = istatus; free = t_free ; } public void init() { char_moveable = 0; } } chara_controller public class chara_controller { GameObject character; int char_type; //0-priest;1-devil int status; //0- start;1->on boat; 2->on dest int char_moveable; //运动使能 int rank ; //排位 Vector3 position; //位置 Vector3 free; //移动的目标地址 readonly Click_GUI click_GUI; Bank_controller bank_con; Boat_controller boat_con ; charact_move chara_movscr; //运动模块 public chara_controller(int irank,int itype) { if (itype == 0) { position = new Vector3(7+irank,2,0); rank = irank; status = 0; char_type = 0; character = Object.Instantiate (Resources.Load ("Perfabs/Priest", typeof(GameObject)), position, Quaternion.identity, null) as GameObject; } else { position = new Vector3(7+irank,2,0); rank = irank; status = 0; char_type = 1; character = Object.Instantiate (Resources.Load ("Perfabs/Devil", typeof(GameObject)), position, Quaternion.identity, null) as GameObject; } chara_movscr = character.AddComponent (typeof(charact_move)) as charact_move; click_GUI = character.AddComponent (typeof(Click_GUI)) as Click_GUI; click_GUI.setController (this); } //角色运动控制函数 public void charac_action(int start_end,Vector3 ifree) { if(status == 0 || status == 2 ) { chara_movscr.set_char_mov(start_end,ifree); status = 1; } else { chara_movscr.set_char_mov(start_end,ifree); status = start_end; } } public void set_position(Vector3 pos) { character.transform.position = pos; position = pos; } public void setName(string name) { character.name = name; } public Vector3 get_position() { return position; } public int get_type(){ return char_type; } public int get_rank(){ return rank ; } public int get_status(){ return status; } public void set_free(Vector3 free_posi){ free = free_posi; } public void get_on_boat(Boat_controller boat_c) { bank_con = null; boat_con = boat_c; character.transform.parent = boat_c.get_Object().transform; } public void get_on_bank(Bank_controller ban_c) { bank_con = ban_c; character.transform.parent = null; boat_con = null; } public Bank_controller get_bank(){ return bank_con; } public void init() { //初始化 position = new Vector3(7+rank,2,0); character.transform.position = position ; status = 0; bank_con = (Director.getInstance ().currentSceneController as scen_controller).start_bank; get_on_bank (bank_con); chara_movscr.init(); } }
    4.boat对象的控制函数和运动模块:
    public class boat_move : MonoBehaviour{ //船的运动模块; int status; //0-> 在起始位置 1-> 在终点位置 int boat_movable; //运动使能 Vector3 start_pos = new Vector3(5.2F,1,0); //船的起始位置 Vector3 desti_pos = new Vector3(-5.2F,1,0); //船的的终点位置 void Update() { if(boat_movable == 1) { if(status == 0 && boat_movable == 1) //从起点移动到终点 { transform.position = Vector3.MoveTowards (transform.position,desti_pos,5*Time.deltaTime); if(transform.position == desti_pos) { status = 1;// boat_movable = 0; } } else if(status == 1 && boat_movable == 1){ //从终点移动到起始点 transform.position = Vector3.MoveTowards (transform.position,start_pos,5*Time.deltaTime); if(transform.position == desti_pos) { status = 0;// boat_movable = 0; } } } } public void set_boat_action(int stat,int moveable) //设置状态和运动时能 { status =stat; boat_movable = moveable; } public void init() //初始化 { status = 0; boat_movable = 0; } } public class Boat_controller{ GameObject boat; Vector3 start_pos = new Vector3(5.2F,1,0); Vector3 desti_pos = new Vector3(-5.2F,1,0); boat_move boat_moscri; int status ; //0->at_start,1->at_dest; 2->boating int boat_movable;//0->不移动 1-->移动 chara_controller [] passenger = new chara_controller [2]; //船上的乘客 public Boat_controller() { status = 0; boat_movable = 0; boat = Object.Instantiate(Resources.Load ("Perfabs/Boat",typeof(GameObject)),start_pos,Quaternion.identity,null) as GameObject; boat.name = "boat"; boat.AddComponent(typeof(Click_GUI)); boat_moscri = boat.AddComponent (typeof(boat_move)) as boat_move; } public void boating() { if(status == 0) { boat_moscri.set_boat_action(0,1); status = 1; } else if(status == 1) { boat_moscri.set_boat_action(1,1); status = 0; } } public int get_free() {//获取船上的空闲位置 if(passenger[0] == null) return 0; if(passenger[1] == null) return 1; return -1; } public void get_on_boat(chara_controller chara_c) { //将角色加入船的乘客队列 int free_i = get_free (); passenger [free_i] = chara_c; } public chara_controller get_off_boat(int rank_i) {//将角色从队列中除去; for(int i = 0; i < 2; ++i){ if(passenger[i]!= null && passenger[i].get_rank() == rank_i) { chara_controller chara_c = passenger [i]; passenger [i] = null; return chara_c ; } } return null; } public GameObject get_Object() { return boat; } public int get_status() { return status ; } public void set_boat_move(int t) { boat_movable = t; } public int [] count_chara() { //统计乘客的数量和类型 int [] count = {0,0,0}; for(int i = 0; i< 2; i++) { if(passenger[i] == null) continue; else if(passenger[i].get_type() == 0) count[0] ++; else{ count[1] ++; } } count[2] = count[0] +count[1]; return count; } public void init() { if(status == 1) { boating(); } passenger = new chara_controller[2]; } }
    5.河岸的控制函数:
    public class Bank_controller{ GameObject bank; Vector3 position; int type ; //1->start -1->destination chara_controller [] characters ; public Bank_controller(int itype) { position = new Vector3(10*itype,1,0); bank = Object.Instantiate (Resources.Load("Perfabs/bank",typeof(GameObject)),position ,Quaternion.identity,null) as GameObject; type = itype; characters = new chara_controller [6]; } public void get_on_bank(chara_controller chara_c) { int irank = chara_c.get_rank(); characters[irank] = chara_c ; } public chara_controller get_off_bank(int irank){ chara_controller ichara = characters[irank]; characters[irank] = null; return ichara ; } public int get_type() { return type; } public int [] count_chara() { int [] count = { 0 , 0}; for(int i = 0; i< 6; ++i) { if(characters[i] == null) continue ; if(characters[i].get_type() == 0) count[0] ++; else if(characters[i].get_type() == 1) count[1] ++; } return count ; } public void init() { characters = new chara_controller[6]; } }

    3.2 User_GUI负责处理玩家动作;在游戏结束时点击按键重新游戏:

    using System.Collections; using System.Collections.Generic; using UnityEngine; using controller; public class User_GUI : MonoBehaviour { private IUserAction action; public int status = 0; GUIStyle style; GUIStyle buttonStyle; void Start() {// action = Director.getInstance ().currentSceneController as IUserAction; style = new GUIStyle(); style.fontSize = 40; style.normal.textColor = new Color(100, 155, 255); style.alignment = TextAnchor.MiddleCenter; buttonStyle = new GUIStyle("button"); buttonStyle.fontSize = 30; buttonStyle.normal.textColor = new Color(100, 155, 255); } void OnGUI() { if (status == 1) { GUI.Label(new Rect(Screen.width/2-50, Screen.height/2-85, 100, 50), "Gameover!", style); if (GUI.Button(new Rect(Screen.width/2-70, Screen.height/2, 140, 70), "Restart", buttonStyle)) { status = 0; action.Restart (); } } else if(status == 2) { GUI.Label(new Rect(Screen.width/2-50, Screen.height/2-85, 100, 50), "You win!", style); if (GUI.Button(new Rect(Screen.width/2-70, Screen.height/2, 140, 70), "Restart", buttonStyle)) { status = 0; action.Restart (); } } } }

    3.3scen_controller 在这里插入代码片场记:创建初始化游戏对象,切换各游戏对象以及游戏的状态,负责管理各游戏对象的交换动作。

    using System.Collections; using System.Collections.Generic; using UnityEngine; using controller; public class scen_controller : MonoBehaviour, ISceneController, IUserAction { User_GUI user_GUI; public Bank_controller start_bank; public Bank_controller dest_bank; public Boat_controller boat; public chara_controller [] characters ; void Awake() { Director director = Director.getInstance (); director.currentSceneController = this; user_GUI = gameObject.AddComponent <User_GUI>() as User_GUI; characters = new chara_controller[6]; load_resource(); } public void load_resource() { start_bank = new Bank_controller(1) ; dest_bank = new Bank_controller (-1); GameObject water = Instantiate (Resources.Load ("Perfabs/Water", typeof(GameObject)), new Vector3(0,0.5F,0), Quaternion.identity, null) as GameObject; boat = new Boat_controller (); for(int i = 0; i < 6; ++i){ if(i < 3) { chara_controller chara_t = new chara_controller (i,0); chara_t.setName("priest" + i); chara_t.get_on_bank(start_bank); start_bank.get_on_bank(chara_t); characters[i] = chara_t; } else{ chara_controller chara_t = new chara_controller (i,1); int t = i - 3; chara_t.setName("devil" +t); chara_t.get_on_bank(start_bank); start_bank.get_on_bank(chara_t); characters[i] = chara_t; } } } public void S_Boating() { int [] count_i = boat.count_chara(); if(count_i[2] == 0) { Debug.Log("boat_empty"); return; } boat.boating(); Debug.Log("set_boat"); user_GUI.status = check_game_over (); } public void Click_char(chara_controller char_i) { if(char_i.get_status() == 1){ //在船上 if(boat.get_status() == 0)//在开始地方 { char_i.get_on_bank(start_bank); start_bank.get_on_bank(char_i); int t_rank = char_i.get_rank(); boat.get_off_boat(t_rank); Vector3 free_pos = new Vector3(7+t_rank ,2,0); char_i.charac_action(0,free_pos); } if(boat.get_status() == 1) //上终点河岸 { char_i.get_on_bank(dest_bank); dest_bank.get_on_bank(char_i); int t_rank = char_i.get_rank(); boat.get_off_boat(t_rank); Vector3 free_pos = new Vector3(-7-t_rank ,2,0); char_i.charac_action(2,free_pos); } } else{//在岸上 Bank_controller bank_i = char_i.get_bank(); if(boat.get_free() == -1) return ; if((bank_i.get_type() == 1 && boat.get_status() == 0)) ///在起点河岸上船 { bank_i.get_off_bank(char_i.get_rank()); int index = (boat.get_free())*2-1; Vector3 free_pos = new Vector3(5+index,1.5F,0); char_i.charac_action(1,free_pos); char_i.get_on_boat (boat); boat.get_on_boat(char_i); }//在终点河岸上船: else if ((bank_i.get_type() == -1 && boat.get_status() == 1)) { bank_i.get_off_bank(char_i.get_rank()); int index = (boat.get_free())*2-1; Vector3 free_pos = new Vector3(-5+index,1.5F,0); char_i.charac_action(1,free_pos); char_i.get_on_boat (boat); boat.get_on_boat(char_i); } else {return ;} } user_GUI.status = check_game_over(); } int check_game_over() { int start_priest = 0; int start_devil = 0; int dest_priest = 0; int dest_devil = 0; int[] start = start_bank.count_chara(); int[] dest = dest_bank.count_chara(); int[] boat_count = boat.count_chara(); if(dest[0] +dest[1] == 6) return 2; //赢 if(boat.get_status() == 0){ start_priest = start[0] + boat_count[0]; start_devil = start[1] + boat_count[1]; dest_priest = dest[0]; dest_devil = dest[1]; } else{ start_priest = start[0] ; start_devil = start[1] ; dest_priest = dest[0]+ boat_count[0]; dest_devil = dest[1]+ boat_count[1]; } Debug.Log("start:"+start[0]+start[1]); Debug.Log("dest:" +dest[0]+dest[1]); Debug.Log("boat:"+ boat_count[0]+boat_count[1]+boat_count[2]); Debug.Log("start_p"+start_priest+start_devil+dest_priest+dest_devil); if((start_priest < start_devil && start_priest !=0) || (dest_priest < dest_devil && dest_priest != 0)) return 1; //游戏结束 return 0; //游戏继续 } public void Restart(){ start_bank.init(); dest_bank.init(); boat.init(); for(int i = 0; i < 6; ++i) { characters[i].init(); start_bank.get_on_bank(characters[i]); } } }

    3.4 处理游戏对象点击的类 Click_GUI

    using System.Collections; using System.Collections.Generic; using UnityEngine; using controller; public class Click_GUI : MonoBehaviour { IUserAction action; chara_controller characterController; public void setController(chara_controller characterCtrl) { characterController = characterCtrl; } void Start() { action = Director.getInstance ().currentSceneController as IUserAction; } void OnMouseDown() { if (gameObject.name == "boat") { action.S_Boating(); } else { action.Click_char(characterController); } } }

    4.游戏运行:

    1:运行截图:

    2:演示视频:

    priest and devil

    项目链接地址

    Processed: 0.009, SQL: 8