联机游戏的前后端交互逻辑(Cocos)【第二章 单机stateMachine and dynamicCreation】

本文主要是介绍联机游戏的前后端交互逻辑(Cocos)【第二章 单机stateMachine and dynamicCreation】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前一章我们详细讲解了一种数据驱动的单机游戏框架。

主要思路为,将游戏内所有实体的状态储存在DataManager的state字段下,从输入系统拿到Input,调用DataManager中的applyInput方法进行处理。

其中有一种特殊的Input,作为时间流逝的量度,周期性地使用applyInput方法应用它,达成某些事件累积状态发生改变的效果。

这一章将要讲解状态机和动态创建。

一、stateMachine(状态机)

状态机是一种很常见的概念。在游戏中,一个实体如果只具有有限状态的动画,我们就可以使用状态机进行实体的控制。

举个栗子,一个玩家可能有站着和跑着两种状态,这两种状态下播放的动画是不同的。如果我们想当玩家移动时播放跑着的动画,当玩家站着时播放静止的动画,可以将玩家的两种状态封装到一个状态机中。

如果输入系统没有Input,我们就认为玩家静止,然后设置state为idle。如果输入系统有Input,我们就认为玩家正在跑动,就设置state为run。这样就可以很方便的控制动画的播放。

在Cocos的3.4版本官方开始引入动画状态机的概念,称为Marionette 动画系统。在此之前,需要手动进行状态机的编码。一个只有idle和run两种状态的状态机编码示例如下

import { _decorator, Animation, AnimationClip } from "cc";
import State from "../../Base/State";
import StateMachine, { getInitParamsTrigger } from "../../Base/StateMachine";
import { EntityTypeEnum } from "../../Common";
import { EntityStateEnum, ParamsNameEnum } from "../../Enum";
const { ccclass } = _decorator;@ccclass("ActorStateMachine")
export class ActorStateMachine extends StateMachine {init(type: EntityTypeEnum) {this.type = type;this.animationComponent = this.node.addComponent(Animation);this.initParams();this.initStateMachines();this.initAnimationEvent();}initParams() {this.params.set(ParamsNameEnum.Idle, getInitParamsTrigger());this.params.set(ParamsNameEnum.Run, getInitParamsTrigger());}initStateMachines() {this.stateMachines.set(ParamsNameEnum.Idle, new State(this, `${this.type}${EntityStateEnum.Idle}`, AnimationClip.WrapMode.Loop));this.stateMachines.set(ParamsNameEnum.Run, new State(this, `${this.type}${EntityStateEnum.Run}`, AnimationClip.WrapMode.Loop));}initAnimationEvent() {}run() {switch (this.currentState) {case this.stateMachines.get(ParamsNameEnum.Idle):case this.stateMachines.get(ParamsNameEnum.Run):if (this.params.get(ParamsNameEnum.Run).value) {this.currentState = this.stateMachines.get(ParamsNameEnum.Run);} else if (this.params.get(ParamsNameEnum.Idle).value) {this.currentState = this.stateMachines.get(ParamsNameEnum.Idle);} else {this.currentState = this.currentState;}break;default:this.currentState = this.stateMachines.get(ParamsNameEnum.Idle);break;}}
}

这种写法显然比较麻烦,建议使用3.4以上版本的Cocos进行可视化状态机制作。

二、dynamicCreation(动态创建)

也举个例子。玩家射击时发射的子弹,本来是不存在的。我们需要它出现在玩家发射的一瞬间的枪口上。这就需要用到动态创建的概念。

一个比较好的思路是,在DataManager中建立资源的Map用于维护各种需要加载或者复用的资源。在游戏初始化的时候,把所有资源都加载到DataManager的Map中。比如,我可能需要加载子弹的prefab,然后在战斗过程中动态的加载它。为此我需要先建立一个资源名称和资源路径的映射Map

resourceMap:<ResourceTypeEnum,string> = new Map()

然后建立一个prefabMap来将资源名称映射到对应的的prefab上

prefabMap:<ResourceTypeEnum,cc.Prefab> = new Map()

在游戏初始化的时候对这个map进行赋值,假定我们的Bullet预制体位于resources的bullet/bullet1

onLoad(){DataManager.Instance.resourceMap.set(ResourceTypeEnum.Bullet,'bullet/bullet1')
}

然后加载资源

cc.resources.load(DataManager.Instance.resourceMap.get(ResouceTypeEnum.Bullet),cc.Prefab,(pre)=>{DataManager.Instance.prefabMap.set(ResouceTypeEnum.Bullet,pre)
})

