Giter Club home page Giter Club logo

minigameclientframe's Introduction

休闲游戏前端框架

基于cocos creator内含部分微信小游戏API

游戏案例

微信小游戏-逻辑大挑战

框架定位

基于框架快速开发包括但不限于微信百度头条等平台小游戏。统一的框架设计便于后续项目的维护与升级,灵活的业务组件方便应对不同平台的定制需求。

架构特色

  • 继承于cc.Object的基类对象
  • 继承于cc.Component的基类组件
  • 基于装饰器模式设计的业务组件(有效应对多渠道定制,功能AB测试等)
  • 场景管理器
  • 模块管理器
  • 弹窗管理器
  • 图集资源管理器
  • 音频管理器
  • 消息通知中心
  • http网络请求封装
  • 微信小游戏部分API
  • 游戏常用函数封装

使用说明

在创建控制器、数据等对象时尽量继承FrameworkObject,在创建UI组件时尽量继承FrameworkComponent。因为里面已经集成了消息中心,图集资源管理,场景管理器,音效管理器,业务组件等常用接口,使用非常方便也便于代码风格统一。

业务组件

基于装饰器模式设计,有效解决多渠道对界面和功能定制需求,不用在源码中处处添加if...else..语句。当然也可以将游戏中原有脚本对比成Node节点,而业务组件对比成Component,将业务组件绑定到原有脚本上,对原有功能原有脚本进行扩展,函数替换,修改等。要添加业务组件的对象需继承FrameworkObject或者FrameworkComponent,业务组价必须继承FrameworkBehavior

  • 替换原函数

    import { ABehavior } from "./ABehavior"
    class AObject extends FrameworkObject {
        protected readonly TAG: string = "AObject";
        public num: number = 1;
        init() {
            this.autoBindFunction(ABehavior);
            functionNameA();
            functionNameB();
        }
    
        functionNameA() {
            this.LOGD(this.TAG, "functionNameA_" + this.num);    
        }
    
        functionNameB() {
            this.LOGD(this.TAG, "functionNameB_" + this.num);
        }
    }
    
    import { AObject } from "./AObject"
    class ABehavior extends FrameworkBehavior {
        protected readonly TAG: string = "ABehavior";
        protected exportFunctionNameList: string[] = [
            'functionNameA',
            'functionNameB'
        ];
    
        functionNameA() {
            let object = this.object as AObject
            object.num = 2;
            this.object.LOGD(this.TAG, "functionNameA_", object.num);
        }
    
        functionNameB() {
            let object = this.object as AObject
            object.num = 2;
            this.object.LOGD(this.TAG, "functionNameB_", object.num);
        }
    }

    AObject中的函数functionNameAfunctionNameB将会被替换成ABehavior中对应的functionNameAfunctionNameB函数。因此执行代码会发现输出

    ABehavior functionNameA_2
    ABehavior functionNameB_2
    
  • 扩展函数

    import { ABehavior } from "./ABehavior"
    class AObject extends FrameworkObject {
        protected readonly TAG: string = "AObject";
    
        init() {
            this.autoBindFunction(ABehavior);
            functionNameA(1);
            functionNameB(1); 
        }
    
        functionNameA(num: number): number {
            this.LOGD(this.TAG, "functionNameA_" + num);
            return num + 1;
        }
    
        functionNameB(num: number) {
            this.LOGD(this.TAG, "functionNameB_" + num);
        }
    }
    
    import { AObject } from "./AObject"
    class ABehavior extends FrameworkBehavior {
        protected readonly TAG: string = "ABehavior";
    
        functionNameA(num: number, returnValue: number) {
            this.LOGD(this.TAG, "functionNameA_" + (num + returnValue));
        }
    
        functionNameB(num: number) {
            this.LOGD(this.TAG, "functionNameB_" + num);
        }
    
        protected manualBindFunction() {
            // 函数名不必一直
            // 先执行AObject中functionNameA 在执行ABehavior中functionNameA 并且AObject中functionNameA函数如果有返回值,则将返回值作为参数传递给ABehavior中functionNameA函数
            this.bindFunction("functionNameA", "functionNameA", false, false);
            // 先执行ABehavior中functionNameA 在执行AObject中functionNameA
            this.bindFunction("functionNameA", "functionNameA", false, true);
        }
    }

    执行结果

    AObject functionNameA_1
    ABehavior functionNameA_3
    ABehavior functionNameB_1
    AObject functionNameB_1

