improved ui elements

This commit is contained in:
Joe Weaver 2020-08-10 16:44:24 -04:00
parent 91fcfd0a0d
commit b33b7b0a21
6 changed files with 162 additions and 43 deletions

View File

@ -21,7 +21,8 @@ export default class InputReceiver{
this.receiver = new Receiver(); this.receiver = new Receiver();
this.keyJustPressed = new Map<boolean>(); this.keyJustPressed = new Map<boolean>();
this.keyPressed = new Map<boolean>(); this.keyPressed = new Map<boolean>();
this.mousePressPosition = null; this.mousePosition = new Vec2(0, 0);
this.mousePressPosition = new Vec2(0, 0);
this.eventQueue = EventQueue.getInstance(); this.eventQueue = EventQueue.getInstance();
this.eventQueue.subscribe(this.receiver, ["mouse_down", "mouse_up", "mouse_move", "key_down", "key_up", "canvas_blur"]); this.eventQueue.subscribe(this.receiver, ["mouse_down", "mouse_up", "mouse_move", "key_down", "key_up", "canvas_blur"]);

View File

@ -9,12 +9,22 @@ export default class UIElement extends CanvasNode{
borderColor: Color; borderColor: Color;
text: string; text: string;
font: string; font: string;
fontSize: number;
hAlign: string;
vAlign: string;
// EventAttributes // EventAttributes
onClick: Function; onClick: Function;
onClickEventId: string; onClickEventId: string;
onHover: Function; onRelease: Function;
onHoverEventId: string; onReleaseEventId: string;
onEnter: Function;
onEnterEventId: string;
onLeave: Function;
onLeaveEventId: string;
protected isClicked: boolean;
protected isEntered: boolean;
constructor(){ constructor(){
super(); super();
@ -22,13 +32,23 @@ export default class UIElement extends CanvasNode{
this.backgroundColor = new Color(0, 0, 0, 0); this.backgroundColor = new Color(0, 0, 0, 0);
this.borderColor = new Color(0, 0, 0, 0); this.borderColor = new Color(0, 0, 0, 0);
this.text = ""; this.text = "";
this.font = "30px Arial"; this.font = "Arial";
this.fontSize = 30;
this.hAlign = "center";
this.vAlign = "center";
this.onClick = null; this.onClick = null;
this.onClickEventId = null; this.onClickEventId = null;
this.onRelease = null;
this.onReleaseEventId = null;
this.onHover = null; this.onEnter = null;
this.onHoverEventId = null; this.onEnterEventId = null;
this.onLeave = null;
this.onLeaveEventId = null;
this.isClicked = false;
this.isEntered = false;
} }
setPosition(vecOrX: Vec2 | number, y: number = null): void { setPosition(vecOrX: Vec2 | number, y: number = null): void {
@ -61,32 +81,96 @@ export default class UIElement extends CanvasNode{
update(deltaT: number): void { update(deltaT: number): void {
if(this.input.isMouseJustPressed()){ if(this.input.isMouseJustPressed()){
let mousePos = this.input.getMousePressPosition(); let clickPos = this.input.getMousePressPosition();
if(mousePos.x >= this.position.x && mousePos.x <= this.position.x + this.size.x){ if(this.contains(clickPos.x, clickPos.y)){
// Inside x bounds this.isClicked = true;
if(mousePos.y >= this.position.y && mousePos.y <= this.position.y + this.size.y){
// Inside element
if(this.onHover !== null){
this.onHover();
}
if(this.onClick !== null){ if(this.onClick !== null){
this.onClick(); this.onClick();
} }
if(this.onClickEventId !== null){ if(this.onClickEventId !== null){
let data = {}; let data = {};
this.emit(this.onClickEventId, data); this.emit(this.onClickEventId, data);
}
} }
} }
} }
if(!this.input.isMousePressed()){
if(this.isClicked){
this.isClicked = false;
}
}
let mousePos = this.input.getMousePosition();
if(mousePos && this.contains(mousePos.x, mousePos.y)){
this.isEntered = true;
if(this.onEnter !== null){
this.onEnter();
}
if(this.onEnterEventId !== null){
let data = {};
this.emit(this.onEnterEventId, data);
}
} else if(this.isEntered) {
this.isEntered = false;
if(this.onLeave !== null){
this.onLeave();
}
if(this.onLeaveEventId !== null){
let data = {};
this.emit(this.onLeaveEventId, data);
}
} else if(this.isClicked) {
// If mouse is dragged off of element while down, it is not clicked anymore
this.isClicked = false;
}
} }
render(ctx: CanvasRenderingContext2D, viewportOrigin: Vec2, viewportSize: Vec2){ protected calculateOffset(ctx: CanvasRenderingContext2D): Vec2 {
ctx.fillStyle = this.backgroundColor.toStringRGBA(); 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;
}
protected calculateBackgroundColor(): string {
return this.backgroundColor.toStringRGBA();
}
protected calculateTextColor(): string {
return this.textColor.toStringRGBA();
}
render(ctx: CanvasRenderingContext2D, viewportOrigin: Vec2, viewportSize: Vec2): void {
ctx.font = this.fontSize + "px " + this.font;
let offset = this.calculateOffset(ctx);
ctx.fillStyle = this.calculateBackgroundColor();
ctx.fillRect(this.position.x - viewportOrigin.x, this.position.y - viewportOrigin.y, this.size.x, this.size.y); ctx.fillRect(this.position.x - viewportOrigin.x, this.position.y - viewportOrigin.y, this.size.x, this.size.y);
ctx.fillStyle = this.textColor.toStringRGBA();
ctx.font = this.font; ctx.fillStyle = this.calculateTextColor();
ctx.fillText(this.text, this.position.x - viewportOrigin.x, this.position.y - viewportOrigin.y + 30); ctx.fillText(this.text, this.position.x + offset.x - viewportOrigin.x, this.position.y + offset.y - viewportOrigin.y);
} }
} }

View File

@ -0,0 +1,23 @@
import UIElement from "../UIElement";
import Color from "../../Utils/Color";
import Vec2 from "../../DataTypes/Vec2";
export default class Button extends UIElement{
constructor(){
super();
this.backgroundColor = new Color(150, 75, 203);
this.borderColor = new Color(41, 46, 30);
this.textColor = new Color(255, 255, 255);
}
protected calculateBackgroundColor(): string {
if(this.isEntered && !this.isClicked){
return this.backgroundColor.lighten().toStringRGBA();
} else if(this.isClicked){
return this.backgroundColor.darken().toStringRGBA();
} else {
return this.backgroundColor.toStringRGBA();
}
}
}

View File

@ -0,0 +1,8 @@
import UIElement from "../UIElement";
export default class Label extends UIElement{
constructor(text: string){
super();
this.text = text;
}
}

View File

@ -12,19 +12,27 @@ export default class Color{
this.b = b; this.b = b;
this.a = a; this.a = a;
} }
lighten(): Color {
return new Color(MathUtils.clamp(this.r + 40, 0, 255), MathUtils.clamp(this.g + 40, 0, 255), MathUtils.clamp(this.b + 40, 0, 255), this.a);
}
darken(): Color {
return new Color(MathUtils.clamp(this.r - 40, 0, 255), MathUtils.clamp(this.g - 40, 0, 255), MathUtils.clamp(this.b - 40, 0, 255), this.a);
}
toString(): string{ toString(): string {
return "#" + MathUtils.toHex(this.r, 2) + MathUtils.toHex(this.g, 2) + MathUtils.toHex(this.b, 2); return "#" + MathUtils.toHex(this.r, 2) + MathUtils.toHex(this.g, 2) + MathUtils.toHex(this.b, 2);
} }
toStringRGB(){ toStringRGB(): string {
return "rgb(" + this.r.toString() + ", " + this.g.toString() + ", " + this.b.toString() + ")"; return "rgb(" + this.r.toString() + ", " + this.g.toString() + ", " + this.b.toString() + ")";
} }
toStringRGBA(){ toStringRGBA(): string {
if(this.a === null){ if(this.a === null){
throw "No alpha value assigned to color"; return this.toStringRGB();
} }
return "rgb(" + this.r.toString() + ", " + this.g.toString() + ", " + this.b.toString() + ", " + this.a.toString() +")" return "rgba(" + this.r.toString() + ", " + this.g.toString() + ", " + this.b.toString() + ", " + this.a.toString() +")"
} }
} }

View File

@ -4,6 +4,7 @@ import Player from "./Nodes/Player";
import UIElement from "./Nodes/UIElement"; import UIElement from "./Nodes/UIElement";
import ColoredCircle from "./Nodes/ColoredCircle"; import ColoredCircle from "./Nodes/ColoredCircle";
import Color from "./Utils/Color"; import Color from "./Utils/Color";
import Button from "./Nodes/UIElements/Button";
function main(){ function main(){
// Create the game object // Create the game object
@ -15,31 +16,27 @@ function main(){
// Initialize GameObjects // Initialize GameObjects
let player = new Player(); let player = new Player();
let recordButton = new UIElement(); let recordButton = new Button();
recordButton.setSize(100, 50); recordButton.setSize(100, 50);
recordButton.setText("Record"); recordButton.setText("Record");
recordButton.setBackgroundColor(new Color(200, 100, 0, 0.3));
recordButton.setPosition(400, 30); recordButton.setPosition(400, 30);
recordButton.onClickEventId = "record_button_press"; recordButton.onClickEventId = "record_button_press";
let stopButton = new UIElement(); let stopButton = new Button();
stopButton.setSize(100, 50); stopButton.setSize(100, 50);
stopButton.setText("Stop"); stopButton.setText("Stop");
stopButton.setBackgroundColor(new Color(200, 0, 0, 0.3));
stopButton.setPosition(550, 30); stopButton.setPosition(550, 30);
stopButton.onClickEventId = "stop_button_press"; stopButton.onClickEventId = "stop_button_press";
let playButton = new UIElement(); let playButton = new Button();
playButton.setSize(100, 50); playButton.setSize(100, 50);
playButton.setText("Play"); playButton.setText("Play");
playButton.setBackgroundColor(new Color(0, 200, 0, 0.3));
playButton.setPosition(700, 30); playButton.setPosition(700, 30);
playButton.onClickEventId = "play_button_press"; playButton.onClickEventId = "play_button_press";
let cycleFramerateButton = new UIElement(); let cycleFramerateButton = new Button();
cycleFramerateButton.setSize(150, 50); cycleFramerateButton.setSize(150, 50);
cycleFramerateButton.setText("Cycle FPS"); cycleFramerateButton.setText("Cycle FPS");
cycleFramerateButton.setBackgroundColor(new Color(200, 0, 200, 0.3));
cycleFramerateButton.setPosition(5, 400); cycleFramerateButton.setPosition(5, 400);
let i = 0; let i = 0;
let fps = [15, 30, 60]; let fps = [15, 30, 60];
@ -48,10 +45,9 @@ function main(){
i = (i + 1) % 3; i = (i + 1) % 3;
} }
let pauseButton = new UIElement(); let pauseButton = new Button();
pauseButton.setSize(100, 50); pauseButton.setSize(100, 50);
pauseButton.setText("Pause"); pauseButton.setText("Pause");
pauseButton.setBackgroundColor(new Color(200, 0, 200, 1));
pauseButton.setPosition(700, 400); pauseButton.setPosition(700, 400);
pauseButton.onClick = () => { pauseButton.onClick = () => {
game.getGameState().addScene(pauseMenu); game.getGameState().addScene(pauseMenu);
@ -62,10 +58,9 @@ function main(){
modalBackground.setBackgroundColor(new Color(0, 0, 0, 0.4)); modalBackground.setBackgroundColor(new Color(0, 0, 0, 0.4));
modalBackground.setPosition(200, 100); modalBackground.setPosition(200, 100);
let resumeButton = new UIElement(); let resumeButton = new Button();
resumeButton.setSize(100, 50); resumeButton.setSize(100, 50);
resumeButton.setText("Resume"); resumeButton.setText("Resume");
resumeButton.setBackgroundColor(new Color(200, 0, 200, 1));
resumeButton.setPosition(400, 200); resumeButton.setPosition(400, 200);
resumeButton.onClick = () => { resumeButton.onClick = () => {
game.getGameState().removeScene(); game.getGameState().removeScene();