联机游戏的前后端交互逻辑(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

相关文章

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

Python与Java交互出现乱码的问题解决

《Python与Java交互出现乱码的问题解决》在现代软件开发中,跨语言系统的集成已经成为日常工作的一部分,特别是当Python和Java之间进行交互时,编码问题往往会成为导致数据传输错误、乱码以及难... 目录背景:为什么会出现乱码问题产生的场景解决方案:确保统一的UTF-8编码完整代码示例总结在现代软件

Linux搭建单机MySQL8.0.26版本的操作方法

《Linux搭建单机MySQL8.0.26版本的操作方法》:本文主要介绍Linux搭建单机MySQL8.0.26版本的操作方法,本文通过图文并茂的形式给大家讲解的非常详细,感兴趣的朋友一起看看吧... 目录概述环境信息数据库服务安装步骤下载前置依赖服务下载方式一:进入官网下载,并上传到宿主机中,适合离线环境

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

最新Spring Security实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)

《最新SpringSecurity实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)》本章节介绍了如何通过SpringSecurity实现从配置自定义登录页面、表单登录处理逻辑的配置,并简单模拟... 目录前言改造准备开始登录页改造自定义用户名密码登陆成功失败跳转问题自定义登出前后端分离适配方案结语前言

Java逻辑运算符之&&、|| 与&、 |的区别及应用

《Java逻辑运算符之&&、||与&、|的区别及应用》:本文主要介绍Java逻辑运算符之&&、||与&、|的区别及应用的相关资料,分别是&&、||与&、|,并探讨了它们在不同应用场景中... 目录前言一、基本概念与运算符介绍二、短路与与非短路与:&& 与 & 的区别1. &&:短路与(AND)2. &:非短

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

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

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

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