场景管理器

单例设计模式,初始化的时候指定从当前场景(from)可以切换到哪些场景(to),类似状态机有效控制场景的切换。

  • 初始化
    export interface SceneParams {
        from: string,       // scene name
        to: string[]        // [scene name]
    }
    public init(params: SceneParams[], currSceneName: string): void;
  • 切换场景
    public changeScene(from: string, to: string, onBeforeLoadScene?: () => void, onLaunched?: () => void, fail?: (res: ChangeSceneResult) => void, progress?: (completed: number, total: number, item: any) => void): void;
    如果脚本继承于FrameworkObject或者FrameworkComponent可以直接在脚本中调用(推荐使用)
    this.changeScene(from, to, onBeforeLoadScene, onLaunched, fail, progress)

模块管理器

单例设计模式,在游戏启动时初始化必要的游戏模块。模块控制器必须继承FrameworkObject

  • 模块注册

    在模块控制器脚本中实现init函数,模块被实例化时将会被调用,并且为init函数传入initParams参数

    public registerModule(moduleName: string, ModuleCtr: new () => FrameworkObject, initParams?: any): FrameworkObject;
  • 移除模块

    在游戏退出某个场景或者某些操作之后,确定该模块暂时不在使用可以将其销毁并且移除。移除模块时,如果模块控制器实现函数onDestroy,那么onDestroy函数将会被调用。

    public removeModule(moduleName: string);
  • 获取模块

    比如在UI脚本中,需要获取该脚本所属模块控制器中的某些数据或者调用模块控制器中的函数。但不建议跨模块控制器调用,因为模块分化的目的就是为了降低代码耦合度,而跨模块调用会增加代码耦合度,并且代码不稳定性增大。

    public getModule(moduleName: string): MoudleStruct;

弹窗管理器

单例设计模式,管理游戏弹窗。弹窗队列可以控制弹窗顺序弹出,弹出时是否隐藏已经弹出接口,是否需要遮罩,是否可重复弹出等。如果一个弹窗在两个及以上界面弹出,建议使用弹窗管理器。如果确认此弹窗只在一个界面使用,不需要使用cc.loader那么不必将Prefab放在resource目录下,可以减小包体积。

  • 打开弹窗

    如果弹窗脚本有实现对应函数,那么会依次调用willShowinitDatashowedinitData会传入data;

    interface OpenWindowParams {
        isSequence?: boolean;               // 是否在队列等待 default true
        hideOther?: boolean;                // 是否隐藏其他界面 default false
        data?: any;                         // 参数
        touchMaskClose?: boolean;           // 点击遮罩关闭 default false
        repeat?: boolean;                   // 是的支持在队列中存在多个 default true
        needMask?: boolean;                 // 是否需要mask default true
        maskOpacity?: number;                // mask透明度
        errorCallback?: Function            // 失败回调
    }
    public openWindow<T extends cc.Component>(prefabPath: string, component: new () => T, params?: OpenWindowParams);
  • 关闭弹窗

    如果使用openWindow接口打开的弹窗,一定要使用closeWindow去关闭。如果弹窗脚本实现了willDestroy,那么在销毁前会调用willDestroy

    public closeWindow<T extends cc.Component>(component: new () => T);

图集资源管理器

单例设计模式,为图集资源提供缓存,对外提供两个接口为cc.Sprite设置纹理。

  • 设置纹理

    // 为节点上的精灵设置纹理
    public setSpriteFrameForNode(node: cc.Node, url: string);
    // 为精灵设置纹理
    public setSpriteFrameForSprite(sprite: cc.Sprite, url: string);

    如果脚本继承于FrameworkObject或者FrameworkComponent可以直接在脚本中调用(推荐使用)

    this.setSpriteFrameForNode(node, url);
    this.setSpriteFrameForSprite(sprite, url);

音频管理器

单例设计模式,在游戏切入后台会自动暂停播放,回到前台会恢复。提供音乐和音频的播放,暂停,静音等接口。

  • 播放音频

    // 播放音乐
    public playMusic(url: string, loop: boolean = true);
    // 播放音效
    public playEffectSound(url: string);

    如果脚本继承于FrameworkObject或者FrameworkComponent可以直接在脚本中调用(推荐使用)

    // 播放音乐
    this.playMusic(url, loop);
    // 播放音效
    this.playEffect(url);

