unity 3d 牧师与魔鬼小游戏(动作分离并添加裁判类)

2023-12-16 11:10

本文主要是介绍unity 3d 牧师与魔鬼小游戏(动作分离并添加裁判类),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、动作分离

1.改进目的:

  • 将 CCAction 代码补充修改,按课件(第四章,作业2 “牧师与魔鬼 动作分离版”),编写“牧师与魔鬼游戏” 要求。
  • 集成 CCAction,使得动作管理从场景控制器中分离。
  • 利用接口消息传递机制,设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束。实现游戏结束判定从场景控制器中分离。

我们在上次作业使用MVC代码架构制作了牧师与魔鬼小游戏,但是不难发现,场景控制器FirstController需要管理的事务过于繁杂,不利于代码管理。而我们现在要做的事情就是,建立一个动作管理器,使得动作管理从场景控制器中分离出来,优化结构,通过场景控制器把需要移动的游戏对象传递给动作管理器,让动作管理器去移动游戏对象。为此,我们需要把每个需要移动的游戏对象的移动方法提取出来,添加到动作管理器中由它来管理不同的移动方法。当动作很多或是需要做同样动作的游戏对象很多的时候,使用动作管理器可以让动作很容易管理,也提高了代码复用性。

        除此之外,我们还需要利用接口消息传递机制,设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束。实现“游戏结束判定”从场景控制器中分离。

2.UML图

本次动作分离版牧师与魔鬼的UML图如下:

其中,ISceneController和IUserAction等接口设计、SSDirector场记和UserGUI用户交互的设计、ModelController和对应Model的设计基本与上次作业无异,主要是新增了SSAction动作基类和SSActionManager动过管理器基类并派生出两个子类CCMoveAction和CCActionManager,他们将实现和管理所有的动作方法(虽然我们在该游戏中只有平移这一动作),在该游戏例子中,在FirstController中声明一个CCActionManager动作管理器对象,需要移动对象时只需要声明一个CCMoveAction对象并添加到动作管理器对象即可实现动作从场景控制器中分离。而Judge类则将场景管理器的“判断游戏结束”功能方法分离出来,判断游戏结束,并通知场景管理器。
 

二、代码实现

Judge:

裁判类实际上是把原来FirstController中的UpdadeGameState()方法单独分离出来成为一个类

public class JudgeController{FirstController firstCtrl;public JudgeController(){firstCtrl = SSDirector.GetInstance().CurrentSceneController as FirstController;}//判断游戏状态public int UpdadeGameState(){if(firstCtrl.gameState != FirstController.PLAYING) return firstCtrl.gameState;//判断是否失败int[,] rolePos = new int[2, 3]{{0, 0, 0}, {0, 0, 0}};foreach(RoleController r in firstCtrl.RoleCtrl){rolePos[r.roleType, r.roleState]++;}if((rolePos[0,0]>0 && rolePos[0,0]<rolePos[1,0]) || (rolePos[0,1]>0 && rolePos[0,1]<rolePos[1,1]) || (rolePos[0,2]>0 && rolePos[0,2] < rolePos[1,2])){return FirstController.FAILED;}  //判断是否成功foreach(RoleController r in firstCtrl.RoleCtrl){if(r.roleType == 0 && r.roleState != FirstController.RIGHTLAND){return FirstController.PLAYING; }}return FirstController.WIN;}
}

在上一篇文章中,游戏对象的移动由MoveController和Move共同管理,这样做的坏处是在FirstController中仍然保留有一小部分的用于管理对象运动的代码。在动作分离版的代码中,管理动作的代码被分解成以下三部分,CCActionManager用于管理所有动作,CCMoveAction用于管理“移动”这种动作,Move则是移动这个动作的实体。

 在CCActionManager中主要实现了MoveRole()和MoveBoat()两个函数。通过调用CCMoveAction中的MoveTo和MoveSeqcenceTo来实现两种不同形式的移动效果。

