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.keyJustPressed = 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.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;
text: string;
font: string;
fontSize: number;
hAlign: string;
vAlign: string;
// EventAttributes
onClick: Function;
onClickEventId: string;
onHover: Function;
onHoverEventId: string;
onRelease: Function;
onReleaseEventId: string;
onEnter: Function;
onEnterEventId: string;
onLeave: Function;
onLeaveEventId: string;
protected isClicked: boolean;
protected isEntered: boolean;
constructor(){
super();
@ -22,13 +32,23 @@ export default class UIElement extends CanvasNode{
this.backgroundColor = new Color(0, 0, 0, 0);
this.borderColor = new Color(0, 0, 0, 0);
this.text = "";
this.font = "30px Arial";
this.font = "Arial";
this.fontSize = 30;
this.hAlign = "center";
this.vAlign = "center";
this.onClick = null;
this.onClickEventId = null;
this.onRelease = null;
this.onReleaseEventId = null;
this.onHover = null;
this.onHoverEventId = null;
this.onEnter = null;
this.onEnterEventId = null;
this.onLeave = null;
this.onLeaveEventId = null;
this.isClicked = false;
this.isEntered = false;
}
setPosition(vecOrX: Vec2 | number, y: number = null): void {
@ -61,14 +81,9 @@ export default class UIElement extends CanvasNode{
update(deltaT: number): void {
if(this.input.isMouseJustPressed()){
let mousePos = this.input.getMousePressPosition();
if(mousePos.x >= this.position.x && mousePos.x <= this.position.x + this.size.x){
// Inside x bounds
if(mousePos.y >= this.position.y && mousePos.y <= this.position.y + this.size.y){
// Inside element
if(this.onHover !== null){
this.onHover();
}
let clickPos = this.input.getMousePressPosition();
if(this.contains(clickPos.x, clickPos.y)){
this.isClicked = true;
if(this.onClick !== null){
this.onClick();
@ -79,14 +94,83 @@ export default class UIElement extends CanvasNode{
}
}
}
if(!this.input.isMousePressed()){
if(this.isClicked){
this.isClicked = false;
}
}
render(ctx: CanvasRenderingContext2D, viewportOrigin: Vec2, viewportSize: Vec2){
ctx.fillStyle = this.backgroundColor.toStringRGBA();
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;
}
}
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;
}
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.fillStyle = this.textColor.toStringRGBA();
ctx.font = this.font;
ctx.fillText(this.text, this.position.x - viewportOrigin.x, this.position.y - viewportOrigin.y + 30);
ctx.fillStyle = this.calculateTextColor();
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

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