[开发者心得] 【模块管理和数据中心】——为什么需要模块管理?①

[复制链接]
3039 |3
空伊伊 发表于 2023-3-9 19:32:51 | 显示全部楼层 |阅读模式

本帖最后由 空伊伊 于 2023-11-8 17:33 编辑

本帖最后由 空伊伊 于 2023-11-8 17:32 编辑

模块管理和数据中心

目录

为什么要使用模块管理①

模块管理的使用步骤②

模块管理的各功能介绍③

为什么要使用数据中心④

数据中心的使用步骤⑤

数据中心的各功能介绍⑥

为什么需要模块管理?

image-20230927163702

(现在分别通过 不使用模块管理 以及 使用模块管理 的方式来实现上图中的游戏功能)

1.不使用模块管理编写游戏逻辑

游戏脚本

const Req_Atk = "Req_Atk"
const Be_Atk = "Be_Atk"
const Req_SendProp = "Req_SendProp"
const GetProp = "GetProp"

export class GameScript {

    /**玩家的背包数据 */
    public client_myBagData = ["攻击道具", "物品1", "物品2"];

    public init(): void {

        // 客户端初始化
        if (SystemUtil.isClient()) {

            // 监听被攻击事件
            Event.addServerListener(Be_Atk, (attacker: Player) => {
                // 从背包中取出一个道具
                let prop = this.client_myBagData.pop()
                // 派发发送道具事件
                Event.dispatchToServer(Req_SendProp, attacker, prop)
            })

            // 监听获取道具事件
            Event.addServerListener(GetProp, (prop) => {
                this.client_AddProp(prop)
            })
        }

        // 服务端初始化
        if (SystemUtil.isServer()) {

            // 监听请求攻击事件
            Event.addClientListener(Req_Atk, (attacker: Player, targetPlayer: Player) => {
                // 派发被攻击事件
                Event.dispatchToClient(targetPlayer, Be_Atk, attacker)
            })

            // 监听请求发送事件
            Event.addClientListener(Req_SendProp, (sender: Player, attacker: Player, prop) => {
                // 派发获取道具事件
                Event.dispatchToClient(attacker, GetProp, prop)
            })
        }
    }

    /**客户端请求攻击targetPlayer */
    public client_ReqAtk(targetPlayer: Player) {
        if (this.client_checkAtkProp()) {
            Event.dispatchToServer(Req_Atk, targetPlayer)
        }
    }

    /**检查背包里否有攻击道具 */
    public client_checkAtkProp(): boolean {
        let index = this.client_myBagData.indexOf("攻击道具")
        if (index != -1) {
            this.client_myBagData.splice(index, 1);
            return true
        } else {
            return false
        }
    }

    /**给自己的背包增加一个道具 */
    public client_AddProp(prop) {
        this.client_myBagData.push(prop)
        console.log(JSON.stringify(this.client_myBagData))
    }

}

调用

@Component
export default class GameStart extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        // 创建一个游戏脚本
        let game = new GameScript()
        // 初始化游戏脚本
        game.init()

        if (SystemUtil.isClient()) {
            // 五秒后攻击一次其他玩家
            setTimeout(() => {
                let otherPlayer = Player.getAllPlayers().find((v) => v != Player.localPlayer)
                game.client_ReqAtk(otherPlayer)
            }, 5000);
        }
    }
}

可以看到,不使用模块管理的话,代码会有以下几个明显的缺点:

1.代码需要书写大量的客户端与服务器之间的通信事件(Events相关的代码重复出现次数过多) 2.难以区分出客户端与服务端 3.多个功能耦合在一起,一个脚本的代码量过多,导致后续维护困难

2.使用模块管理编写游戏逻辑(未使用数据模块)

背包模块(客户端)

/**
 * 背包模块(客户端)
 */
export class BagModuleC extends ModuleC<BagModuleS, null>{
    /**玩家的背包数据 */
    public client_myBagData = ["攻击道具", "物品1", "物品2"];

    /**检查背包里否有攻击道具 */
    public checkAtkProp(): boolean {
        let index = this.client_myBagData.indexOf("攻击道具")
        if (index != -1) {
            this.client_myBagData.splice(index, 1);
            return true
        } else {
            return false
        }
    }

    /**给自己的背包增加一个道具 */
    public net_addProp(prop) {
        this.client_myBagData.push(prop)
    }