CCMoveAction:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CCMoveAction
{GameObject moveObject;public bool IsMoving(){return(this.moveObject != null && this.moveObject.GetComponent<Move>().isMoving == true);}public void MoveTo(GameObject moveObject, Vector3 destination){Move test;this.moveObject = moveObject;if (!moveObject.TryGetComponent<Move>(out test)) {moveObject.AddComponent<Move>();}this.moveObject.GetComponent<Move>().moveAction = this;this.moveObject.GetComponent<Move>().destination = destination;this.moveObject.GetComponent<Move>().moveMode = Move.single;}public void MoveSequenceTo(GameObject moveObject, Vector3 destination){Move test;this.moveObject = moveObject;if (!moveObject.TryGetComponent<Move>(out test)) {moveObject.AddComponent<Move>();}this.moveObject.GetComponent<Move>().moveAction = this;this.moveObject.GetComponent<Move>().destination = destination;this.moveObject.GetComponent<Move>().moveMode = Move.sequence;}
}

Move:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Move : MonoBehaviour
{public static int single = 0;public static int sequence = 1;public bool isMoving;bool initialized;public int moveMode;public bool doneMoving;public float speed = 5;int n_seq;public Vector3[] desseq;public Vector3 destination;public CCMoveAction moveAction;public Move(){n_seq = 0;isMoving = false;initialized = false;moveMode = -1;}void Update(){if(moveMode == -1) return;if(!initialized){if(moveMode == single){desseq = new Vector3[1];desseq[0] = destination;}else if(moveMode == sequence){desseq = new Vector3[3];desseq[0] = transform.localPosition + new Vector3(0, 1, 0);desseq[1] = destination + new Vector3(0, 1, 0);desseq[2] = destination;}else{Debug.Log("ERROR!");}initialized = true;}     isMoving = true;if(n_seq >= desseq.Length){n_seq = 0;moveMode = -1;initialized = false;isMoving = false;return;}if(transform.localPosition == desseq[n_seq]){n_seq += 1;return;}transform.localPosition = Vector3.MoveTowards(transform.localPosition, desseq[n_seq], speed * Time.deltaTime);}
}

CCActionManager:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CCActionManager
{public CCMoveAction moveBoatAction;public CCMoveAction moveRoleAction;public FirstController controller;public CCActionManager(){controller = SSDirector.GetInstance().CurrentSceneController as FirstController;controller.actionManager = this;moveBoatAction = new CCMoveAction();moveRoleAction = new CCMoveAction();}public bool IsMoving(){return moveRoleAction.IsMoving() || moveBoatAction.IsMoving();}public void MoveRole(BoatController BoatCtrl, RoleController RoleCtrl, int destination, int seat){Vector3 finalPos;if(destination == FirstController.RIGHTLAND){finalPos = Position.roleRightPos[seat];}else if(destination == FirstController.LEFTLAND){finalPos = Position.roleLeftPos[seat];}else{if(BoatCtrl.onLeftside){finalPos = Position.seatLeftPos[seat];}else{finalPos = Position.seatRightPos[seat];}}moveRoleAction.MoveSequenceTo(RoleCtrl.GetModelGameObject(), finalPos);}public void MoveBoat(BoatController BoatCtrl, int destination){if(destination == FirstController.RIGHTLAND){moveBoatAction.MoveTo(BoatCtrl.GetModelGameObject(), Position.boatRightPos);for(int i = 0; i < 3; i++){if(BoatCtrl.seat[i] != -1){RoleController r = controller.RoleCtrl[controller.IDToNumber(BoatCtrl.seat[i])];moveRoleAction.MoveTo(r.GetModelGameObject(), Position.seatRightPos[i]);}}}else{moveBoatAction.MoveTo(BoatCtrl.GetModelGameObject(), Position.boatLeftPos);for(int i = 0; i < 3; i++){if(BoatCtrl.seat[i] != -1){RoleController r = controller.RoleCtrl[controller.IDToNumber(BoatCtrl.seat[i])];moveRoleAction.MoveTo(r.GetModelGameObject(), Position.seatLeftPos[i]);}}}}
}

FirstController:

