3D游戏编程与设计Hw4(牧师与魔鬼)

2023-12-16 11:10

本文主要是介绍3D游戏编程与设计Hw4(牧师与魔鬼),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  • 游戏中提及的事物:物体牧师、物体魔鬼、物体河岸、物体水域、物体船。

玩家动作表(规则表)

玩家玩家动作
点击Go按钮则行进(船上必须有一个人)
魔鬼/牧师点击岸上的玩家则跑到船上,同理返回岸上。岸边的牧师数必须等于或大于魔鬼数,否则游戏失败

UML类图
在这里插入图片描述
代码参考学长博客实现:
Boat.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Boat{readonly GameObject boat;readonly Moveable moveableScript;readonly Vector3 startPos = new Vector3(-1.95F,0.68F,0);// 在起始岸边的位置readonly Vector3 endPos = new Vector3(1.95F,0.68F,0);// 在终点岸边的位置readonly Vector3 startFirstPos = new Vector3(-2.3F,1.15F,0);// 在起始岸边船的第一个座位位置readonly Vector3 startSecondPos = new Vector3(-1.54F,1.15F,0);// 在起始岸边船的第二个座位位置readonly Vector3 endFirstPos = new Vector3(1.54F,1.15F,0);// 在终点岸边船的第一个座位位置readonly Vector3 endSecondPos = new Vector3(2.3F,1.15F,0);// 在终点岸边船的第二个座位位置private Character[] passenger;// 乘客对象数组,存放船上的对象private int curPosition;//当前船在哪个岸边 0-start  1-endprivate int count;// 船上人数public Boat(){// 初始化对象数组,一开始船上无人,故置为空passenger = new Character[2];passenger[0] = null;passenger[1] = null;// 动态加载船的预制boat = Object.Instantiate (Resources.Load ("Prefabs/boat", typeof(GameObject)), startPos, Quaternion.identity, null) as GameObject;boat.name = "boat";// 添加moveable组件使得船可以移动moveableScript = boat.AddComponent (typeof(Moveable)) as Moveable;// 初始变量curPosition = 0;count = 0;}// move 函数使船可以根据当前位置进行移动public void move(){if(curPosition == 0){moveableScript.setDestination(endPos);curPosition = 1;}else{moveableScript.setDestination(startPos);curPosition = 0;}}// 下面两个函数分别用来判断船的情况public bool isEmpty(){return count == 0;}public bool isFull(){return count == 2;}public bool addPassenger(Character ch){if(count == 2){return false;}// 找到空位置for(int i = 0;i < 2;++i){if(passenger[i] == null){passenger[i] = ch;break;}}count++;return true;}public bool removePassenger(Character ch){if(count == 0){return false;}// 找到要删除的乘客for(int i = 0;i < 2;++i){if(passenger[i] != null && passenger[i].getName() == ch.getName()){passenger[i] = null;}}count--;return true;}public int getCurPosition(){return curPosition;}public Vector3 getEmptyPosition(){// 若船已满,则返回坐标(0,0,0)if(count == 2){return new Vector3(0,0,0);}if(curPosition == 0){if(passenger[0] == null){return startFirstPos;}else{return startSecondPos;}}else{if(passenger[0] == null){return endFirstPos;}else{return endSecondPos;}}}public GameObject getGameobj(){return boat;}public int getNumOfPriest(){int res = 0;for(int i = 0;i < 2;++i){if(passenger[i] != null && passenger[i].getType() == 0){res++;}}return res;}public int getNumOfDevil(){int res = 0;for(int i = 0;i < 2;++i){if(passenger[i] != null && passenger[i].getType() == 1){res++;}}return res;}public void reset(){count = 0;passenger[0] = null;passenger[1] = null;// 若船在终点,则回到起始岸if(curPosition == 1){moveableScript.setDestination(startPos);curPosition = 0;}}
}

