cleaned up UIElement code
This commit is contained in:
parent
6149b983a5
commit
fff1ac4907
|
@ -15,13 +15,14 @@ export default abstract class CanvasNode extends GameNode implements Region {
|
|||
|
||||
constructor(){
|
||||
super();
|
||||
this.position.setOnChange(this.positionChanged);
|
||||
this._size = new Vec2(0, 0);
|
||||
this._size.setOnChange(this.sizeChanged);
|
||||
this._size.setOnChange(() => this.sizeChanged());
|
||||
this._scale = new Vec2(1, 1);
|
||||
this._scale.setOnChange(this.scaleChanged);
|
||||
this._scale.setOnChange(() => this.scaleChanged());
|
||||
this._boundary = new AABB();
|
||||
this.updateBoundary();
|
||||
|
||||
this.size.set(101, 101);
|
||||
}
|
||||
|
||||
get size(): Vec2 {
|
||||
|
@ -30,7 +31,8 @@ export default abstract class CanvasNode extends GameNode implements Region {
|
|||
|
||||
set size(size: Vec2){
|
||||
this._size = size;
|
||||
this._size.setOnChange(this.sizeChanged);
|
||||
// Enter as a lambda to bind "this"
|
||||
this._size.setOnChange(() => this.sizeChanged());
|
||||
this.sizeChanged();
|
||||
}
|
||||
|
||||
|
@ -40,23 +42,21 @@ export default abstract class CanvasNode extends GameNode implements Region {
|
|||
|
||||
set scale(scale: Vec2){
|
||||
this._scale = scale;
|
||||
this._scale.setOnChange(this.scaleChanged);
|
||||
// Enter as a lambda to bind "this"
|
||||
this._scale.setOnChange(() => this.scaleChanged());
|
||||
this.scaleChanged();
|
||||
}
|
||||
|
||||
|
||||
protected positionChanged = (): void => {
|
||||
if(this.hasPhysics){
|
||||
this.collisionShape.center = this.position;
|
||||
}
|
||||
protected positionChanged(): void {
|
||||
super.positionChanged();
|
||||
this.updateBoundary();
|
||||
}
|
||||
|
||||
protected sizeChanged = (): void => {
|
||||
protected sizeChanged(): void {
|
||||
this.updateBoundary();
|
||||
}
|
||||
|
||||
protected scaleChanged = (): void => {
|
||||
protected scaleChanged(): void {
|
||||
this.updateBoundary();
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
constructor(){
|
||||
this.input = InputReceiver.getInstance();
|
||||
this._position = new Vec2(0, 0);
|
||||
this._position.setOnChange(this.positionChanged);
|
||||
this._position.setOnChange(() => this.positionChanged());
|
||||
this.receiver = new Receiver();
|
||||
this.emitter = new Emitter();
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
|
||||
set position(pos: Vec2) {
|
||||
this._position = pos;
|
||||
this._position.setOnChange(this.positionChanged);
|
||||
this._position.setOnChange(() => this.positionChanged());
|
||||
this.positionChanged();
|
||||
}
|
||||
|
||||
|
@ -220,8 +220,7 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
/**
|
||||
* Called if the position vector is modified or replaced
|
||||
*/
|
||||
// TODO - For some reason this isn't recognized in the child class
|
||||
protected positionChanged = (): void => {
|
||||
protected positionChanged(): void {
|
||||
if(this.hasPhysics){
|
||||
this.collisionShape.center = this.position;
|
||||
}
|
||||
|
|
|
@ -5,18 +5,13 @@ import Vec2 from "../DataTypes/Vec2";
|
|||
/**
|
||||
* The representation of a UIElement - the parent class of things like buttons
|
||||
*/
|
||||
export default class UIElement extends CanvasNode {
|
||||
export default abstract class UIElement extends CanvasNode {
|
||||
// Style attributes
|
||||
protected textColor: Color;
|
||||
protected backgroundColor: Color;
|
||||
protected borderColor: Color;
|
||||
protected text: string;
|
||||
protected font: string;
|
||||
protected fontSize: number;
|
||||
protected hAlign: string;
|
||||
protected vAlign: string;
|
||||
protected borderRadius: number;
|
||||
protected borderWidth: number;
|
||||
protected padding: Vec2;
|
||||
|
||||
// EventAttributes
|
||||
onClick: Function;
|
||||
|
@ -35,16 +30,11 @@ export default class UIElement extends CanvasNode {
|
|||
super();
|
||||
this.position = position;
|
||||
|
||||
this.textColor = new Color(0, 0, 0, 1);
|
||||
this.backgroundColor = new Color(0, 0, 0, 0);
|
||||
this.borderColor = new Color(0, 0, 0, 0);
|
||||
this.text = "";
|
||||
this.font = "Arial";
|
||||
this.fontSize = 30;
|
||||
this.hAlign = "center";
|
||||
this.vAlign = "center";
|
||||
this.borderRadius = 5;
|
||||
this.borderWidth = 1;
|
||||
this.padding = Vec2.ZERO;
|
||||
|
||||
this.onClick = null;
|
||||
this.onClickEventId = null;
|
||||
|
@ -60,16 +50,12 @@ export default class UIElement extends CanvasNode {
|
|||
this.isEntered = false;
|
||||
}
|
||||
|
||||
setText(text: string): void {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
setBackgroundColor(color: Color): void {
|
||||
this.backgroundColor = color;
|
||||
}
|
||||
|
||||
setTextColor(color: Color): void {
|
||||
this.textColor = color;
|
||||
setPadding(padding: Vec2): void {
|
||||
this.padding.copy(padding);
|
||||
}
|
||||
|
||||
update(deltaT: number): void {
|
||||
|
@ -126,36 +112,6 @@ export default class UIElement extends CanvasNode {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the offset of the text - this is useful for rendering text with different alignments
|
||||
*
|
||||
*/
|
||||
protected calculateOffset(ctx: CanvasRenderingContext2D): Vec2 {
|
||||
let textWidth = ctx.measureText(this.text).width;
|
||||
|
||||
let offset = new Vec2(0, 0);
|
||||
|
||||
let hDiff = this.size.x - textWidth;
|
||||
if(this.hAlign === "center"){
|
||||
offset.x = hDiff/2;
|
||||
} else if (this.hAlign === "right"){
|
||||
offset.x = hDiff;
|
||||
}
|
||||
|
||||
if(this.vAlign === "top"){
|
||||
ctx.textBaseline = "top";
|
||||
offset.y = 0;
|
||||
} else if (this.vAlign === "bottom"){
|
||||
ctx.textBaseline = "bottom";
|
||||
offset.y = this.size.y;
|
||||
} else {
|
||||
ctx.textBaseline = "middle";
|
||||
offset.y = this.size.y/2;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridable method for calculating background color - useful for elements that want to be colored on different after certain events
|
||||
*/
|
||||
|
@ -169,42 +125,4 @@ export default class UIElement extends CanvasNode {
|
|||
protected calculateBorderColor(): string {
|
||||
return this.borderColor.toStringRGBA();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridable method for calculating text color - useful for elements that want to be colored on different after certain events
|
||||
*/
|
||||
protected calculateTextColor(): string {
|
||||
return this.textColor.toStringRGBA();
|
||||
}
|
||||
|
||||
render(ctx: CanvasRenderingContext2D): void {
|
||||
// Grab the global alpha so we can adjust it for this render
|
||||
let previousAlpha = ctx.globalAlpha;
|
||||
ctx.globalAlpha = this.getLayer().getAlpha();
|
||||
|
||||
let origin = this.scene.getViewTranslation(this);
|
||||
|
||||
ctx.font = this.fontSize + "px " + this.font;
|
||||
let offset = this.calculateOffset(ctx);
|
||||
|
||||
// Stroke and fill a rounded rect and give it text
|
||||
ctx.fillStyle = this.calculateBackgroundColor();
|
||||
ctx.fillRoundedRect(this.position.x - origin.x - this.size.x/2, this.position.y - origin.y - this.size.y/2,
|
||||
this.size.x, this.size.y, this.borderRadius);
|
||||
|
||||
ctx.strokeStyle = this.calculateBorderColor();
|
||||
ctx.lineWidth = this.borderWidth;
|
||||
ctx.strokeRoundedRect(this.position.x - origin.x - this.size.x/2, this.position.y - origin.y - this.size.y/2,
|
||||
this.size.x, this.size.y, this.borderRadius);
|
||||
|
||||
ctx.fillStyle = this.calculateTextColor();
|
||||
ctx.fillText(this.text, this.position.x + offset.x - origin.x - this.size.x/2, this.position.y + offset.y - origin.y - this.size.y/2);
|
||||
|
||||
ctx.globalAlpha = previousAlpha;
|
||||
|
||||
ctx.lineWidth = 4;
|
||||
ctx.strokeStyle = "#00FF00"
|
||||
let b = this.boundary;
|
||||
ctx.strokeRect(b.x - b.hw - origin.x, b.y - b.hh - origin.y, b.hw*2, b.hh*2);
|
||||
}
|
||||
}
|
|
@ -1,12 +1,11 @@
|
|||
import UIElement from "../UIElement";
|
||||
import Label from "./Label";
|
||||
import Color from "../../Utils/Color";
|
||||
import Vec2 from "../../DataTypes/Vec2";
|
||||
|
||||
export default class Button extends UIElement{
|
||||
export default class Button extends Label {
|
||||
|
||||
constructor(position: Vec2, text: string){
|
||||
super(position);
|
||||
this.text = text;
|
||||
super(position, text);
|
||||
|
||||
this.backgroundColor = new Color(150, 75, 203);
|
||||
this.borderColor = new Color(41, 46, 30);
|
||||
|
|
|
@ -1,9 +1,130 @@
|
|||
import Vec2 from "../../DataTypes/Vec2";
|
||||
import Color from "../../Utils/Color";
|
||||
import UIElement from "../UIElement";
|
||||
|
||||
export default class Label extends UIElement{
|
||||
protected textColor: Color;
|
||||
protected text: string;
|
||||
protected font: string;
|
||||
protected fontSize: number;
|
||||
protected hAlign: string;
|
||||
protected vAlign: string;
|
||||
|
||||
/** A flag for if the width of the text has been measured on the canvas for auto width assignment */
|
||||
protected sizeAssigned: boolean;
|
||||
|
||||
constructor(position: Vec2, text: string){
|
||||
super(position);
|
||||
this.text = text;
|
||||
this.textColor = new Color(0, 0, 0, 1);
|
||||
this.font = "Arial";
|
||||
this.fontSize = 30;
|
||||
this.hAlign = "center";
|
||||
this.vAlign = "center";
|
||||
|
||||
this.sizeAssigned = false;
|
||||
}
|
||||
|
||||
setText(text: string): void {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
setTextColor(color: Color): void {
|
||||
this.textColor = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridable method for calculating text color - useful for elements that want to be colored on different after certain events
|
||||
*/
|
||||
protected calculateTextColor(): string {
|
||||
return this.textColor.toStringRGBA();
|
||||
}
|
||||
|
||||
protected calculateTextWidth(ctx: CanvasRenderingContext2D): number {
|
||||
ctx.font = this.fontSize + "px " + this.font;
|
||||
return ctx.measureText(this.text).width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the offset of the text - this is useful for rendering text with different alignments
|
||||
*
|
||||
*/
|
||||
protected calculateTextOffset(ctx: CanvasRenderingContext2D): Vec2 {
|
||||
let textWidth = this.calculateTextWidth(ctx);
|
||||
|
||||
let offset = new Vec2(0, 0);
|
||||
|
||||
let hDiff = this.size.x - textWidth;
|
||||
if(this.hAlign === "center"){
|
||||
offset.x = hDiff/2;
|
||||
} else if (this.hAlign === "right"){
|
||||
offset.x = hDiff;
|
||||
}
|
||||
|
||||
if(this.vAlign === "top"){
|
||||
ctx.textBaseline = "top";
|
||||
offset.y = 0;
|
||||
} else if (this.vAlign === "bottom"){
|
||||
ctx.textBaseline = "bottom";
|
||||
offset.y = this.size.y;
|
||||
} else {
|
||||
ctx.textBaseline = "middle";
|
||||
offset.y = this.size.y/2;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
protected sizeChanged(): void {
|
||||
super.sizeChanged();
|
||||
this.sizeAssigned = true;
|
||||
}
|
||||
|
||||
protected autoSize(ctx: CanvasRenderingContext2D){
|
||||
let width = this.calculateTextWidth(ctx);
|
||||
let height = this.fontSize;
|
||||
this.size.set(width + this.padding.x*2, height + this.padding.y*2);
|
||||
this.sizeAssigned = true;
|
||||
}
|
||||
|
||||
/** On the next render, size this element to it's current text using its current font size */
|
||||
sizeToText(): void {
|
||||
this.sizeAssigned = false;
|
||||
}
|
||||
|
||||
render(ctx: CanvasRenderingContext2D): void {
|
||||
// If the size is unassigned (by the user or automatically) assign it
|
||||
if(!this.sizeAssigned){
|
||||
this.autoSize(ctx);
|
||||
}
|
||||
|
||||
// Grab the global alpha so we can adjust it for this render
|
||||
let previousAlpha = ctx.globalAlpha;
|
||||
ctx.globalAlpha = this.getLayer().getAlpha();
|
||||
|
||||
let origin = this.scene.getViewTranslation(this);
|
||||
|
||||
ctx.font = this.fontSize + "px " + this.font;
|
||||
let offset = this.calculateTextOffset(ctx);
|
||||
|
||||
// Stroke and fill a rounded rect and give it text
|
||||
ctx.fillStyle = this.calculateBackgroundColor();
|
||||
ctx.fillRoundedRect(this.position.x - origin.x - this.size.x/2, this.position.y - origin.y - this.size.y/2,
|
||||
this.size.x, this.size.y, this.borderRadius);
|
||||
|
||||
ctx.strokeStyle = this.calculateBorderColor();
|
||||
ctx.lineWidth = this.borderWidth;
|
||||
ctx.strokeRoundedRect(this.position.x - origin.x - this.size.x/2, this.position.y - origin.y - this.size.y/2,
|
||||
this.size.x, this.size.y, this.borderRadius);
|
||||
|
||||
ctx.fillStyle = this.calculateTextColor();
|
||||
ctx.fillText(this.text, this.position.x + offset.x - origin.x - this.size.x/2, this.position.y + offset.y - origin.y - this.size.y/2);
|
||||
|
||||
ctx.globalAlpha = previousAlpha;
|
||||
|
||||
ctx.lineWidth = 4;
|
||||
ctx.strokeStyle = "#00FF00"
|
||||
let b = this.boundary;
|
||||
ctx.strokeRect(b.x - b.hw - origin.x, b.y - b.hh - origin.y, b.hw*2, b.hh*2);
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ export default class Viewport {
|
|||
private view: AABB;
|
||||
private boundary: AABB;
|
||||
private following: GameNode;
|
||||
private focus: Vec2;
|
||||
|
||||
/**
|
||||
* A queue of previous positions of what this viewport is following. Used for smoothing viewport movement
|
||||
|
@ -35,6 +36,7 @@ export default class Viewport {
|
|||
this.smoothingFactor = 10;
|
||||
this.scrollZoomEnabled = false;
|
||||
this.canvasSize = Vec2.ZERO;
|
||||
this.focus = Vec2.ZERO;
|
||||
}
|
||||
|
||||
enableZoom(): void {
|
||||
|
@ -131,6 +133,14 @@ export default class Viewport {
|
|||
this.smoothingFactor = smoothingFactor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the viewport to focus on a point. Overidden by "following".
|
||||
* @param focus
|
||||
*/
|
||||
setFocus(focus: Vec2): void {
|
||||
this.focus.copy(focus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the CanvasNode is inside of the viewport
|
||||
* @param node
|
||||
|
@ -223,6 +233,7 @@ export default class Viewport {
|
|||
|
||||
this.view.center.copy(pos);
|
||||
} else {
|
||||
this.lastPositions.enqueue(this.focus);
|
||||
if(this.lastPositions.getSize() > this.smoothingFactor){
|
||||
this.lastPositions.dequeue();
|
||||
}
|
||||
|
|
37
src/_DemoClasses/Mario/MainMenu.ts
Normal file
37
src/_DemoClasses/Mario/MainMenu.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
import Vec2 from "../../DataTypes/Vec2";
|
||||
import Debug from "../../Debug/Debug";
|
||||
import InputHandler from "../../Input/InputHandler";
|
||||
import InputReceiver from "../../Input/InputReceiver";
|
||||
import { GraphicType } from "../../Nodes/Graphics/GraphicTypes";
|
||||
import Button from "../../Nodes/UIElements/Button";
|
||||
import { UIElementType } from "../../Nodes/UIElements/UIElementTypes";
|
||||
import Scene from "../../Scene/Scene";
|
||||
import Color from "../../Utils/Color";
|
||||
|
||||
export default class MainMenu extends Scene {
|
||||
|
||||
playBtn: Button;
|
||||
|
||||
loadScene(): void {
|
||||
|
||||
}
|
||||
|
||||
startScene(): void {
|
||||
this.addUILayer("Main");
|
||||
|
||||
let size = this.viewport.getHalfSize();
|
||||
this.viewport.setFocus(size);
|
||||
|
||||
this.playBtn = <Button>this.add.uiElement(UIElementType.BUTTON, "Main", {position: new Vec2(size.x, size.y), text: "Play Game"});
|
||||
this.playBtn.setBackgroundColor(Color.GREEN);
|
||||
this.playBtn.setPadding(new Vec2(50, 10));
|
||||
this.playBtn.onClick = () => {
|
||||
console.log("Play");
|
||||
}
|
||||
}
|
||||
|
||||
updateScene(): void {
|
||||
Debug.log("mp", InputReceiver.getInstance().getMousePosition().toString());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import GameLoop from "./Loop/GameLoop";
|
||||
import {} from "./index";
|
||||
import MainMenu from "./_DemoClasses/Mario/MainMenu";
|
||||
import Level1 from "./_DemoClasses/Mario/Level1";
|
||||
|
||||
function main(){
|
||||
|
@ -26,7 +27,7 @@ function main(){
|
|||
}
|
||||
|
||||
let sm = game.getSceneManager();
|
||||
sm.addScene(Level1, sceneOptions);
|
||||
sm.addScene(MainMenu, {});
|
||||
}
|
||||
|
||||
CanvasRenderingContext2D.prototype.roundedRect = function(x: number, y: number, w: number, h: number, r: number): void {
|
||||
|
|
Loading…
Reference in New Issue
Block a user