Editor User Interface

Hi, i’m very new to PlayCanvas and i was wondering if there’s a comprehensive guide on how to build a user interface in the editor. I’ve been looking around but it’sa like putting together a puzzle from different puzzle sets :frowning:

thanks in advance

A user interface that does what?

It needs to be dynamically generated, what i’m trying to achieve is to write a script that will allow on the inspector to add elements to the UI (in this case panels and buttons) according to the needs at hand

Wait, you mean not in a project but adding more buttons to the editor? I dont know if thats even possible.

no no, i mean in the project, her’s the flow i have in. mind:

  • i create a screen element;
  • i attach a script to it that manages what is generated inside of it through attributes, in my case i’m aiming at generating panel-groups that will contain on their turn a series of buttons (also generated via script) something like this:
var DynamicUi = pc.createScript('dynamicUi');

DynamicUi.attributes.add('panelCount', {
    type: 'number',
    default: 2,
    description: 'Number of panels to create (default is 2)'
});


DynamicUi.attributes.add('buttons', {
    type: 'json',
    array: true,
    schema: [{
        name: 'panelIndex',
        type: 'number',
        default: 0,
        description: 'Panel index to which this button belongs'
    }, {
        name: 'label',
        type: 'string',
        default: 'Button',
        description: 'Label of the button'
    }, {
        name: 'image',
        type: 'asset',
        description: 'Image for the button'
    }, {
        name: 'backgroundColor',
        type: 'rgb',
        default: [1, 1, 1],
        description: 'Background color of the button'
    }, {
        name: 'action',
        type: 'string',
         enum: [
            { "none": "none" },
            { "customAction": "customAction" }
        ],
        description: 'Action to perform when button is clicked'
    }]
});

// initialize code called once per entity
DynamicUi.prototype.initialize = function() {
    this.panels = [];
   
    for (let i = 0; i < this.panelCount; i++) {
        let panel = new pc.Entity('Panel' + i);
         console.log('Creating panel: ' + panel.name); 
        panel.addComponent('element', {
            type: 'group',
        
            width: 330,
            height:440,
            color: new pc.Color(0, 1, 0, 0.3)
        });

        
        this.setPanelPosition(panel, i);
        this.entity.addChild(panel);
        console.log(`added ${panel.name} to ${this.entity.name}`)
        this.panels.push(panel);
        let foundPanel = this.entity.findByName(panel.name);
if (foundPanel) {
    console.log(`Confirmed panel ${panel.name} is present as a child of ${this.entity.name}`);
} else {
    console.error(`Panel ${panel.name} was NOT found after adding.`);
}
    }

    console.log("Panels created, now creating buttons...");
    this.buttons.forEach((buttonData) => {
        if (buttonData.panelIndex < this.panels.length) {
            this.createButton(buttonData, this.panels[buttonData.panelIndex]);
            console.log(`Button created for panel index: ${buttonData.panelIndex}`);
        }
    });

    console.log("Finished creating buttons, adding resize listener...");
    this.app.graphicsDevice.on('resizecanvas', this.onResizeCanvas, this);

};

DynamicUi.prototype.setPanelPosition = function(panel, index) {
    let width = window.innerWidth;
    console.log('Index',index)
    if (width < 768) {
        panel.element.anchor = [0, index * 0.5, 1, (index + 1) * 0.5];
    } else {
        panel.element.anchor = [index * 0.5, 0, (index + 1) * 0.5, 1]
    }
};

DynamicUi.prototype.onResizeCanvas = function() {
    console.log('Canvas resized');
    // Reposition panels if needed
    for (let i = 0; i < this.panels.length; i++) {
        this.setPanelPosition(this.panels[i], i);
    }
};

DynamicUi.prototype.createButton = function(buttonData, panel) {
    let button = new pc.Entity('Button' + buttonData.label);

    button.addComponent('element', {
        type: 'button',
        anchor: [0.5, 0.5, 0.5, 0.5],
        pivot: [0.5, 0.5],
        width: 100,
        height: 40,
        color: buttonData.backgroundColor,
        text: buttonData.label,
        useInput: true
    });

        button.addComponent('button', {
        active: true
    });

    /*if (buttonData.image) {
        button.element,textureAsset = buttonData.image
    };*/

    button.button.on('click', function() {
        this.executeAction(buttonData.action)
    }, this);

    panel.addChild(button)

     console.log('Button created: ' + button.name + ' in panel: ' + panel.name);
};

DynamicUi.prototype.executeAction = function(action) {
    switch(action) {
        case 'customAction' :
        console.log('executing custom action');
        break;
        default:
        console.log('button clicked')
    }
}

// update code called every frame
DynamicUi.prototype.update = function(dt) {

};

Personally I would just have a bunch of premade panels then enable or disable them when needed.