Land.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Land{private GameObject land;readonly Vector3 startPos = new Vector3(-6.6F,0,0);// 起始岸的位置readonly Vector3 endPos = new Vector3(6.6F,0,0);// 终点岸的位置private int type;//河岸类型 0-start 1-endprivate int count;// 岸上人数private Character[] curCharacter;// 当前岸上的角色readonly Vector3[] place;// 岸上的六个位置坐标 角色数组下标和位置数组下标保持一致private int[] emptyPlace;// 岸上六个位置的情况 0-empty 1-not emptypublic Land(string sel){place = new Vector3[6];if(sel == "start"){land = Object.Instantiate(Resources.Load("Prefabs/land", typeof(GameObject)),startPos, Quaternion.identity, null) as GameObject;land.name = "start";type = 0;count = 0;for(int i = 0;i < 6;++i){place[i] = new Vector3(-3.5F-0.8F*i,1.5F,0);}}else{land = Object.Instantiate(Resources.Load("Prefabs/land", typeof(GameObject)),endPos, Quaternion.identity, null) as GameObject;land.name = "end";type = 1;count = 0;for(int i = 0;i < 6;++i){place[i] = new Vector3(3.5F+0.8F*i,1.5F,0);}}curCharacter = new Character[6];emptyPlace = new int[6];for(int i = 0;i < 6;++i){curCharacter[i] = null;}for(int i = 0;i < 6;++i){emptyPlace[i] = 0;}}public int getType(){return type;}public int getCount(){return count;}public Vector3 getOnLand(Character ch){int index = 0;// 找到空位置,将角色放入对应下标的角色数组中,方便后面查找删除while(true){if(emptyPlace[index] == 0){emptyPlace[index] = 1;curCharacter[index] = ch;count++;break;}else{index++;}}// 返回角色所在位置return place[index];}public void leaveLand(Character ch){for(int i = 0;i < 6;++i){if( curCharacter[i] != null && curCharacter[i].getName() == ch.getName()){curCharacter[i] = null;emptyPlace[i] = 0;count--;return;}}  }public Vector3 getEmptyPosition(){for(int i = 0;i < 6;++i){if(emptyPlace[i] == 0){return place[i];}}return new Vector3(0,0,0);}public int getNumOfPriest(){int res = 0;for(int i = 0;i < 6;++i){if(curCharacter[i] == null){continue;}if(curCharacter[i].getType() == 0){res++;}}return res;}public int getNumOfDevil(){int res = 0;for(int i = 0;i < 6;++i){if(curCharacter[i] == null){continue;}if(curCharacter[i].getType() == 1){res++;}}return res;}public void reset(){if(type == 0){for(int i = 0;i < 6;++i){emptyPlace[i] = 1;}count = 6;}else{for(int i = 0;i < 6;++i){emptyPlace[i] = 0;}count = 0;}}
}

