lab06:牧师与魔鬼游戏 动作分离版

2024-01-21 22:50

本文主要是介绍lab06:牧师与魔鬼游戏 动作分离版,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这里写自定义目录标题

  • 整体描述
  • UML图
  • 代码介绍
    • action part
    • controller part
    • view part
  • 代码地址

整体描述

本次项目在第一版牧师与魔鬼的基础上,将动作从场记中分离出来,并设计一个裁判类监测游戏进行的。

这样改进的优点:
1.降低了不同功能之间的耦合性,代码的复用性更好。
2.通过门面模式,程序更加容易进行修改。

UML图

参考了经典的cocos2d方案
在这里插入图片描述

代码介绍

action part

SSAction 动作基类。

定义了两个虚函数 Start 和 Update,后续的动作类都继承该动作基类。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SSAction : ScriptableObject
{public bool enable = true;public bool destroy = false;public GameObject gameobject { get; set; }public Transform transform { get; set; }public ISSActionCallback callback { get; set; }protected SSAction() { }// Start is called before the first frame updatepublic virtual void Start(){throw new System.NotImplementedException();}// Update is called once per framepublic virtual void Update(){throw new System.NotImplementedException();}
}

ISSActionCallback 接口类,定义了一个回调函数。

SSActionEvent 是回调函数,当动作完成后需要通知主控制器。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum SSActionEventType : int { Started, Competeted }
public interface ISSActionCallback
{public void SSActionEvent(SSAction source,SSActionEventType events = SSActionEventType.Competeted,int intParam = 0, string strParam = null, Object objectParam = null);
}

SSActionManager 动作管理基类

在Update 中实现所有动作的基本管理。
思路是遍历动作字典中的所有动作,查看它们的信息,进行销毁或更新操作。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SSActionManager : MonoBehaviour
{private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();private List<SSAction> waitingAdd = new List<SSAction> ();private List<int> waitingDelete = new List<int>();// Start is called before the first frame updateprotected void Start(){}// Update is called once per frameprotected void Update(){foreach(SSAction ac in waitingAdd){actions[ac.GetInstanceID()] = ac;}waitingAdd.Clear();foreach(KeyValuePair<int, SSAction> kv in actions){SSAction ac = kv.Value;if(ac.destroy){waitingDelete.Add(ac.GetInstanceID());}else if(ac.enable){ac.Update();}}foreach(int key in waitingDelete){SSAction ac = actions[key];actions.Remove(key);Destroy(ac);}waitingDelete.Clear();}public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager){action.gameobject = gameobject;action.transform = gameobject.transform;action.callback = manager;waitingAdd.Add(action);action.Start();}
}

CCMoveToAction 继承了SSAction基类

完成了通用的单个GameObject移动实现。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;// 移动的动作具体实现类
public class CCMoveToAction : SSAction
{public Vector3 target;   // 移动后的目标位置public float speed;private CCMoveToAction(){}// Start is called before the first frame updatepublic override void Start(){}// Update is called once per framepublic override void Update(){this.transform.localPosition = Vector3.MoveTowards(this.transform.localPosition, target, speed * Time.deltaTime);// 如果游戏对象不存在或者当前位置已在目标位置上,则不移动if (this.transform.localPosition == target || this.gameobject == null){this.destroy = true;this.callback.SSActionEvent(this);return;}}public static CCMoveToAction GetSSAction(Vector3 target, float speed){CCMoveToAction action = ScriptableObject.CreateInstance<CCMoveToAction>();action.target = target;action.speed = speed;return action;}
}

CCSequenceAction 继承了SSAction基类,作用是组合动作实现