消息通知中心

单例设计模式,游戏本地消息中心。

  • 监听消息

    public static listen(event: string, callback: (params?: any) => void, target?: any);
    public listen(event: string, callback: (params?: any) => void, target?: any);

    如果脚本继承于FrameworkObject或者FrameworkComponent可以直接在脚本中调用(推荐使用)

    this.listen(event, callback, target);
  • 移除消息

    在对象被销毁时一定要要

    // 移除指定消息
    public static ignore(event: string, callback: (params?: any) => void, target?: any): void;
    public ignore(event: string, callback: (params?: any) => void, target?: any): void;
    // 移除target监听的所有消息
    public static ignoreAllTarget(target: any): void;
    public ignoreAllTarget(target: any): void;

    如果脚本继承于FrameworkObject或者FrameworkComponent可以直接在脚本中调用(推荐使用)

    // 移除指定消息
    this.ignore(event, callback, target);
    // 移除target监听的所有消息
    this.ignoreAllTarget(target);

http网络请求封装

兼容微信平台和浏览器

  • 请求
    export interface HttpBaseParams {
        url: string,
        data?: string | { [key: string]: any },
        header?: { [name: string]: string },
        method?: "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "TRACE" | "CONNECT",  //default GET 
        dataType?: "json" | "arraybuffer",                                          //default json
        responseType?: string,                                                      //default text
        timeout?: number,
        success?: (res: any) => void,
        fail?: (res?: any) => void,
        complete?: (res?: any) => void
    }
    public static httpRequest(params: HttpBaseParams);

微信相关

授权

将逐渐AuthComponent绑定到对应节点,如果玩家没有授权则会在对应节点上创建透明授权按钮,玩家授权成功游戏内创建的所有透明授权按钮将会被销毁。

分享

封装相关接口在WechatShare,按照微信官方文档说明调用即可。建议游戏自行再次封装区分平台

  • 示例
    export class ShareManager extends FrameworkObject {
        
        protected static TAG: string = "ShareManager";
        
        static showTransmitMenu() {
            if (cc.sys.platform == cc.sys.WECHAT_GAME) {
                WechatShare.updateShareMenu();
                WechatShare.showShareMenu({
                    success: () => { },
                    fail: () => {}
                });
                WechatShare.onShareAppMessage(() => {
                    return  { title: "", imageUrl: "" }
                });
            }
        }
    
        static shareAppMessage() {
            if (cc.sys.platform == cc.sys.WECHAT_GAME) {
                WechatShare.shareAppMessage({ title: "", imageUrl: "" });
            }
        }
    }

banner广告

一个adUnitId对应唯一banner实例,如果两次展示同一adUnitId对应的banner但是位置发生变化,则回销毁之前的banner实例,重新初始化。

  • 展示
    static showBanner(params: {
        adUnitId: string,
        type: "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right",
        adIntervals?: boolean,
        errorCallBack?: (res: {errMsg: string, errCode: number}) => void
    });
  • 隐藏
    // 隐藏指定banner
    static hideBanner(adUnitId: string);
    // 隐藏所有banner
    static hideAllBanners();
  • 销毁
    // 销毁指定banner
    static destroyBanner(adUnitId: string);
    // 销毁所有banner
    static destroyAllBanner();

视频广告

  • 展示
    static showRewardedVideoAd(params: {
        adUnitId: string,
        finished: () => void,
        unfinish: () => void,
        errorCallBack?: (res: {errMsg: string, errCode: number})=> void
    });

插屏广告

  • 展示
    static showInterstitialAd(params: {
        adUnitId: string,
        close?: () => void
        errorCallBack?: (res: {errMsg: string, errCode: number})=> void 
    });

格子广告

  • 展示
    static showGridAd(params: {
        adUnitId: string,
        adTheme: "white" | "black",
        gridCount: number,
        style: { left: number, top: number, width: number, opacity: number },
        resize?: (gridAd: { style: { top: number, left: number, width: number, height: number, realWidth: number, realHeight: number } }) => void,
        errorCallback?: (res: {errMsg: string, errCode: number}) => void 
    })
  • 隐藏
    static hideGridAd(adUnitId: string);

欢迎讨论

EMail: [email protected]

minigameclientframe's People

Contributors

huxiaohei avatar

Watchers

James Cloos avatar

Forkers

tomato-cc bmjoy

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.