Character.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Character {readonly GameObject character;readonly int type; //0-priest 1-devilreadonly Moveable moveableScript;// 移动脚本组件readonly GUIClick _GUIClick;// 响应鼠标点击组件private bool isOnBoat;// 是否在船上private bool isFinished;//是否已经过河// 构造函数,根据传入的字符串选择创建牧师对象或者魔鬼对象public Character(string sel){// 动态加载预制if(sel == "priest"){character = Object.Instantiate(Resources.Load("Prefabs/priest", typeof(GameObject)),Vector3.zero, Quaternion.identity, null) as GameObject;type = 0;}else{character = Object.Instantiate(Resources.Load("Prefabs/devil", typeof(GameObject)),Vector3.zero, Quaternion.identity, null) as GameObject;type = 1;}// 为对象添加移动和点击响应组件moveableScript = character.AddComponent (typeof(Moveable)) as Moveable;_GUIClick = character.AddComponent(typeof(GUIClick)) as GUIClick;_GUIClick.bindCharacter(this);// 初始化变量isOnBoat = false;isFinished = false;}public int getType(){return type;}public void setName(string name) {character.name = name;}public string getName() {return character.name;}public void getOnBoat(Boat boat){// 设置transform为船的子组件,这样当船移动的时候就可以随着船移动character.transform.parent = boat.getGameobj().transform;isOnBoat = true;}public void getOffBoat(){character.transform.parent = null;isOnBoat = false;}public void getOnLand(Land land){if(land.getType() == 0){isFinished = false;}else{isFinished = true;}isOnBoat = false;}public bool getIsOnBoat(){return isOnBoat;}public void setPosition(Vector3 pos){character.transform.position = pos;}public void moveToPosition(Vector3 pos){moveableScript.setDestination(pos);}public bool getIsFinished(){return isFinished;}// 重置对象public void reset(){moveableScript.reset();// 如果对象已经过河if(isFinished){// 通过导演对象获取当前场景的控制器,取得其控制的Land对象Land endLand = (Director.getInstance ().currentSceneController as FirstController).endLand;endLand.leaveLand(this);Land startLand = (Director.getInstance ().currentSceneController as FirstController).startLand;getOnLand(startLand);setPosition(startLand.getOnLand(this));}// 如果对象在船上if(isOnBoat){getOffBoat();Land startLand = (Director.getInstance ().currentSceneController as FirstController).startLand;Boat boat = (Director.getInstance ().currentSceneController as FirstController).boat;boat.removePassenger(this);getOnLand(startLand);setPosition(startLand.getOnLand(this));}character.transform.parent = null;        }}

以上是预制物体的代码,实现了程序运行后物体自动生成而不是在Scene界面自己做。

接下来是控制部分:
SceneController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public interface SceneController {void loadResources ();void checkGameStatus();
}

FirstController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class FirstController : MonoBehaviour, SceneController, UserAction{readonly Vector3 water_pos = new Vector3(0,-0.4F,0);// 河流预制的位置public Land startLand;// 起始河岸public Land endLand;// 终点河岸public Boat boat;// 船public int status;//游戏状态 0-gaming 1-lose 2-win private Character[] characters;// 六个游戏角色private _GUI userGUI;// GUI组件void Awake() {// 将自身设置为当前场记Director director = Director.getInstance ();director.currentSceneController = this;// 将GUI作为一个组件userGUI = gameObject.AddComponent <_GUI>() as _GUI;characters = new Character[6];// 加载游戏资源loadResources();}// 实现SceneController接口,加载游戏资源public void loadResources() {GameObject water = Instantiate (Resources.Load ("Prefabs/river", typeof(GameObject)), water_pos, Quaternion.identity, null) as GameObject;water.name = "water";startLand = new Land ("start");endLand = new Land ("end");boat = new Boat();loadCharacter ();}// 实现SceneController接口,检查游戏状态 0->not finish, 1->lose, 2->winpublic void checkGameStatus() {	// 船在出发点int startNumOfPriest = startLand.getNumOfPriest();int startNumOfDevil = startLand.getNumOfDevil();int endNumOfPriest = endLand.getNumOfPriest();int endNumOfDevil = endLand.getNumOfDevil();int boatNumOfPriest = boat.getNumOfPriest();int boatNumOfDevil = boat.getNumOfDevil();if(endNumOfPriest + endNumOfDevil + boatNumOfPriest + boatNumOfDevil == 6){status = 2;return ;}if(boat.getCurPosition() == 1){if((startNumOfPriest  < startNumOfDevil && startNumOfPriest > 0)||(endNumOfPriest +  boatNumOfPriest < endNumOfDevil + boatNumOfDevil && endNumOfPriest +  boatNumOfPriest > 0)){status = 1;return ;}}else{if((startNumOfPriest + boatNumOfPriest < startNumOfDevil + boatNumOfDevil && startNumOfPriest + boatNumOfPriest > 0) || (endNumOfPriest < endNumOfDevil && endNumOfPriest > 0)){status = 1;return ;}}status = 0;}// 加载游戏对象private void loadCharacter() {for (int i = 0; i < 3; i++) {Character ch = new Character("priest");ch.setName("priest" + i);ch.getOnLand(startLand);ch.setPosition (startLand.getOnLand(ch));characters[i] = ch;}for (int i = 0; i < 3; i++) {Character ch = new Character("devil");ch.setName("devil" + i);ch.setPosition (startLand.getOnLand(ch));ch.getOnLand(startLand);characters [i+3] = ch;}}// 实现UserAction接口的goButtonIsClicked函数public void goButtonIsClicked(){if(!boat.isEmpty()){boat.move();checkGameStatus();}}// 实现UserAction接口的characterIsClicked函数public void characterIsClicked(Character ch){// 角色在船上if(ch.getIsOnBoat()){if(boat.getCurPosition() == 0){ch.moveToPosition(startLand.getOnLand(ch));ch.getOnLand(startLand);}else{ch.moveToPosition(endLand.getOnLand(ch));ch.getOnLand(endLand);}ch.getOffBoat();boat.removePassenger(ch);}// 角色在岸上else{if(!boat.isFull()){if(ch.getIsFinished() && boat.getCurPosition() == 1){ch.getOnBoat(boat);endLand.leaveLand(ch);ch.moveToPosition(boat.getEmptyPosition());boat.addPassenger(ch);}if(!ch.getIsFinished() && boat.getCurPosition() == 0){ch.getOnBoat(boat);startLand.leaveLand(ch);ch.moveToPosition(boat.getEmptyPosition());boat.addPassenger(ch);}}}}// 重置游戏public void restart(){status = 0;for(int i = 0;i < 6;++i){characters[i].reset();}boat.reset();startLand.reset();endLand.reset();		}}

Director.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;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;}
}