思路是通过一个list存储组合动作中的各个子动作,并按存放的顺序依次执行。
根据参数 repeat 判断是否要重复执行组合动作。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CCSequenceAction : SSAction, ISSActionCallback
{// 动作序列public List<SSAction> sequence;public int repeat = -1;public int start = 0;// Start is called before the first frame updatepublic override void Start(){// 初始化列表中的动作foreach (SSAction action in sequence){action.gameobject = this.gameobject;action.transform = this.transform;action.callback = this;action.Start();}}// Update is called once per framepublic override void Update(){if (sequence.Count <= 0){return;}if (sequence.Count > 0 && start < sequence.Count){sequence[start].Update();}else{return;}}// 构造动作序列对象public static CCSequenceAction GetSSAction(int repeat, int start, List<SSAction> sequence){CCSequenceAction action = ScriptableObject.CreateInstance<CCSequenceAction>();action.repeat = repeat;action.start = start;action.sequence = sequence;return action;}// 执行完一个动作后回调public void SSActionEvent(SSAction source,SSActionEventType events = SSActionEventType.Competeted,int intParam = 0, string strParam = null, Object objectParam = null){source.destroy = false;this.start++;if (this.start >= sequence.Count){this.start = 0;if (this.repeat > 0){this.repeat--;}else{this.destroy = true;this.callback.SSActionEvent(this);}}}void OnDestroy(){}
}

SSActionManager 动作管理基类

动作对象管理器的基类,实现了所有动作的基本管理
update:每一帧 添加、删除等复杂集合对象的使用。
提供了添加新动作的方法 RunAction。该方法把游戏对象与动作绑定,并绑定该动作事件的消息接收者。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SSActionManager : MonoBehaviour
{private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();private List<SSAction> waitingAdd = new List<SSAction> ();private List<int> waitingDelete = new List<int>();// Start is called before the first frame updateprotected void Start(){}// Update is called once per frameprotected void Update(){foreach(SSAction ac in waitingAdd){actions[ac.GetInstanceID()] = ac;}waitingAdd.Clear();foreach(KeyValuePair<int, SSAction> kv in actions){SSAction ac = kv.Value;if(ac.destroy){waitingDelete.Add(ac.GetInstanceID());}else if(ac.enable){ac.Update();}}foreach(int key in waitingDelete){SSAction ac = actions[key];actions.Remove(key);Destroy(ac);}waitingDelete.Clear();}public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager){action.gameobject = gameobject;action.transform = gameobject.transform;action.callback = manager;waitingAdd.Add(action);action.Start();}
}

CCActionManager 动作组合

MoveBoat 移动船,简单动作,对应为 CCMoveToAction。

MoveRole 移动人物,组合动作,对应为 CCSequenceAction

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CCActionManager : SSActionManager, ISSActionCallback
{public CCMoveToAction boatMovement;public CCSequenceAction roleMovement;public FirstController controller;private bool isMoving = false;protected new void Start(){controller = (FirstController)SSDirector.GetInstance().CurrentSceneController;controller.actionManager = this;}public bool CheckMoving(){return isMoving;}public void MoveBoat(GameObject boat, Vector3 target, float speed){if (isMoving)return;isMoving = true;boatMovement = CCMoveToAction.GetSSAction(target, speed);this.RunAction(boat, boatMovement, this);}public void MoveRole(GameObject role, Vector3 middle_pos, Vector3 target, float speed){if (isMoving)return;isMoving = true;SSAction ac1 = CCMoveToAction.GetSSAction(middle_pos, speed);SSAction ac2 = CCMoveToAction.GetSSAction(target, speed);roleMovement = CCSequenceAction.GetSSAction(0, 0, new List<SSAction> {CCMoveToAction.GetSSAction(middle_pos, speed), CCMoveToAction.GetSSAction(target, speed)});this.RunAction(role, roleMovement, this);}public void SSActionEvent(SSAction source,SSActionEventType events = SSActionEventType.Competeted,int intParam = 0,string strParam = null,Object objectParam = null){isMoving = false;}
}

controller part

JudgeController 裁判类

裁判类的作用是在每一帧update里判断游戏进行的状态并通知主控制器

就是将原来 FirstController 中的 判断游戏是否结束的逻辑分离出来用一个类实现。

