用23种设计模式打造一个cocos creator的游戏框架----(七)代理模式

news2025/1/21 5:54:46

1、模式标准

模式名称:代理模式

模式分类:结构型

模式意图:为其他对象提供一种代理以控制对这个对象的访问。

结构图:

适用于:

  1. 远程代理:也称为大使,这是最常见的类型,在分布式对象通信中被用于表示运行在不同地址空间的对象。

  2. 虚拟代理:根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。

  3. 安全代理:用来控制真实对象访问时的权限。

  4. 智能指引:当调用真实对象时,代理处理另外一些事。

代理模式主要有两个角色:

  • 代理(Proxy):保存一个引用使得代理可以访问实体。提供一个与主题的接口相同的接口,这样代理就可以用来替代实体。控制对实体的存取,并可能负责创建和删除它。

  • 实体(Real Subject):代理所代表的真实对象,是真正的被调用的对象。

2、分析与设计 

代理在日常开发中经常用到,比如通过香港服务器代理去看github上的项目。比如通过抓包工具作为代理,将app的请求过程进行拦截修改,然后在发送出去。代理虽然帮你干了你想干是事情,但是你却不知道它其实干了更多你不知道的。代理的玩法有很多,在游戏框架中我们如何使用代理模式,应该也有很多玩法,这里我只介绍其中一种。

在前端开发中vue的作者用在vue3中用proxy来取代vue2的Object.defineProperty实现响应式。游戏中也经常用到数据与视图的绑定,比如玩家的金币,在数据层player.money = 200时,我们希望页面上的所有显示金币数量的地方,都自动自动刷新视图显示为200,且如果数值不变时,你们你触发n多次player.money = 200,都不会触发刷新视图的事件。

3、开始打造

interface IObject {
    operation()
}
class RealObject implements IObject {
    operation() {

    }
}

class ProxyObject implements IObject {
    realObject: RealObject;

    constructor(realObject: RealObject) {
        this.realObject = realObject
    }

    public operation(): void {
        //在调用目标对象之前,完成一些操作
        console.log("Before Do Something");
        this.realObject.operation();
        //在调用目标对象之后,完成一些操作
        console.log("After Do Something");
    }
}

 如果是代理对象,就不用自己写一个了,用内部基于 ES6 的 Proxy 实现就够用了

const vmHandler = {
    set(obj, prop, value) {
        // 代理拦截修改
        obj[prop] = value;
        return true
    }
};
let loading_vm: ILoadingVM = {
        progress: 0
    }
let proxy_loading_vm = new Proxy(loading_vm, vmHandler)

我们的目的是给游戏框架整一个数据绑定的功能,所以这里用 ES6 的 Proxy就够了。

4、开始使用

这里用ES6 的 Proxy自带的那个代理,因为我们主要是对数据修改进行代理拦截

因为之前是考虑到多个游戏分离,所以给每个游戏整了一个IGameVM,目前简单点只给ui做了全局的vm

export class DemoVM implements IGameVM {
 
   /**
     * 
     * 唯一的方法出口
     */
    getVMs() {
        return {
            // loadingVM: this._getLoadingVM(),
            gateVM: this._getGateVM(),
            // battleVM: this._getBattleVM(),
        }
    }   

    /**
     * 动态显示数据
     */
    private proxy_gate_vm: IGateVM_JCQ = null
    private _gate_vm: IGateVM_JCQ = {
        ps: 0,
        gold: 0,
        diamond: 0,
        last_battle_id: 0 // 当前最高关卡
    }
    private _getGateVM() {
        if (!xhgame.gui.getUI(xhgame.uiid.Gate_Index)) {
            return this._gate_vm
        }
        if (this.proxy_gate_vm == null && xhgame.gui.getUI(xhgame.uiid.Gate_Index)) {
            const handler = xhgame.gui.getUI(xhgame.uiid.Gate_Index).getComponent(GateView).vmHandler
            // 设计模式12 代理模式
            this.proxy_gate_vm = new Proxy(this._gate_vm, handler);
        }
        return this.proxy_gate_vm
    }
}
export class GateView extends ViewComponent {