视觉部分(点击事件聚集处)
GUI.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class _GUI : MonoBehaviour{private SceneController sc;private UserAction ac;private GUIStyle style;private int status;private Texture2D priest;private Texture2D devil;private Texture2D rule;void Start(){style = new GUIStyle();style.fontSize = 40;// 获得控制器,通过控制器更新model部分的数据sc = Director.getInstance ().currentSceneController;ac = Director.getInstance().currentSceneController as UserAction;status = (Director.getInstance ().currentSceneController as FirstController).status;// 动态加载图片priest = Instantiate (Resources.Load ("Pictures/牧师", typeof(Texture2D))) as Texture2D;devil = Instantiate (Resources.Load ("Pictures/恶魔", typeof(Texture2D))) as Texture2D;rule = Instantiate (Resources.Load ("Pictures/规则", typeof(Texture2D))) as Texture2D;// Debug.Log("Screen.width"+Screen.width);// Debug.Log(" Screen.height"+ Screen.height);}void OnGUI(){// 同步游戏状态status = (Director.getInstance ().currentSceneController as FirstController).status;if(GUI.Button(new Rect(1300,850, 120, 120),"GO")){if(status == 0){ac.goButtonIsClicked();}}if(GUI.Button(new Rect(1600,850, 120, 120), "Restart")){ac.restart();}if(status == 1){GUI.Label(new Rect(800,100,300,250),devil);GUI.Label(new Rect(840, 400, 100, 50), "You lose!",style);}if(status == 2){GUI.Label(new Rect(800,100,300,250),priest);GUI.Label(new Rect(840, 400, 100, 50), "You win!",style);}GUI.Label(new Rect(0,800,1500,1500),rule);}
}

GUIClick.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class GUIClick : MonoBehaviour{UserAction action;Character bindingCharacter;// 组件当前绑定的角色对象SceneController sc;int status;// 游戏状态public void bindCharacter(Character ch){bindingCharacter = ch;status = (Director.getInstance ().currentSceneController as FirstController).status;}void Start(){action = Director.getInstance().currentSceneController as UserAction;sc = Director.getInstance().currentSceneController;}void OnMouseDown(){// 同步游戏状态status = (Director.getInstance ().currentSceneController as FirstController).status;// 只有在游戏中点击才有效if(status == 0){action.characterIsClicked(bindingCharacter);}}
}

剩下两个组件:
Moveabel.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Moveable : MonoBehaviour{readonly float speed = 10;int 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, speed * Time.deltaTime);if (transform.position == middle) {moving_status = 2;}} else if (moving_status == 2) {transform.position = Vector3.MoveTowards (transform.position, dest, 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;}
}

UserAction.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public interface UserAction {public void goButtonIsClicked();public void characterIsClicked(Character characterCtrl);public void restart();
}
  • 视频链接
    3D作业牧师与魔鬼

这篇关于3D游戏编程与设计Hw4(牧师与魔鬼)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/500244

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

怎么让1台电脑共享给7人同时流畅设计

在当今的创意设计与数字内容生产领域,图形工作站以其强大的计算能力、专业的图形处理能力和稳定的系统性能,成为了众多设计师、动画师、视频编辑师等创意工作者的必备工具。 设计团队面临资源有限,比如只有一台高性能电脑时,如何高效地让七人同时流畅地进行设计工作,便成为了一个亟待解决的问题。 一、硬件升级与配置 1.高性能处理器(CPU):选择多核、高线程的处理器,例如Intel的至强系列或AMD的Ry

国产游戏崛起:技术革新与文化自信的双重推动

近年来,国产游戏行业发展迅猛,技术水平和作品质量均得到了显著提升。特别是以《黑神话:悟空》为代表的一系列优秀作品,成功打破了过去中国游戏市场以手游和网游为主的局限,向全球玩家展示了中国在单机游戏领域的实力与潜力。随着中国开发者在画面渲染、物理引擎、AI 技术和服务器架构等方面取得了显著进展,国产游戏正逐步赢得国际市场的认可。然而,面对全球游戏行业的激烈竞争,国产游戏技术依然面临诸多挑战,未来的

基于51单片机的自动转向修复系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念