在 Update 中实现判断的逻辑。

当游戏结束,需要通知firstcontroller时,我们在firstCotroller 中添加一个回调函数,在裁判类中调用该回调函数通知firstcontroller。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;// 裁判控制器类,判断游戏进行的状态并通知主控制器
public class JudgeController : MonoBehaviour
{public FirstController sceneController;public Land rightLand;public Land leftLand;public Boat boat;// Start is called before the first frame updatevoid Start(){this.sceneController = (FirstController)SSDirector.GetInstance().CurrentSceneController;this.rightLand = sceneController.rightLandController.GetLand();this.leftLand = sceneController.leftLandController.GetLand();this.boat = sceneController.boatController.GetBoatModel();}// Update is called once per framevoid Update(){if (sceneController.isRunning == false){return;}if (rightLand.priestCount == 3){// win, callbacksceneController.JudgeResultCallBack("You win!!");return;}else{int leftPriestCount, rightPriestCount, leftDevilCount, rightDevilCount;leftPriestCount = leftLand.priestCount + (boat.isRight ? 0 : boat.priestCount);rightPriestCount = 3 - leftPriestCount;leftDevilCount = leftLand.devilCount + (boat.isRight ? 0 : boat.devilCount);rightDevilCount = 3 - leftDevilCount;if ((leftPriestCount != 0 && leftPriestCount < leftDevilCount) || (rightPriestCount != 0 && rightPriestCount < rightDevilCount)){// losesceneController.JudgeResultCallBack("Game over!!");return;}}}
}

FirstController 场景主控制器

与v1版本主要不同:不实现移动和检查的逻辑,交由CCActionManager与JudgeController类实现。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class FirstController : MonoBehaviour, ISceneController, IUserAction
{// 控制器public LandController leftLandController, rightLandController;public BoatController boatController;public RoleController[] roleControllers;// 比较简单不单独创建控制器River river;// 场景是否正在运行public bool isRunning;public float time;public CCActionManager actionManager;public float speed = 5;public void LoadResources(){// 场景是否正在运行isRunning = true;// 实例化role ControllersroleControllers = new RoleController[6];for (int i = 0; i < 6; ++i){roleControllers[i] = new RoleController();roleControllers[i].CreateRole(DefaultPosition.role_land[i], i < 3 ? true : false, i);}// 实例化land controllerleftLandController = new LandController();leftLandController.CreateLand(DefaultPosition.left_land);leftLandController.GetLand().land.name = "left_land";rightLandController = new LandController();rightLandController.CreateLand(DefaultPosition.right_land);rightLandController.GetLand().land.name = "right_land";// 添加人物并放置在左岸  foreach (RoleController roleController in roleControllers){roleController.GetRoleModel().role.transform.localPosition =leftLandController.AddRole(roleController.GetRoleModel());}// 添加船只控制器boatController = new BoatController();boatController.CreateBoat(DefaultPosition.left_boat);// 创建河流对象river = new River(DefaultPosition.river);time = 60;}public void MoveBoat(){if (isRunning == false || actionManager.CheckMoving() == true) return;Vector3 target;if (boatController.GetBoatModel().isRight){target = DefaultPosition.left_boat;}else{target = DefaultPosition.right_boat;}actionManager.MoveBoat(boatController.GetBoatModel().boat, target, speed);boatController.GetBoatModel().isRight = !boatController.GetBoatModel().isRight;}public void MoveRole(Role roleModel){if (isRunning == false || actionManager.CheckMoving() == true) return;Vector3 middle_pos;Vector3 target;if (roleModel.inBoat){if (boatController.GetBoatModel().isRight){target = rightLandController.AddRole(roleModel);}else{target = leftLandController.AddRole(roleModel);}middle_pos = new Vector3(roleModel.role.transform.localPosition.x, target.y, target.z);actionManager.MoveRole(roleModel.role, middle_pos, target, speed);roleModel.onRight = boatController.GetBoatModel().isRight;boatController.RemoveRole(roleModel);}else{if (boatController.GetBoatModel().isRight == roleModel.onRight){if (roleModel.onRight){rightLandController.RemoveRole(roleModel);}else{leftLandController.RemoveRole(roleModel);}target = boatController.AddRole(roleModel);middle_pos = new Vector3(target.x, roleModel.role.transform.localPosition.y, target.z);actionManager.MoveRole(roleModel.role, middle_pos, target, speed);}}}public void Restart(){SSDirector.ReloadCurrentScene();}public void JudgeResultCallBack(string result){this.gameObject.GetComponent<UserGUI>().SetMessage(result);this.gameObject.GetComponent<UserGUI>().IsGameEnd = true;this.isRunning = false;}void Awake(){SSDirector.GetInstance().CurrentSceneController = this;LoadResources();this.gameObject.AddComponent<UserGUI>();this.gameObject.AddComponent<CCActionManager>();this.gameObject.AddComponent<JudgeController>();}void Update(){}
}