    private ps_lable: Label
    private gold_lable: Label
    private diamond_lable: Label
    private last_battle_lable: Label


    protected onLoad(): void {
        this.ps_lable = this.node.getChildByName('top').getChildByName('value').getComponent(Label)
        this.gold_lable = this.node.getChildByName('top').getChildByName('gold').getChildByName('value').getComponent(Label)
        this.diamond_lable = this.node.getChildByName('top').getChildByName('diamond').getChildByName('value').getComponent(Label)
        this.last_battle_lable = this.node.getChildByName('bottom').getChildByName('curBattleIdText').getComponent(Label)
    }


    get vmHandler() {
        const that = this
        return {
            set(obj: IGateVM_JCQ, prop, value) {
                // 如果原先的值一样就不做视图层的修改了
                if (prop == 'ps' && value != obj[prop]) {
                    that.ps_lable.string = value + '/3'
                }
                if (prop == 'gold') {
                    that.gold_lable.string = value
                }
                if (prop == 'diamond') {
                    that.diamond_lable.string = value
                }
                if (prop == 'last_battle_id') {
                    that.last_battle_lable.string = '当前第' + value + '关'
                }
                obj[prop] = value;
                return true
            }
        };
    }
}

    
export class xhgame {

    .....

    /** 当前游戏用到的视图绑定 */
    static get vm() {
        return gameInstance.game.getVM().getVMs()
    }

    ....
}

使用时只需要 

xhgame.vm.gateVM.gold = 200

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1290351.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中文BERT模型预训练参数总结以及转化为pytorch的方法

1.目前针对中文的bert预训练模型有三家: 谷歌发布的chinese_L-12_H-768_A-12 还有哈工大的chinese-bert-wwm / chinese-bert-wwm-ext 以及HuggingFace上的bert-base-chinese(由清华大学基于谷歌的BERT在中文数据集上训练开发的模型,上传在HuggingFace) …

ElasticSearch篇---第四篇

系列文章目录 文章目录 系列文章目录前言一、elasticsearch 是如何实现 master 选举的?二、elasticsearch 索引数据多了怎么办,如何调优,部署?三、说说你们公司 es 的集群架构,索引数据大小,分片有多少?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽…

李宏毅gpt个人记录

参考: 李宏毅机器学习--self-supervised:BERT、GPT、Auto-encoder-CSDN博客 用无标注资料的任务训练完模型以后,它本身没有什么用,GPT 1只能够把一句话补完,可以把 Self-Supervised Learning 的 Model做微微的调整&am…

【改进YOLOv8】融合感受野注意力卷积RFCBAMConv的杂草分割系统

1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 研究背景与意义 随着计算机视觉技术的不断发展,图像分割成为了一个重要的研究领域。图像分割可以将图像中的不同对象或区域进行有效的分离,对于许多应用领…

shell脚本生成随机双色球号码

[rootcentos7 ~]#cat lottery.sh #!/bin/bash #定义零长度数组 arr() length${#arr[]} while [ "${length}" -lt 6 ]do#取1到33的随机数s$[$RANDOM%331]#判断随机数是否在数组中,不在就赋值给数组if [[ ! "${arr[]}" ~ "${s}" ]]then…

什么是神经网络的超参数

1 引言 超参数在神经网络的设计和训练中起着至关重要的作用。它们是在开始训练之前设置的参数,与网络的结构、训练过程和优化算法有关。正确的超参数选择对于达到最优模型性能至关重要。 2 神经网络结构的超参数 层数(Layers): 决…

pyecharts可视化作图1:基金净值-折线图

近期,接触到pyecharts模块,感觉其在可视化作图上比较强大,虽然无法和前端页面相比,但对于基础的数据展示,可以轻松处理。 本期主要以基金净值走势为案例,绘制相应的折线图,由于该模块较为简单&a…

多用户商城系统支付模块 用户支付的钱到哪里去了