加载完毕后,我们就可以通过DataManager里面的prefabMap映射方便地获取到子弹的prefab,然后进行动态创建。

一个可能的代码示例如下

onLoad(){EventManager.Instance.on(EventTypeEnum.PlayerShoot,this.createBullet,this)...
}createBullet(position:cc.Vec2,direction:cc.Vec2){const bullet = cc.instantiate(DataManager.Instance.prefabMap.get(ResourceTypeEnum.Bullet))DataManager.Instance.stage.addChild(bullet)bullet.setPosition(position.x,position.y)const angle =direction.x > 0? rad2Angle(Math.asin(direction.y / side)): rad2Angle(Math.asin(-direction.y / side)) + 180;this.node.setRotationFromEuler(0, 0, angle);
}

在这段代码中,我们先监听了PlayerShoot这个事件,当玩家发射子弹触发这个事件的时候,我们就调用createBullet这个函数,传入position和direction两个参数。通过资源名称,利用DataManager中的map映射到对应的prefab,获取prefab之后,我们调用instantiate方法进行实例化,将新生成子弹的父节点设为舞台,然后设置子弹的位置和方向。

这仅仅是一个很简单的动态创建栗子。值得注意的是,动态创建实体很消耗电脑的性能。更加优越的解决方案是建立对象池。这个我们下节再讲。

这篇关于联机游戏的前后端交互逻辑(Cocos)【第二章 单机stateMachine and dynamicCreation】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

基于WinForm+Halcon实现图像缩放与交互功能

《基于WinForm+Halcon实现图像缩放与交互功能》本文主要讲述在WinForm中结合Halcon实现图像缩放、平移及实时显示灰度值等交互功能,包括初始化窗口的不同方式,以及通过特定事件添加相应... 目录前言初始化窗口添加图像缩放功能添加图像平移功能添加实时显示灰度值功能示例代码总结最后前言本文将

Python开发围棋游戏的实例代码(实现全部功能)

《Python开发围棋游戏的实例代码(实现全部功能)》围棋是一种古老而复杂的策略棋类游戏,起源于中国,已有超过2500年的历史,本文介绍了如何用Python开发一个简单的围棋游戏,实例代码涵盖了游戏的... 目录1. 围棋游戏概述1.1 游戏规则1.2 游戏设计思路2. 环境准备3. 创建棋盘3.1 棋盘类

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

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

衡石分析平台使用手册-单机安装及启动

单机安装及启动​ 本文讲述如何在单机环境下进行 HENGSHI SENSE 安装的操作过程。 在安装前请确认网络环境,如果是隔离环境,无法连接互联网时,请先按照 离线环境安装依赖的指导进行依赖包的安装,然后按照本文的指导继续操作。如果网络环境可以连接互联网,请直接按照本文的指导进行安装。 准备工作​ 请参考安装环境文档准备安装环境。 配置用户与安装目录。 在操作前请检查您是否有 sud

uniapp设置微信小程序的交互反馈

链接:uni.showToast(OBJECT) | uni-app官网 (dcloud.net.cn) 设置操作成功的弹窗: title是我们弹窗提示的文字 showToast是我们在加载的时候进入就会弹出的提示。 2.设置失败的提示窗口和标签 icon:'error'是设置我们失败的logo 设置的文字上限是7个文字,如果需要设置的提示文字过长就需要设置icon并给

火柴游戏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

Debugging Lua Project created in Cocos Code IDE creates “Waiting for debugger to connect” in Win-7

转自 I Installed Cocos Code IDE and created a new Lua Project. When Debugging the Project(F11) the game window pops up and gives me the message waiting for debugger to connect and then freezes. Also a

逻辑表达式,最小项

目录 得到此图的逻辑电路 1.画出它的真值表 2.根据真值表写出逻辑式 3.画逻辑图 逻辑函数的表示 逻辑表达式 最小项 定义 基本性质 最小项编号 最小项表达式   得到此图的逻辑电路 1.画出它的真值表 这是同或的逻辑式。 2.根据真值表写出逻辑式   3.画逻辑图   有两种画法,1是根据运算优先级非>与>或得到,第二种是采

UMI复现代码运行逻辑全流程(一)——eval_real.py(尚在更新)

一、文件夹功能解析 全文件夹如下 其中,核心文件作用为: diffusion_policy:扩散策略核心文件夹,包含了众多模型及基础库 example:标定及配置文件 scripts/scripts_real:测试脚本文件,区别在于前者倾向于单体运行,后者为整体运行 scripts_slam_pipeline:orb_slam3运行全部文件 umi:核心交互文件夹,作用在于构建真