view part

基本没有改动,逻辑参考v1版本的博客说明。

代码地址

github地址

这篇关于lab06:牧师与魔鬼游戏 动作分离版的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

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

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储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.功能

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

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

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

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

火柴游戏java版

代码 /*** 火柴游戏* <p>* <li>有24根火柴</li>* <li>组成 A + B = C 等式</li>* <li>总共有多少种适合方式?</li>* <br>* <h>分析:</h>* <li>除去"+"、"="四根,最多可用火柴根数20根。</li>* <li>全部用两根组合成"1",最大数值为1111。使用枚举法,A和B范围在0~1111,C为A+B。判断</li>** @

国产游戏行业的崛起与挑战:技术创新引领未来

国产游戏行业的崛起与挑战:技术创新引领未来 近年来,国产游戏行业蓬勃发展,技术水平不断提升,许多优秀作品在国际市场上崭露头角。从画面渲染到物理引擎,从AI技术到服务器架构,国产游戏已实现质的飞跃。然而,面对全球游戏市场的激烈竞争,国产游戏技术仍然面临诸多挑战。本文将探讨这些挑战,并展望未来的机遇,深入分析IT技术的创新将如何推动行业发展。 国产游戏技术现状 国产游戏在画面渲染、物理引擎、AI

第四次北漂----挣个独立游戏的素材钱

第四次北漂,在智联招聘上,有个小公司主动和我联系。面试了下,决定入职了,osg/osgearth的。月薪两万一。 大跌眼镜的是,我入职后,第一天的工作内容就是接手他的工作,三天后他就离职了。 我之所以考虑入职,是因为 1,该公司有恒歌科技的freex平台源码,可以学学,对以前不懂的解解惑。 2,挣点素材钱,看看张亮002的视频,他用了6000多,在虚幻商城买的吸血鬼游戏相关的素材,可以玩两年。我

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

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

nyoj 1038 纸牌游戏

poj 的一道改编题,说是翻译题更恰当,因为只是小幅度改动。 一道模拟题,代码掌控能力比较好,思维逻辑清晰的话就能AC。 代码如下: #include<stdio.h>#include<string.h>#include<algorithm>using namespace std;struct node{char c[5];int rk;char da[5];int nu

如果出一个名叫白神话悟空的游戏

最近黑神话由于与原著不符引起了原著派的争议。 所以我在摸鱼的时候想到如果游科或者某个别的公司“痛改前非”不夹带私货完全复刻吴承恩百回版剧情制作一个“重走西游路”的游戏,会有一个什么样的销量?(设定为原著派已经多方渠道认证,此游戏的确没有夹带私货,绝大部分复刻了原著剧情) 游戏玩法我想了几类 超长线性有岔路蜈蚣形状地图,蜈蚣的腿部是探索区域和支线,重走西游路线,开篇就是开始取经前唐玄宗御弟cg