preface

A previous post shared my process and thoughts for designing and implementing a generic TypeScript game UI framework, but didn’t go into detail on how to use it.

Article link: Design and implementation of general game UI framework

How to use ~

introduce

Display-ctrl is a typescript-based, zero-dependency, cross-engine, efficient, flexible, highly extensible display control library (UI framework library)

You can customize the resource handling and controller base classes based on the project and the engine used by the project.

A reasonable abstraction base allows you to inherit from the manager base class and use the base class interface to easily extend the interface to suit your needs.

The library also uses TypeScript’s high-level type inference, giving you an extremely comfortable interface call experience.

This library has no dependencies and can be used alone.

Libraries based on both CocosCreator2.4.2 and CocosCreator3D implementations are provided in the repository (including the implementation of the layer management library)

  1. dpctrl-ccc
  2. dpctrl-c3d

github:EasyGameFramework

features

  • Cross-engine, suitable for any TS/JS game/application project
  • Typescript-based programming with higher-order types provides extremely comfortable type hints
  • High extensible
  • High can be customized
  • Zero dependency, can be used alone

How to use it?

The installation

  1. Install via NPM

     npm i @ailhc/display-ctrl   
    Copy the code
  2. Local link NPM package

    A. Clone Project warehouse

     git clone https://github.com/AILHC/EasyGameFrameworkOpen
    Copy the code

    B. In the Packages/display-Ctrl folder

     npm link
    Copy the code

    C. Under the project game project directory

     npm link @ailhc/display-ctrl    
    Copy the code
  3. Use the source code

    A. Clone Project warehouse

     git clone https://github.com/AILHC/EasyGameFrameworkOpen
    Copy the code

    B. Directly copy the ts source code in packages/display-ctrl/ SRC to the project folder

customization

Implementation engine layer

Different engines or projects need to be implemented accordingly. It’s very simple

  1. Controller base class implementation
import{}from "@ailhc/display-ctrl";
export class NodeCtrl implements displayCtrl.ICtrl<cc.Node> { key? :string | any; isLoading? :boolean; isLoaded? :boolean; isInited? :boolean; isShowed? :boolean; needShow? :boolean; needLoad? :boolean; isShowing? :boolean;
    visible: boolean;
    onLoadData: any;
    protected node: cc.Node;
    protected _mgr: displayCtrl.IMgr;
    constructor(dpcMgr? : displayCtrl.IMgr) {
        this._mgr = dpcMgr; } onInit(config? : displayCtrl.IInitConfig<any.any>) :void{ } onShow(config? : displayCtrl.IShowConfig<any.any.any>) :void {
        if (this.node) {
            this.node.active = true;
        }
    }
    getRess(): any[] | string[] {
        return undefined;
    }
    getNode(): cc.Node {
        return this.node;
    }
    onUpdate(updateData: any) :void {
    }
    getFace<T = any>(): T {
        return this as any; } onDestroy(destroyRes? :boolean) :void {
        if (this.node) {
            this.node.destroy(); }}onHide() {
        if (this.node) {
            this.node.active = false; }}forceHide() {
        this.node && (this.node.active = false);
        this.isShowed = false;
    }
    onResize(){}}Copy the code

I’ve provided two implementation references for CocosCreator

  • CocosCreator3d implementation dPCtrL-C3D
  • Dpctrl-ccc is implemented in CocosCreator2.4.2

Can be installed directly (ibid.)

  1. Resource processing interface customization

Each project has its own resource handling requirements, so this part of the logic is decoupled to allow the consumer to inject the resource handler.

//egf-ccc-full DpcTestMainComp.ts
const dpcMgr = new DpcMgr<IDpcTestViewKeyMap, any, IDpcTestViewShowDataMap>();

        dpcMgr.init(
            {
                loadRes: (config) = > {
                    constonLoadData: IDpcTestOnLoadData = config.onLoadData; onLoadData? .showLoading && dtM.uiMgr.showDpc("LoadingView");
                    cc.assetManager.loadAny(config.ress,
                        { bundle: "resources" },
                        (finish, total) = > {
                            console.log(`${config.key}The load:${finish}/${total}`); onLoadData? .showLoading && dtM.uiMgr.updateDpc("LoadingView", { finished: finish, total: total })
                        },
                        (err, items) = > {
                            if (err) {
                                console.error('Load failed', err);
                                config.error && config.error();
                            } else{ config.complete && config.complete(); } onLoadData? .showLoading && dtM.uiMgr.hideDpc("LoadingView"); })},releaseRes: (ctrlIns) = > {
                    const ress = ctrlIns.getRess();
                    if (ress && ress.length) {
                        let asset: cc.Asset;
                        ress.forEach((res: { path: string }) = > {
                            asset = cc.resources.get(res.path);
                            if(asset) { cc.assetManager.releaseAsset(asset); }}); }}})Copy the code

Begin to use

Basic usage (take CocosCreator2.4.2 as an example): Create a normal interface

  • Create a simple interface for prefab

In the test scenario, create a new Node with an image and a spine animation.

Then drag it to resources/ display-Ctrl-test-views

Delete the interface node in the scene

  • Create a new interface controller code file