多用户商城系统是类似京东天猫的电商平台,用户一般使用微信或者支付宝支付,在购买商品或服务支付后,商家发货或提供服务后,平台需要将钱结算给提供商品或者服务的商户。 这时会涉及平台和商户的结算问题,一般有两种解决…

【Qt开发流程】之对象模型3:对象树及其所有权

描述 Qt对象树是一种基于父子关系的对象管理机制,用于管理Qt应用程序中的所有对象。在Qt中,每个对象都可以拥有一个或多个子对象,并且每个子对象只能属于一个父对象。每个对象的所有权(也称为生存期)由其父对象控制。…

LangChain学习一:模型-实战

文章目录 上一节内容学习目标:模型(models)学习内容一:模型分类学习内容二:不同模型实战3.1 Chat-聊天模型3.1.1 声明3.1.2 Chat-聊天类型实战3.1.2.1 AIMessage(AI 消息)3.1.2.2 HumanMessage&…

力扣46. 全排列(java 回溯法)

Problem: 46. 全排列 文章目录 题目描述思路解题方法复杂度Code 题目描述 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 思路 1.该题目要求求出一个数组的全排列,我们可以利用回溯模拟出一个对数组中所有…

9_企业架构队列缓存中间件分布式Redis

企业架构队列缓存中间件分布式Redis 学习目标和内容 1、能够描述Redis作用及其业务适用场景 2、能够安装配置启动Redis 3、能够使用命令行客户端简单操作Redis 4、能够实现操作基本数据类型 5、能够理解描述Redis数据持久化机制 6、能够操作安装php的Redis扩展 7、能够操作实现…

maven生命周期回顾

目录 文章目录 **目录**两种最常用打包方法:生命周期: 两种最常用打包方法: 1.先 clean,然后 package2.先 clean,然后install 生命周期: 根据maven生命周期,当你执行mvn install时&#xff0c…

JAVA IO:NIO

1.阻塞 IO 模型 ​ 最传统的一种 IO 模型,即在读写数据过程中会发生阻塞现象。当用户线程发出 IO 请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出 CPU。当…

Unity 简单打包脚本

打包脚本 这个打包脚本适用于做demo,脚本放在Editor目录下 using System; using System.Collections; using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine;public class BuildAB {[MenuItem("Tools/递归遍历文件夹下…

构建第一个事件驱动型 Serverless 应用

我相信,我们从不缺精彩的应用创意,我们缺少的把这些想法变成现实的时间和付出。 我认为,无服务器技术真的有助于最大限度节省应用开发和部署的时间,并且无服务器技术用可控的成本,实现了我的那些有趣的想法。 在我 2…

kali学习

目录 黑客法则: 一:页面使用基础 二:msf和Windows永恒之蓝漏洞 kali最强渗透工具——metasploit 介绍 使用永恒之蓝进行攻击 ​编辑 使用kali渗透工具生成远程控制木马 渗透测试——信息收集 域名信息收集 黑客法则: 一&…

Java架构师系统架构设计原则应用

目录 1 导语2 如何设计高并发系统:局部并发原则3 如何设计高并发系统:服务化与拆分4 高可用系统有哪些设计原则?5 如何保持简单轻量的架构-DRY、KISS,YAGNI原则6 如何设计组件间的交互和行为-HCLC,CQS,SOC7 框架层面的发展趋势-约定大于配置想学习架构师构建流程请跳转:…

有源滤波器在矿区配电网中的应用

针对目前有源滤波器应用于矿区谐波治理时电网频率适应能力较低的问题,针对定采样点数字控制系统提出了一种具有频率自适应能力的谐振控制策略。该策略不仅可以实现对电网频率波动的自适应,提高滤波器补偿效果,而且不需要在线对控制器参数进行…

ansible常用模块介绍

ansible运行模块的两种方式 Ad - Hoc 利用 ansible 命令直接完成管理 , 主要用于临时命令使用场景 ansible westos -m shell -a ls /mnt playbook ansible 脚本 , 主要用于大型项目场景 , 需要前期的规划 vim test.yml - hosts: all task…