在FirstController中就创建Judge类对象和CCActionManager类对象,由judge判断游戏输赢,由CCActionManager执行游戏对象的移动动作,其他与之前无异

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class FirstController : MonoBehaviour, ISceneController, IUserAction
{public static int LEFTLAND = 0;public static int RIGHTLAND = 1;public static int BOAT = 2;public static int PRIEST = 0;public static int DEVIL = 1;public static int PLAYING = 0;public static int WIN = 1;public static int FAILED = 2;public CCActionManager actionManager;public BoatController BoatCtrl;public RoleController[] RoleCtrl = new RoleController[6];public LandController[] LandCtrl = new LandController[2];public JudgeController JudgeCtrl;public int[] rolesID = new int[6]{0,1,2,3,4,5};public int gameState;void Awake(){SSDirector director = SSDirector.GetInstance();director.CurrentSceneController = this;director.CurrentSceneController.Initialize();}public void Initialize(){//如果有,则释放原有的GameObjectfor(int i = 0; i < 6; i++){if(RoleCtrl[i] != null){Destroy(RoleCtrl[i].GetModelGameObject());}}for(int i = 0; i < 2; i++){if(LandCtrl[i] != null){Destroy(LandCtrl[i].GetModelGameObject());}}if(BoatCtrl != null){Destroy(BoatCtrl.GetModelGameObject());}// 加载控制器和模型BoatCtrl = new BoatController();BoatCtrl.CreateModel();for(int i = 0; i < 6; i++){int roleType = (i < 3) ? PRIEST : DEVIL;RoleCtrl[i] = new RoleController(roleType, rolesID[i]);RoleCtrl[i].CreateModel();}LandCtrl[0] = new LandController(LEFTLAND, rolesID);LandCtrl[1] = new LandController(RIGHTLAND, rolesID);LandCtrl[0].CreateModel();LandCtrl[1].CreateModel();JudgeCtrl = new JudgeController();actionManager = new CCActionManager();//开始游戏gameState = PLAYING;}//将角色的ID转换成数组的下标public int IDToNumber(int ID){for(int i = 0; i < 6; i++){if(rolesID[i] == ID){return i;}}return -1;}//点击船时执行public void MoveBoat(){if(gameState != PLAYING || actionManager.IsMoving()) return;gameState = JudgeCtrl.UpdadeGameState();if(BoatCtrl.onLeftside){actionManager.MoveBoat(BoatCtrl, RIGHTLAND);}else{actionManager.MoveBoat(BoatCtrl, LEFTLAND);}BoatCtrl.onLeftside = !BoatCtrl.onLeftside;}//点击角色时执行public void MoveRole(int id){int num = IDToNumber(id);if(gameState != PLAYING || actionManager.IsMoving()) return;int seat;switch(RoleCtrl[num].roleState){case 0: // LEFTLANDif(!BoatCtrl.onLeftside) return;seat = BoatCtrl.embark(id);if(seat == -1) return;LandCtrl[0].LeaveLand(id);RoleCtrl[num].GoTo(BOAT);actionManager.MoveRole(BoatCtrl, RoleCtrl[num], BOAT, seat);break;case 1: // RIGHTLANDif(BoatCtrl.onLeftside) return;seat = BoatCtrl.embark(id);if(seat == -1) return;LandCtrl[1].LeaveLand(id);RoleCtrl[num].GoTo(BOAT);actionManager.MoveRole(BoatCtrl, RoleCtrl[num], BOAT, seat);break;case 2: //BOATif(BoatCtrl.onLeftside){seat = LandCtrl[0].getEmptySeat();BoatCtrl.disembark(id);LandCtrl[0].GoOnLand(id);RoleCtrl[num].GoTo(LEFTLAND);actionManager.MoveRole(BoatCtrl, RoleCtrl[num], LEFTLAND, seat);}else{seat = LandCtrl[1].getEmptySeat();BoatCtrl.disembark(id);LandCtrl[1].GoOnLand(id);RoleCtrl[num].GoTo(RIGHTLAND);actionManager.MoveRole(BoatCtrl, RoleCtrl[num], RIGHTLAND, seat);}break;default: break;}}//Reset按钮执行的功能public void Restart(){Initialize();gameState = PLAYING;}//获取游戏当前状态public int GetGameState(){return gameState;}
}

三、游戏展示

游戏展示视频:unity 3d游戏编程作业 牧师与魔鬼动作分离版 (bilibili.com)

代码地址:冯威彬/unity 3d - 码云 - 开源中国 (gitee.com)

参考师兄文章,感谢师兄!Unity3D小游戏——牧师与魔鬼(动作分离版) - LoongChan - 博客园 (cnblogs.com)

这篇关于unity 3d 牧师与魔鬼小游戏(动作分离并添加裁判类)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

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

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

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

MiniGPT-3D, 首个高效的3D点云大语言模型,仅需一张RTX3090显卡,训练一天时间,已开源

项目主页:https://tangyuan96.github.io/minigpt_3d_project_page/ 代码:https://github.com/TangYuan96/MiniGPT-3D 论文:https://arxiv.org/pdf/2405.01413 MiniGPT-3D在多个任务上取得了SoTA,被ACM MM2024接收,只拥有47.8M的可训练参数,在一张RTX

用Unity2D制作一个人物,实现移动、跳起、人物静止和动起来时的动画:中(人物移动、跳起、静止动作)

上回我们学到创建一个地形和一个人物,今天我们实现一下人物实现移动和跳起,依次点击,我们准备创建一个C#文件 创建好我们点击进去,就会跳转到我们的Vision Studio,然后输入这些代码 using UnityEngine;public class Move : MonoBehaviour // 定义一个名为Move的类,继承自MonoBehaviour{private Rigidbo

SAM2POINT:以zero-shot且快速的方式将任何 3D 视频分割为视频

摘要 我们介绍 SAM2POINT,这是一种采用 Segment Anything Model 2 (SAM 2) 进行零样本和快速 3D 分割的初步探索。 SAM2POINT 将任何 3D 数据解释为一系列多向视频,并利用 SAM 2 进行 3D 空间分割,无需进一步训练或 2D-3D 投影。 我们的框架支持各种提示类型,包括 3D 点、框和掩模,并且可以泛化到不同的场景,例如 3D 对象、室

请解释Java Web应用中的前后端分离是什么?它有哪些好处?什么是Java Web中的Servlet过滤器?它有什么作用?

请解释Java Web应用中的前后端分离是什么?它有哪些好处? Java Web应用中的前后端分离 在Java Web应用中,前后端分离是一种开发模式,它将传统Web开发中紧密耦合的前端(用户界面)和后端(服务器端逻辑)代码进行分离,使得它们能够独立开发、测试、部署和维护。在这种模式下,前端通常通过HTTP请求与后端进行数据交换,后端则负责业务逻辑处理、数据库交互以及向前端提供RESTful

Unity Post Process Unity后处理学习日志

Unity Post Process Unity后处理学习日志 在现代游戏开发中,后处理(Post Processing)技术已经成为提升游戏画面质量的关键工具。Unity的后处理栈(Post Processing Stack)是一个强大的插件,它允许开发者为游戏场景添加各种视觉效果,如景深、色彩校正、辉光、模糊等。这些效果不仅能够增强游戏的视觉吸引力,还能帮助传达特定的情感和氛围。 文档

模具要不要建设3D打印中心

随着3D打印技术的日益成熟与广泛应用,模具企业迎来了自建3D打印中心的热潮。这一举措不仅为企业带来了前所未有的发展机遇,同时也伴随着一系列需要克服的挑战,如何看待企业引进增材制造,小编为您全面分析。 机遇篇: 加速产品创新:3D打印技术如同一把钥匙,为模具企业解锁了快速迭代产品设计的可能。企业能够迅速将创意转化为实体模型,缩短产品从设计到市场的周期,抢占市场先机。 强化定制化服务:面

Unity协程搭配队列开发Tips弹窗模块

概述 在Unity游戏开发过程中,提示系统是提升用户体验的重要组成部分。一个设计良好的提示窗口不仅能及时传达信息给玩家,还应当做到不干扰游戏流程。本文将探讨如何使用Unity的协程(Coroutine)配合队列(Queue)数据结构来构建一个高效且可扩展的Tips弹窗模块。 技术模块介绍 1. Unity协程(Coroutines) 协程是Unity中的一种特殊函数类型,允许异步操作的实现