// DepResView.ts
// Add an interface key declaration to indicate the type in order to call the display interface
declare global {
    interface IDpcTestViewKeyMap {
        DepResView: "DepResView"}}export class DepResView extends NodeCtrl {
    static typeKey = "DepResView";
    private static _ress: { path: string.type: any} [];// Interface prefab resource path
    public static prefabUrl = "display-ctrl-test-views/DepResView";
    onLoadData: IDpcTestOnLoadData = { showLoading: true };
    // Implement the getRess interface to return an array of dependent resources
    getRess() {
        if(! DepResView._ress) { DepResView._ress = [ {path: DepResView.prefabUrl, type: cc.Prefab },
                { path: "test-txts/txt1".type: cc.TextAsset }
            ]
        }
        return DepResView._ress;
    }
    // implement onInit interface to instantiate display node
    onInit() {
        super.onInit()
        this.node = getPrefabNodeByPath(DepResView.prefabUrl);
        this.node.getChildByName("close-icon").on(cc.Node.EventType.MOUSE_DOWN, () = > {
            dtM.uiMgr.hideDpc(this.key); })}// Implement the onShow interface to add display nodes to Canvas(preferably using the layer management library provided by my framework)
    onShow(config: displayCtrl.IShowConfig) {
        super.onShow(config);
        const canvas =  cc.director.getScene().getChildByName("Canvas");
        canvas.addChild(this.node);
    }
    onHide() {
        super.onHide(); }}Copy the code

Here’s a basic set of actions: call the manager interface

  1. According to
// Simple call display
dtM.uiMgr.showDpc("DepResView");// Use double quotes to indicate the type
// Pass data to call display

dtM.uiMgr.showDpc("MutiInsView",onShowData);// Use double quotes to indicate the type
Copy the code

MutiInsView (MutiInsView); MutiInsView (MutiInsView); examples\egf-ccc-full\assets\tests\display-ctrl\view-ctrls\MutiInsView.ts

declare global {
    interface IDpcTestViewKeyMap {
        MutiInsView: "MutiInsView"
    }
    interface IDpcTestViewShowDataMap {
        MutiInsView: { preStr: string.clickCount: number}; }}Copy the code
  1. update

Called when the business needs to update the rendering of the specified interface with data, for example, loading the interface

// Start loading
dtM.uiMgr.updateDpc("LoadingView", { finished: 0.total: 1 });
// Load finished
dtM.uiMgr.updateDpc("LoadingView", { finished: 1.total: 1 });

Copy the code

Examples \ egf-ccC-full \assets\tests\ display-Ctrl-view-ctrls \ mutiinsView.ts

declare global {
    interface IDpcTestViewKeyMap {
        LoadingView: "LoadingView"
    }
    interface IDpcTestUpdateDataMap {
        LoadingView: { finished: number.total: number}}}Copy the code
  1. hidden
dtM.uiMgr.hideDpc("DepResView");// Use double quotes to indicate the type
Copy the code
  1. The destruction
dtM.uiMgr.destroyDpc(dtM.uiMgr.keys.DepResView, true);// The second parameter selects whether to destroy the resource
Copy the code

Custom resource processing display controller

In business development, the resource processing logic of some interfaces may be special and needs to be customized. The framework provides an interface for customized resource processing

  1. Create a custom resource processing display controller
// To inherit displayCtrl.IResHandler, the manager calls the interface implemented by the controller instead of the generic processor interface
export class CustomResHandleView extends NodeCtrl implements displayCtrl.IResHandler {
    static typeKey = "CustomResHandleView";
    private static _ress: string[];
    private static _monsterNames = ["BuleMonster"."GreenMonster"."PurpleMonster"."RedMonster"."YellowMonster"];
    private static _monsterIconDir = "monster_icon";
    private static prefabUrl: string = "display-ctrl-test-views/CustomResHandleView";
    private _monsterIconRess: { path: string.type: any} [];// Customize resource loading
    loadRes(config: displayCtrl.IResLoadConfig): void {
        dtM.uiMgr.showDpc({
            typeKey: dtM.uiMgr.keys.LoadingView,
            showedCb: () = > {
                const randomMonsterNameIndexs = getSomeRandomInt(0, CustomResHandleView._monsterNames.length - 1.2);
                const ress = [];
                this._monsterIconRess = ress;
                randomMonsterNameIndexs.forEach(element= > {
                    ress.push({ path: CustomResHandleView._monsterIconDir + "/" + CustomResHandleView._monsterNames[element], type: cc.SpriteFrame });
                });
                ress.push({ path: CustomResHandleView.prefabUrl, type: cc.Prefab });
                ress.push({ path: "test-txts/txt1".type: cc.TextAsset });
                cc.assetManager.loadAny(ress, { bundle: "resources" }, (finished: number, total: number, item) = > {
                    dtM.uiMgr.updateDpc(dtM.uiMgr.keys.LoadingView,
                        {
                            finished: finished, total: total
                        })
                }, (err, data) = > {
                    if (err) {
                        config.error();
                    } else {
                        config.complete();
                    }
                    dtM.uiMgr.hideDpc("LoadingView"); }); }})}// Customize resource release
    releaseRes(): void {
        cc.assetManager.releaseAsset(cc.resources.get(CustomResHandleView.prefabUrl));
    }
    // omit the code
}
Copy the code

Other interfaces to the manager

The specific interface declaration can be seen in dP-Ctrl-interfaces.ts

  • Obtain dependent resources, which can be used to obtain resources dependent on multiple controllers and preload them in batches
  • Gets a singleton controller instance
  • Preloads the specified controller
  • Creating a Controller Instance

, etc.

Other possibilities

In fact, the main character of the game can also be the display controller instance

Customize more possibilities through IShowConfig, such as page display animation after playback callback

Leverage the underlying interface of the manager to extend the logic for managing the stack UI

The last

Welcome to pay attention to my public account, more content to continue to update

Public number search: play game development

QQ group: 1103157878

Blog homepage: ailhc.github. IO /

The Denver nuggets: juejin. Cn/user / 306949…

github: github.com/AILHC