    /**从自己的背包中移除一个道具 */
    public removeProp(prop) {
        let index = this.client_myBagData.indexOf(prop)
        if (index != -1) {
            this.client_myBagData.splice(index, 1);
        }
    }
}

背包模块(服务端)

/**
 * 背包模块(服务端)
 */
export class BagModuleS extends ModuleS<BagModuleC, null>{
    /**给targetPlayer添加道具prop */
    public addPropByPlayer(targetPlayer: Player, prop) {
        this.getClient(targetPlayer).net_addProp(prop)
    }
}

战斗模块(客户端)

/**
 * 战斗模块(客户端)
 */
export class FightModuleC extends ModuleC<FightModuleS, null>{
    /**请求攻击targetPlayer */
    public reqAtk(targetPlayer: Player) {
        // 获得背包客户端模块
        let bagModuleC = ModuleService.getModule(BagModuleC)
        if (bagModuleC.checkAtkProp()) {
            // 如果有攻击道具,通知服务端发起攻击
            this.server.net_ReqAtk(targetPlayer)
        }
    }

    /**被attacker攻击 */
    public net_BeAtk(attacker: Player) {
        let bagModuleC = ModuleService.getModule(BagModuleC)
        let prop = bagModuleC.client_myBagData.pop()
        // 通知服务端发送道具
        this.server.net_SendProp(attacker, prop)
    }
}

战斗模块(服务端)

/**
 * 战斗模块(服务端)
 */
export class FightModuleS extends ModuleS<FightModuleC, null>{
    /**服务端发起攻击 */
    net_ReqAtk(targetPlayer: Player) {
        // 服务端通知目标执行被攻击
        this.getClient(targetPlayer).net_BeAtk(this.currentPlayer)
    }

    /**服务端发送道具prop给targetPlayer */
    public net_SendProp(targetPlayer: Player, prop) {
        // 获得背包服务端模块
        let bagModuleS = ModuleService.getModule(BagModuleS)
        // 给targetPlayer添加道具
        bagModuleS.addPropByPlayer(targetPlayer, prop)
    }
}

调用

@Component
export default class GameStart extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {

        // 注册模块(作用相当于游戏脚本里的初始化)
        ModuleService.registerModule(BagModuleS, BagModuleC, null)
        ModuleService.registerModule(FightModuleS, FightModuleC, null)

        if (SystemUtil.isClient()) {
            // 五秒后攻击一次其他玩家
            setTimeout(() => {
                let otherPlayer = Player.getAllPlayers().find((v) => v != Player.localPlayer)
                // 获取战斗模块(客户端),调用其攻击方法
                ModuleService.getModule(FightModuleC).reqAtk(otherPlayer)
            }, 5000);
        }
    }
}

可以看到,使用模块管理后,代码得到了以下改善:

1.客户端和服务端分开编写,避免前后端代码难以区分的问题 2.不再需要来回监听和派发事件,只需要在方法前面加上net_即可完成通信事件的调用 3.代码由原来的一个脚本拆成了两个模块,四个class,降低了耦合度,方便多人开发与管理

3.总结

模块管理帮助我们区分开了服务端和客户端,让代码的调用域变得清楚明了。同时模块管理为我们封装好了事件调用,让我们不用再编写大量的Events代码。此外,模块管理的一个更大作用:“数据同步”,我会在下一节数据中心相关内容里进行讲述。

(如果你是代码编写的新手,可能会觉得使用模块管理后反而代码量增多,逻辑也变复杂了。其实不然,当你制作的游戏复杂度提高之后,你就能体会到模块管理的好处了。)

下一节:模块管理的使用步骤②

回复

使用道具 举报

空伊伊楼主 发表于 2023-3-13 19:18:34 | 显示全部楼层
模块管理和数据中心目前已经是集成在编辑器里边了,会随着版本更新一直维护。大家可以放心使用~~
回复

使用道具 举报

喵喵哭唧唧 发表于 2023-3-16 17:03:46 | 显示全部楼层
大佬你写的太好了,我来拜读你的神作
回复

使用道具 举报

喵喵哭唧唧 发表于 2023-3-16 17:07:28 | 显示全部楼层
太强了
回复

使用道具 举报

热门版块
快速回复 返回顶部 返回列表