improved webGL shader, added label shader
This commit is contained in:
parent
4214ef7fd4
commit
924469a2cd
77
dist/builtin/shaders/label.fshader
vendored
Normal file
77
dist/builtin/shaders/label.fshader
vendored
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
uniform vec4 u_BackgroundColor;
|
||||||
|
uniform vec4 u_BorderColor;
|
||||||
|
uniform float u_BorderWidth;
|
||||||
|
uniform float u_BorderRadius;
|
||||||
|
uniform vec2 u_MaxSize;
|
||||||
|
|
||||||
|
varying vec4 v_Position;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec2 adj_MaxSize = u_MaxSize - u_BorderWidth;
|
||||||
|
vec2 rad_MaxSize = u_MaxSize - u_BorderRadius;
|
||||||
|
vec2 rad2_MaxSize = u_MaxSize - 2.0*u_BorderRadius;
|
||||||
|
|
||||||
|
bool inX = (v_Position.x < adj_MaxSize.x) && (v_Position.x > -adj_MaxSize.x);
|
||||||
|
bool inY = (v_Position.y < adj_MaxSize.y) && (v_Position.y > -adj_MaxSize.y);
|
||||||
|
|
||||||
|
bool inRadiusRangeX = (v_Position.x < rad_MaxSize.x) && (v_Position.x > -rad_MaxSize.x);
|
||||||
|
bool inRadiusRangeY = (v_Position.y < rad_MaxSize.y) && (v_Position.y > -rad_MaxSize.y);
|
||||||
|
|
||||||
|
bool inRadius2RangeX = (v_Position.x < rad2_MaxSize.x) && (v_Position.x > -rad2_MaxSize.x);
|
||||||
|
bool inRadius2RangeY = (v_Position.y < rad2_MaxSize.y) && (v_Position.y > -rad2_MaxSize.y);
|
||||||
|
|
||||||
|
if(inX && inY){
|
||||||
|
// Inside bounds, draw background color
|
||||||
|
gl_FragColor = u_BackgroundColor;
|
||||||
|
} else {
|
||||||
|
// In boundary, draw border color
|
||||||
|
gl_FragColor = u_BorderColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This isn't working well right now
|
||||||
|
/*
|
||||||
|
if(inRadius2RangeX || inRadius2RangeY){
|
||||||
|
// Draw normally
|
||||||
|
if(inX && inY){
|
||||||
|
// Inside bounds, draw background color
|
||||||
|
gl_FragColor = u_BackgroundColor;
|
||||||
|
} else {
|
||||||
|
// In boundary, draw border color
|
||||||
|
gl_FragColor = u_BorderColor;
|
||||||
|
}
|
||||||
|
} else if(inRadiusRangeX || inRadiusRangeY){
|
||||||
|
// Draw a rounded boundary for the inner part
|
||||||
|
float x = v_Position.x - sign(v_Position.x)*rad2_MaxSize.x;
|
||||||
|
float y = v_Position.y - sign(v_Position.y)*rad2_MaxSize.y;
|
||||||
|
|
||||||
|
float radSq = x*x + y*y;
|
||||||
|
float bRadSq = u_BorderRadius*u_BorderRadius;
|
||||||
|
|
||||||
|
if(radSq > bRadSq){
|
||||||
|
// Outside of radius - draw as transparent
|
||||||
|
gl_FragColor = u_BorderColor;
|
||||||
|
} else {
|
||||||
|
gl_FragColor = u_BackgroundColor;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Both coordinates are in the circular section
|
||||||
|
float x = v_Position.x - sign(v_Position.x)*rad_MaxSize.x;
|
||||||
|
float y = v_Position.y - sign(v_Position.y)*rad_MaxSize.y;
|
||||||
|
|
||||||
|
float radSq = x*x + y*y;
|
||||||
|
float bRadSq = u_BorderRadius*u_BorderRadius;
|
||||||
|
|
||||||
|
if(radSq > bRadSq){
|
||||||
|
// Outside of radius - draw as transparent
|
||||||
|
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
} else if(sqrt(bRadSq) - sqrt(radSq) < u_BorderWidth) {
|
||||||
|
// In border
|
||||||
|
gl_FragColor = u_BorderColor;
|
||||||
|
} else {
|
||||||
|
gl_FragColor = u_BackgroundColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
12
dist/builtin/shaders/label.vshader
vendored
Normal file
12
dist/builtin/shaders/label.vshader
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
attribute vec4 a_Position;
|
||||||
|
|
||||||
|
uniform mat4 u_Transform;
|
||||||
|
|
||||||
|
varying vec4 v_Position;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
gl_Position = u_Transform * a_Position;
|
||||||
|
|
||||||
|
// Pass position to the fragment shader
|
||||||
|
v_Position = a_Position;
|
||||||
|
}
|
24
dist/hw1_assets/shaders/gradient_circle.fshader
vendored
24
dist/hw1_assets/shaders/gradient_circle.fshader
vendored
|
@ -1,24 +0,0 @@
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
uniform vec4 u_Color;
|
|
||||||
|
|
||||||
varying vec4 v_Position;
|
|
||||||
|
|
||||||
void main(){
|
|
||||||
// Default alpha is 0
|
|
||||||
float alpha = 0.0;
|
|
||||||
|
|
||||||
// Radius is 0.5, since the diameter of our quad is 1
|
|
||||||
float radius = 0.5;
|
|
||||||
|
|
||||||
// Get the distance squared of from (0, 0)
|
|
||||||
float dist_sq = v_Position.x*v_Position.x + v_Position.y*v_Position.y;
|
|
||||||
|
|
||||||
if(dist_sq < radius*radius){
|
|
||||||
// Multiply by 4, since distance squared is at most 0.25
|
|
||||||
alpha = 4.0*dist_sq;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the alpha value in our color
|
|
||||||
gl_FragColor = vec4(u_Color.rgb, alpha);
|
|
||||||
}
|
|
11
dist/hw1_assets/shaders/gradient_circle.vshader
vendored
11
dist/hw1_assets/shaders/gradient_circle.vshader
vendored
|
@ -1,11 +0,0 @@
|
||||||
attribute vec4 a_Position;
|
|
||||||
|
|
||||||
uniform mat4 u_Transform;
|
|
||||||
|
|
||||||
varying vec4 v_Position;
|
|
||||||
|
|
||||||
void main(){
|
|
||||||
gl_Position = u_Transform * a_Position;
|
|
||||||
|
|
||||||
v_Position = a_Position;
|
|
||||||
}
|
|
145
dist/hw1_assets/spritesheets/player_spaceship.json
vendored
145
dist/hw1_assets/spritesheets/player_spaceship.json
vendored
|
@ -1,145 +0,0 @@
|
||||||
{
|
|
||||||
"name": "player_spaceship",
|
|
||||||
"spriteSheetImage": "player_spaceship.png",
|
|
||||||
"spriteWidth": 256,
|
|
||||||
"spriteHeight": 256,
|
|
||||||
"leftBuffer": 0,
|
|
||||||
"rightBuffer": 0,
|
|
||||||
"topBuffer": 0,
|
|
||||||
"bottomBuffer": 0,
|
|
||||||
"columns": 5,
|
|
||||||
"rows": 5,
|
|
||||||
"animations": [
|
|
||||||
{
|
|
||||||
"name": "idle",
|
|
||||||
"repeat": true,
|
|
||||||
"frames": [
|
|
||||||
{
|
|
||||||
"index": 0,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 1,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 2,
|
|
||||||
"duration": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "boost",
|
|
||||||
"repeat": true,
|
|
||||||
"frames": [
|
|
||||||
{
|
|
||||||
"index": 3,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 4,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 5,
|
|
||||||
"duration": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "shield",
|
|
||||||
"repeat": false,
|
|
||||||
"frames": [
|
|
||||||
{
|
|
||||||
"index": 6,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 7,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 8,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 9,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 10,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 11,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 12,
|
|
||||||
"duration": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "explode",
|
|
||||||
"repeat": false,
|
|
||||||
"frames": [
|
|
||||||
{
|
|
||||||
"index": 13,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 14,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 15,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 16,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 17,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 18,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 19,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 20,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 21,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 22,
|
|
||||||
"duration": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"index": 23,
|
|
||||||
"duration": 10
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "explode",
|
|
||||||
"repeat": false,
|
|
||||||
"onEnd": "dead",
|
|
||||||
"frames": [
|
|
||||||
{
|
|
||||||
"index": 24,
|
|
||||||
"duration": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
BIN
dist/hw1_assets/spritesheets/player_spaceship.png
vendored
BIN
dist/hw1_assets/spritesheets/player_spaceship.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 66 KiB |
|
@ -1,48 +0,0 @@
|
||||||
import Vec2 from "./Wolfie2D/DataTypes/Vec2";
|
|
||||||
import { GraphicType } from "./Wolfie2D/Nodes/Graphics/GraphicTypes";
|
|
||||||
import Point from "./Wolfie2D/Nodes/Graphics/Point";
|
|
||||||
import Rect from "./Wolfie2D/Nodes/Graphics/Rect";
|
|
||||||
import AnimatedSprite from "./Wolfie2D/Nodes/Sprites/AnimatedSprite";
|
|
||||||
import Sprite from "./Wolfie2D/Nodes/Sprites/Sprite";
|
|
||||||
import Scene from "./Wolfie2D/Scene/Scene";
|
|
||||||
import Color from "./Wolfie2D/Utils/Color";
|
|
||||||
|
|
||||||
export default class WebGLScene extends Scene {
|
|
||||||
|
|
||||||
private point: Point;
|
|
||||||
private rect: Rect;
|
|
||||||
private player: AnimatedSprite;
|
|
||||||
private t: number = 0;
|
|
||||||
|
|
||||||
loadScene() {
|
|
||||||
this.load.spritesheet("player", "hw1_assets/spritesheets/player_spaceship.json");
|
|
||||||
}
|
|
||||||
|
|
||||||
startScene() {
|
|
||||||
this.addLayer("primary");
|
|
||||||
|
|
||||||
this.point = this.add.graphic(GraphicType.POINT, "primary", {position: new Vec2(100, 100), size: new Vec2(10, 10)})
|
|
||||||
this.point.color = Color.CYAN;
|
|
||||||
console.log(this.point.color.toStringRGBA());
|
|
||||||
|
|
||||||
this.rect = <Rect>this.add.graphic(GraphicType.RECT, "primary", {position: new Vec2(300, 100), size: new Vec2(100, 50)});
|
|
||||||
this.rect.color = Color.ORANGE;
|
|
||||||
|
|
||||||
this.player = this.add.animatedSprite("player", "primary");
|
|
||||||
this.player.position.set(800, 500);
|
|
||||||
this.player.scale.set(0.5, 0.5);
|
|
||||||
this.player.animation.play("idle");
|
|
||||||
}
|
|
||||||
|
|
||||||
updateScene(deltaT: number) {
|
|
||||||
this.t += deltaT;
|
|
||||||
|
|
||||||
let s = Math.sin(this.t);
|
|
||||||
let c = Math.cos(this.t);
|
|
||||||
|
|
||||||
this.point.position.x = 100 + 100*c;
|
|
||||||
this.point.position.y = 100 + 100*s;
|
|
||||||
|
|
||||||
this.rect.rotation = this.t;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
import AI from "../DataTypes/Interfaces/AI";
|
|
||||||
import GameEvent from "../Events/GameEvent";
|
|
||||||
import GameNode from "../Nodes/GameNode";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A very basic AI class that just runs a function every update
|
|
||||||
*/
|
|
||||||
export default class ControllerAI implements AI {
|
|
||||||
protected owner: GameNode;
|
|
||||||
|
|
||||||
initializeAI(owner: GameNode, options: Record<string, any>): void {
|
|
||||||
this.owner = owner;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleEvent(event: GameEvent): void {}
|
|
||||||
|
|
||||||
update(deltaT: number): void {}
|
|
||||||
}
|
|
|
@ -12,4 +12,6 @@ export default class StateMachineAI extends StateMachine implements AI {
|
||||||
|
|
||||||
// @implemented
|
// @implemented
|
||||||
initializeAI(owner: GameNode, config: Record<string, any>): void {}
|
initializeAI(owner: GameNode, config: Record<string, any>): void {}
|
||||||
|
|
||||||
|
activate(options: Record<string, any>): void {}
|
||||||
}
|
}
|
|
@ -10,6 +10,9 @@ export default interface AI extends Updateable {
|
||||||
/** Initializes the AI with the actor and any additional config */
|
/** Initializes the AI with the actor and any additional config */
|
||||||
initializeAI(owner: GameNode, options: Record<string, any>): void;
|
initializeAI(owner: GameNode, options: Record<string, any>): void;
|
||||||
|
|
||||||
|
/** Activates this AI from a stopped state and allows variables to be passed in */
|
||||||
|
activate(options: Record<string, any>): void;
|
||||||
|
|
||||||
/** Handles events from the Actor */
|
/** Handles events from the Actor */
|
||||||
handleEvent(event: GameEvent): void;
|
handleEvent(event: GameEvent): void;
|
||||||
}
|
}
|
|
@ -30,6 +30,7 @@ export default interface Actor {
|
||||||
/**
|
/**
|
||||||
* Sets the AI to start/stop for this Actor.
|
* Sets the AI to start/stop for this Actor.
|
||||||
* @param active The new active status of the AI.
|
* @param active The new active status of the AI.
|
||||||
|
* @param options An object that allows options to be pased to the activated AI
|
||||||
*/
|
*/
|
||||||
setAIActive(active: boolean): void;
|
setAIActive(active: boolean, options: Record<string, any>): void;
|
||||||
}
|
}
|
|
@ -23,6 +23,26 @@ export default class AABB extends Shape {
|
||||||
this.halfSize = halfSize ? halfSize : new Vec2(0, 0);
|
this.halfSize = halfSize ? halfSize : new Vec2(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns a point representing the top left corner of the AABB */
|
||||||
|
get topLeft(): Vec2 {
|
||||||
|
return new Vec2(this.left, this.top)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a point representing the top right corner of the AABB */
|
||||||
|
get topRight(): Vec2 {
|
||||||
|
return new Vec2(this.right, this.top)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a point representing the bottom left corner of the AABB */
|
||||||
|
get bottomLeft(): Vec2 {
|
||||||
|
return new Vec2(this.left, this.bottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a point representing the bottom right corner of the AABB */
|
||||||
|
get bottomRight(): Vec2 {
|
||||||
|
return new Vec2(this.right, this.bottom)
|
||||||
|
}
|
||||||
|
|
||||||
// @override
|
// @override
|
||||||
getBoundingRect(): AABB {
|
getBoundingRect(): AABB {
|
||||||
return this.clone();
|
return this.clone();
|
||||||
|
|
|
@ -7,7 +7,7 @@ import Shape from "./Shape";
|
||||||
*/
|
*/
|
||||||
export default class Circle extends Shape {
|
export default class Circle extends Shape {
|
||||||
private _center: Vec2;
|
private _center: Vec2;
|
||||||
private radius: number;
|
radius: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Circle
|
* Creates a new Circle
|
||||||
|
@ -32,6 +32,24 @@ export default class Circle extends Shape {
|
||||||
return new Vec2(this.radius, this.radius);
|
return new Vec2(this.radius, this.radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get r(): number {
|
||||||
|
return this.radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
set r(radius: number) {
|
||||||
|
this.radius = radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @override
|
||||||
|
/**
|
||||||
|
* A simple boolean check of whether this AABB contains a point
|
||||||
|
* @param point The point to check
|
||||||
|
* @returns A boolean representing whether this AABB contains the specified point
|
||||||
|
*/
|
||||||
|
containsPoint(point: Vec2): boolean {
|
||||||
|
return this.center.distanceSqTo(point) <= this.radius*this.radius;
|
||||||
|
}
|
||||||
|
|
||||||
// @override
|
// @override
|
||||||
getBoundingRect(): AABB {
|
getBoundingRect(): AABB {
|
||||||
return new AABB(this._center.clone(), new Vec2(this.radius, this.radius));
|
return new AABB(this._center.clone(), new Vec2(this.radius, this.radius));
|
||||||
|
@ -51,4 +69,8 @@ export default class Circle extends Shape {
|
||||||
clone(): Circle {
|
clone(): Circle {
|
||||||
return new Circle(this._center.clone(), this.radius);
|
return new Circle(this._center.clone(), this.radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
return "(center: " + this.center.toString() + ", radius: " + this.radius + ")";
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -71,6 +71,13 @@ export default abstract class Shape {
|
||||||
*/
|
*/
|
||||||
abstract overlaps(other: Shape): boolean;
|
abstract overlaps(other: Shape): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple boolean check of whether this Shape contains a point
|
||||||
|
* @param point The point to check
|
||||||
|
* @returns A boolean representing whether this Shape contains the specified point
|
||||||
|
*/
|
||||||
|
abstract containsPoint(point: Vec2): boolean;
|
||||||
|
|
||||||
static getTimeOfCollision(A: Shape, velA: Vec2, B: Shape, velB: Vec2): [Vec2, Vec2, boolean, boolean] {
|
static getTimeOfCollision(A: Shape, velA: Vec2, B: Shape, velB: Vec2): [Vec2, Vec2, boolean, boolean] {
|
||||||
if(A instanceof AABB && B instanceof AABB){
|
if(A instanceof AABB && B instanceof AABB){
|
||||||
return Shape.getTimeOfCollision_AABB_AABB(A, velA, B, velB);
|
return Shape.getTimeOfCollision_AABB_AABB(A, velA, B, velB);
|
||||||
|
|
|
@ -269,6 +269,17 @@ export default class Vec2 {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does an element wise remainder operation on this vector. this.x %= other.x and this.y %= other.y
|
||||||
|
* @param other The other vector
|
||||||
|
* @returns this vector
|
||||||
|
*/
|
||||||
|
remainder(other: Vec2): Vec2 {
|
||||||
|
this.x = this.x % other.x;
|
||||||
|
this.y = this.y % other.y;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the squared distance between this vector and another vector
|
* Returns the squared distance between this vector and another vector
|
||||||
* @param other The vector to compute distance squared to
|
* @param other The vector to compute distance squared to
|
||||||
|
|
|
@ -78,6 +78,36 @@ export default class Debug {
|
||||||
this.debugRenderingContext.globalAlpha = alpha;
|
this.debugRenderingContext.globalAlpha = alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a circle at the specified position
|
||||||
|
* @param center The center of the circle
|
||||||
|
* @param radius The dimensions of the box
|
||||||
|
* @param filled A boolean for whether or not the circle is filled
|
||||||
|
* @param color The color of the circle
|
||||||
|
*/
|
||||||
|
static drawCircle(center: Vec2, radius: number, filled: boolean, color: Color): void {
|
||||||
|
let alpha = this.debugRenderingContext.globalAlpha;
|
||||||
|
this.debugRenderingContext.globalAlpha = color.a;
|
||||||
|
|
||||||
|
if(filled){
|
||||||
|
this.debugRenderingContext.fillStyle = color.toString();
|
||||||
|
this.debugRenderingContext.beginPath();
|
||||||
|
this.debugRenderingContext.arc(center.x, center.y, radius, 0, 2 * Math.PI);
|
||||||
|
this.debugRenderingContext.closePath();
|
||||||
|
this.debugRenderingContext.fill();
|
||||||
|
} else {
|
||||||
|
let lineWidth = 2;
|
||||||
|
this.debugRenderingContext.lineWidth = lineWidth;
|
||||||
|
this.debugRenderingContext.strokeStyle = color.toString();
|
||||||
|
this.debugRenderingContext.beginPath();
|
||||||
|
this.debugRenderingContext.arc(center.x, center.y, radius, 0, 2 * Math.PI);
|
||||||
|
this.debugRenderingContext.closePath();
|
||||||
|
this.debugRenderingContext.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.debugRenderingContext.globalAlpha = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws a ray at the specified position
|
* Draws a ray at the specified position
|
||||||
* @param from The starting position of the ray
|
* @param from The starting position of the ray
|
||||||
|
|
|
@ -18,6 +18,7 @@ import EnvironmentInitializer from "./EnvironmentInitializer";
|
||||||
import Vec2 from "../DataTypes/Vec2";
|
import Vec2 from "../DataTypes/Vec2";
|
||||||
import Registry from "../Registry/Registry";
|
import Registry from "../Registry/Registry";
|
||||||
import WebGLRenderer from "../Rendering/WebGLRenderer";
|
import WebGLRenderer from "../Rendering/WebGLRenderer";
|
||||||
|
import Scene from "../Scene/Scene";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main loop of the game engine.
|
* The main loop of the game engine.
|
||||||
|
@ -130,7 +131,7 @@ export default class Game {
|
||||||
/**
|
/**
|
||||||
* Starts the game
|
* Starts the game
|
||||||
*/
|
*/
|
||||||
start(): void {
|
start(InitialScene: new (...args: any) => Scene, options: Record<string, any>): void {
|
||||||
// Set the update function of the loop
|
// Set the update function of the loop
|
||||||
this.loop.doUpdate = (deltaT: number) => this.update(deltaT);
|
this.loop.doUpdate = (deltaT: number) => this.update(deltaT);
|
||||||
|
|
||||||
|
@ -142,7 +143,9 @@ export default class Game {
|
||||||
|
|
||||||
// Load the items with the resource manager
|
// Load the items with the resource manager
|
||||||
this.resourceManager.loadResourcesFromQueue(() => {
|
this.resourceManager.loadResourcesFromQueue(() => {
|
||||||
// When we're dont loading, start the loop
|
// When we're done loading, start the loop
|
||||||
|
console.log("Finished Preload - loading first scene");
|
||||||
|
this.sceneManager.addScene(InitialScene, options);
|
||||||
this.loop.start();
|
this.loop.start();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -178,14 +181,7 @@ export default class Game {
|
||||||
// Clear the canvases
|
// Clear the canvases
|
||||||
Debug.clearCanvas();
|
Debug.clearCanvas();
|
||||||
|
|
||||||
if(this.gameOptions.useWebGL){
|
this.renderingManager.clear(this.clearColor);
|
||||||
(<WebGLRenderingContext>this.ctx).clearColor(this.clearColor.r, this.clearColor.g, this.clearColor.b, this.clearColor.a);
|
|
||||||
(<WebGLRenderingContext>this.ctx).clear((<WebGLRenderingContext>this.ctx).COLOR_BUFFER_BIT | (<WebGLRenderingContext>this.ctx).DEPTH_BUFFER_BIT);
|
|
||||||
} else {
|
|
||||||
(<CanvasRenderingContext2D>this.ctx).clearRect(0, 0, this.WIDTH, this.HEIGHT);
|
|
||||||
(<CanvasRenderingContext2D>this.ctx).fillStyle = this.clearColor.toString();
|
|
||||||
(<CanvasRenderingContext2D>this.ctx).fillRect(0, 0, this.WIDTH, this.HEIGHT);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.sceneManager.render();
|
this.sceneManager.render();
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import NavigationPath from "../Pathfinding/NavigationPath";
|
||||||
import TweenManager from "../Rendering/Animations/TweenManager";
|
import TweenManager from "../Rendering/Animations/TweenManager";
|
||||||
import Debug from "../Debug/Debug";
|
import Debug from "../Debug/Debug";
|
||||||
import Color from "../Utils/Color";
|
import Color from "../Utils/Color";
|
||||||
|
import Circle from "../DataTypes/Shapes/Circle";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The representation of an object in the game world.
|
* The representation of an object in the game world.
|
||||||
|
@ -198,6 +199,15 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
||||||
this.scene.getPhysicsManager().registerObject(this);
|
this.scene.getPhysicsManager().registerObject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the collider for this GameNode
|
||||||
|
* @param collider The new collider to use
|
||||||
|
*/
|
||||||
|
setCollisionShape(collider: Shape): void {
|
||||||
|
this.collisionShape = collider;
|
||||||
|
this.collisionShape.center.copy(this.position);
|
||||||
|
}
|
||||||
|
|
||||||
// @implemented
|
// @implemented
|
||||||
/**
|
/**
|
||||||
* @param group The name of the group that will activate the trigger
|
* @param group The name of the group that will activate the trigger
|
||||||
|
@ -254,8 +264,9 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
||||||
}
|
}
|
||||||
|
|
||||||
// @implemented
|
// @implemented
|
||||||
setAIActive(active: boolean): void {
|
setAIActive(active: boolean, options: Record<string, any>): void {
|
||||||
this.aiActive = active;
|
this.aiActive = active;
|
||||||
|
this.ai.activate(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------- TWEENABLE PROPERTIES ----------*/
|
/*---------- TWEENABLE PROPERTIES ----------*/
|
||||||
|
@ -306,8 +317,13 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
||||||
|
|
||||||
/** Called if the position vector is modified or replaced */
|
/** Called if the position vector is modified or replaced */
|
||||||
protected positionChanged(): void {
|
protected positionChanged(): void {
|
||||||
if(this.hasPhysics){
|
if(this.collisionShape){
|
||||||
|
if(this.colliderOffset){
|
||||||
this.collisionShape.center = this.position.clone().add(this.colliderOffset);
|
this.collisionShape.center = this.position.clone().add(this.colliderOffset);
|
||||||
|
} else {
|
||||||
|
this.collisionShape.center = this.position.clone();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -336,15 +352,20 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this has a collider, draw it
|
// If this has a collider, draw it
|
||||||
if(this.hasPhysics && this.collisionShape){
|
if(this.collisionShape){
|
||||||
let color = this.isColliding ? Color.RED : Color.GREEN;
|
let color = this.isColliding ? Color.RED : Color.GREEN;
|
||||||
|
|
||||||
if(this.isTrigger){
|
if(this.isTrigger){
|
||||||
color = Color.PURPLE;
|
color = Color.MAGENTA;
|
||||||
}
|
}
|
||||||
|
|
||||||
color.a = 0.2;
|
color.a = 0.2;
|
||||||
|
|
||||||
|
if(this.collisionShape instanceof AABB){
|
||||||
Debug.drawBox(this.inRelativeCoordinates(this.collisionShape.center), this.collisionShape.halfSize.scaled(this.scene.getViewScale()), true, color);
|
Debug.drawBox(this.inRelativeCoordinates(this.collisionShape.center), this.collisionShape.halfSize.scaled(this.scene.getViewScale()), true, color);
|
||||||
|
} else if(this.collisionShape instanceof Circle){
|
||||||
|
Debug.drawCircle(this.inRelativeCoordinates(this.collisionShape.center), this.collisionShape.hw*this.scene.getViewScale(), true, color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ export default abstract class UIElement extends CanvasNode {
|
||||||
// See of this object was just clicked
|
// See of this object was just clicked
|
||||||
if(Input.isMouseJustPressed()){
|
if(Input.isMouseJustPressed()){
|
||||||
let clickPos = Input.getMousePressPosition();
|
let clickPos = Input.getMousePressPosition();
|
||||||
if(this.contains(clickPos.x, clickPos.y)){
|
if(this.contains(clickPos.x, clickPos.y) && this.visible && !this.layer.isHidden()){
|
||||||
this.isClicked = true;
|
this.isClicked = true;
|
||||||
|
|
||||||
if(this.onClick !== null){
|
if(this.onClick !== null){
|
||||||
|
@ -136,15 +136,15 @@ export default abstract class UIElement extends CanvasNode {
|
||||||
* Overridable method for calculating background color - useful for elements that want to be colored on different after certain events
|
* Overridable method for calculating background color - useful for elements that want to be colored on different after certain events
|
||||||
* @returns The background color of the UIElement
|
* @returns The background color of the UIElement
|
||||||
*/
|
*/
|
||||||
calculateBackgroundColor(): string {
|
calculateBackgroundColor(): Color {
|
||||||
return this.backgroundColor.toStringRGBA();
|
return this.backgroundColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overridable method for calculating border color - useful for elements that want to be colored on different after certain events
|
* Overridable method for calculating border color - useful for elements that want to be colored on different after certain events
|
||||||
* @returns The border color of the UIElement
|
* @returns The border color of the UIElement
|
||||||
*/
|
*/
|
||||||
calculateBorderColor(): string {
|
calculateBorderColor(): Color {
|
||||||
return this.borderColor.toStringRGBA();
|
return this.borderColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,14 +14,14 @@ export default class Button extends Label {
|
||||||
}
|
}
|
||||||
|
|
||||||
// @override
|
// @override
|
||||||
calculateBackgroundColor(): string {
|
calculateBackgroundColor(): Color {
|
||||||
// Change the background color if clicked or hovered
|
// Change the background color if clicked or hovered
|
||||||
if(this.isEntered && !this.isClicked){
|
if(this.isEntered && !this.isClicked){
|
||||||
return this.backgroundColor.lighten().toStringRGBA();
|
return this.backgroundColor.lighten();
|
||||||
} else if(this.isClicked){
|
} else if(this.isClicked){
|
||||||
return this.backgroundColor.darken().toStringRGBA();
|
return this.backgroundColor.darken();
|
||||||
} else {
|
} else {
|
||||||
return this.backgroundColor.toStringRGBA();
|
return this.backgroundColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -68,6 +68,10 @@ export default class Label extends UIElement{
|
||||||
return ctx.measureText(this.text).width;
|
return ctx.measureText(this.text).width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setHAlign(align: string): void {
|
||||||
|
this.hAlign = align;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the offset of the text - this is used for rendering text with different alignments
|
* Calculate the offset of the text - this is used for rendering text with different alignments
|
||||||
* @param ctx The rendering context
|
* @param ctx The rendering context
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import Map from "../../DataTypes/Map";
|
import Map from "../../DataTypes/Map";
|
||||||
import ShaderType from "../../Rendering/WebGLRendering/ShaderType";
|
import ShaderType from "../../Rendering/WebGLRendering/ShaderType";
|
||||||
|
import LabelShaderType from "../../Rendering/WebGLRendering/ShaderTypes/LabelShaderType";
|
||||||
import PointShaderType from "../../Rendering/WebGLRendering/ShaderTypes/PointShaderType";
|
import PointShaderType from "../../Rendering/WebGLRendering/ShaderTypes/PointShaderType";
|
||||||
import RectShaderType from "../../Rendering/WebGLRendering/ShaderTypes/RectShaderType";
|
import RectShaderType from "../../Rendering/WebGLRendering/ShaderTypes/RectShaderType";
|
||||||
import SpriteShaderType from "../../Rendering/WebGLRendering/ShaderTypes/SpriteShaderType";
|
import SpriteShaderType from "../../Rendering/WebGLRendering/ShaderTypes/SpriteShaderType";
|
||||||
|
@ -14,6 +15,7 @@ export default class ShaderRegistry extends Map<ShaderType> {
|
||||||
public static POINT_SHADER = "point";
|
public static POINT_SHADER = "point";
|
||||||
public static RECT_SHADER = "rect";
|
public static RECT_SHADER = "rect";
|
||||||
public static SPRITE_SHADER = "sprite";
|
public static SPRITE_SHADER = "sprite";
|
||||||
|
public static LABEL_SHADER = "label";
|
||||||
|
|
||||||
private registryItems: Array<ShaderRegistryItem> = new Array();
|
private registryItems: Array<ShaderRegistryItem> = new Array();
|
||||||
|
|
||||||
|
@ -21,8 +23,6 @@ export default class ShaderRegistry extends Map<ShaderType> {
|
||||||
* Preloads all built-in shaders
|
* Preloads all built-in shaders
|
||||||
*/
|
*/
|
||||||
public preload(){
|
public preload(){
|
||||||
console.log("Preloading");
|
|
||||||
|
|
||||||
// Get the resourceManager and queue all built-in shaders for preloading
|
// Get the resourceManager and queue all built-in shaders for preloading
|
||||||
const rm = ResourceManager.getInstance();
|
const rm = ResourceManager.getInstance();
|
||||||
|
|
||||||
|
@ -35,17 +35,17 @@ export default class ShaderRegistry extends Map<ShaderType> {
|
||||||
// Queue a load for the sprite shader
|
// Queue a load for the sprite shader
|
||||||
this.registerAndPreloadItem(ShaderRegistry.SPRITE_SHADER, SpriteShaderType, "builtin/shaders/sprite.vshader", "builtin/shaders/sprite.fshader");
|
this.registerAndPreloadItem(ShaderRegistry.SPRITE_SHADER, SpriteShaderType, "builtin/shaders/sprite.vshader", "builtin/shaders/sprite.fshader");
|
||||||
|
|
||||||
|
// Queue a load for the label shader
|
||||||
|
this.registerAndPreloadItem(ShaderRegistry.LABEL_SHADER, LabelShaderType, "builtin/shaders/label.vshader", "builtin/shaders/label.fshader");
|
||||||
|
|
||||||
// Queue a load for any preloaded items
|
// Queue a load for any preloaded items
|
||||||
for(let item of this.registryItems){
|
for(let item of this.registryItems){
|
||||||
const shader = new item.constr(item.key);
|
const shader = new item.constr(item.key);
|
||||||
shader.initBufferObject();
|
shader.initBufferObject();
|
||||||
this.add(item.key, shader);
|
this.add(item.key, shader);
|
||||||
|
|
||||||
console.log("Added", item.key);
|
|
||||||
|
|
||||||
// Load if desired
|
// Load if desired
|
||||||
if(item.preload !== undefined){
|
if(item.preload !== undefined){
|
||||||
console.log("Preloading", item.key);
|
|
||||||
rm.shader(item.key, item.preload.vshaderLocation, item.preload.fshaderLocation);
|
rm.shader(item.key, item.preload.vshaderLocation, item.preload.fshaderLocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import Slider from "../Nodes/UIElements/Slider";
|
||||||
import TextInput from "../Nodes/UIElements/TextInput";
|
import TextInput from "../Nodes/UIElements/TextInput";
|
||||||
import AnimatedSprite from "../Nodes/Sprites/AnimatedSprite";
|
import AnimatedSprite from "../Nodes/Sprites/AnimatedSprite";
|
||||||
import Vec2 from "../DataTypes/Vec2";
|
import Vec2 from "../DataTypes/Vec2";
|
||||||
|
import Color from "../Utils/Color";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of the RenderingManager class using CanvasRenderingContext2D.
|
* An implementation of the RenderingManager class using CanvasRenderingContext2D.
|
||||||
|
@ -32,6 +33,8 @@ export default class CanvasRenderer extends RenderingManager {
|
||||||
protected origin: Vec2;
|
protected origin: Vec2;
|
||||||
protected zoom: number;
|
protected zoom: number;
|
||||||
|
|
||||||
|
protected worldSize: Vec2;
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
@ -49,6 +52,8 @@ export default class CanvasRenderer extends RenderingManager {
|
||||||
canvas.width = width;
|
canvas.width = width;
|
||||||
canvas.height = height;
|
canvas.height = height;
|
||||||
|
|
||||||
|
this.worldSize = new Vec2(width, height);
|
||||||
|
|
||||||
this.ctx = canvas.getContext("2d");
|
this.ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
this.graphicRenderer = new GraphicRenderer(this.ctx);
|
this.graphicRenderer = new GraphicRenderer(this.ctx);
|
||||||
|
@ -107,7 +112,10 @@ export default class CanvasRenderer extends RenderingManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render the uiLayers on top of everything else
|
// Render the uiLayers on top of everything else
|
||||||
uiLayers.forEach(key => uiLayers.get(key).getItems().forEach(node => this.renderNode(<CanvasNode>node)));
|
uiLayers.forEach(key => {
|
||||||
|
if(!uiLayers.get(key).isHidden())
|
||||||
|
uiLayers.get(key).getItems().forEach(node => this.renderNode(<CanvasNode>node))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -221,4 +229,10 @@ export default class CanvasRenderer extends RenderingManager {
|
||||||
this.uiElementRenderer.renderTextInput(uiElement);
|
this.uiElementRenderer.renderTextInput(uiElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear(clearColor: Color): void {
|
||||||
|
this.ctx.clearRect(0, 0, this.worldSize.x, this.worldSize.y);
|
||||||
|
this.ctx.fillStyle = clearColor.toString();
|
||||||
|
this.ctx.fillRect(0, 0, this.worldSize.x, this.worldSize.y);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -45,11 +45,11 @@ export default class UIElementRenderer {
|
||||||
|
|
||||||
// Stroke and fill a rounded rect and give it text
|
// Stroke and fill a rounded rect and give it text
|
||||||
this.ctx.globalAlpha = label.backgroundColor.a;
|
this.ctx.globalAlpha = label.backgroundColor.a;
|
||||||
this.ctx.fillStyle = label.calculateBackgroundColor();
|
this.ctx.fillStyle = label.calculateBackgroundColor().toStringRGBA();
|
||||||
this.ctx.fillRoundedRect(-label.size.x/2, -label.size.y/2,
|
this.ctx.fillRoundedRect(-label.size.x/2, -label.size.y/2,
|
||||||
label.size.x, label.size.y, label.borderRadius);
|
label.size.x, label.size.y, label.borderRadius);
|
||||||
|
|
||||||
this.ctx.strokeStyle = label.calculateBorderColor();
|
this.ctx.strokeStyle = label.calculateBorderColor().toStringRGBA();
|
||||||
this.ctx.globalAlpha = label.borderColor.a;
|
this.ctx.globalAlpha = label.borderColor.a;
|
||||||
this.ctx.lineWidth = label.borderWidth;
|
this.ctx.lineWidth = label.borderWidth;
|
||||||
this.ctx.strokeRoundedRect(-label.size.x/2, -label.size.y/2,
|
this.ctx.strokeRoundedRect(-label.size.x/2, -label.size.y/2,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import UIElement from "../Nodes/UIElement";
|
||||||
import ResourceManager from "../ResourceManager/ResourceManager";
|
import ResourceManager from "../ResourceManager/ResourceManager";
|
||||||
import UILayer from "../Scene/Layers/UILayer";
|
import UILayer from "../Scene/Layers/UILayer";
|
||||||
import Scene from "../Scene/Scene";
|
import Scene from "../Scene/Scene";
|
||||||
|
import Color from "../Utils/Color";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract framework to put all rendering in once place in the application
|
* An abstract framework to put all rendering in once place in the application
|
||||||
|
@ -48,6 +49,9 @@ export default abstract class RenderingManager {
|
||||||
*/
|
*/
|
||||||
abstract render(visibleSet: Array<CanvasNode>, tilemaps: Array<Tilemap>, uiLayers: Map<UILayer>): void;
|
abstract render(visibleSet: Array<CanvasNode>, tilemaps: Array<Tilemap>, uiLayers: Map<UILayer>): void;
|
||||||
|
|
||||||
|
/** Clears the canvas */
|
||||||
|
abstract clear(color: Color): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders a sprite
|
* Renders a sprite
|
||||||
* @param sprite The sprite to render
|
* @param sprite The sprite to render
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import Graph from "../DataTypes/Graphs/Graph";
|
import Graph from "../DataTypes/Graphs/Graph";
|
||||||
import Map from "../DataTypes/Map";
|
import Map from "../DataTypes/Map";
|
||||||
import Vec2 from "../DataTypes/Vec2";
|
import Vec2 from "../DataTypes/Vec2";
|
||||||
|
import Debug from "../Debug/Debug";
|
||||||
import CanvasNode from "../Nodes/CanvasNode";
|
import CanvasNode from "../Nodes/CanvasNode";
|
||||||
import Graphic from "../Nodes/Graphic";
|
import Graphic from "../Nodes/Graphic";
|
||||||
import { GraphicType } from "../Nodes/Graphics/GraphicTypes";
|
import { GraphicType } from "../Nodes/Graphics/GraphicTypes";
|
||||||
|
@ -10,10 +11,13 @@ import AnimatedSprite from "../Nodes/Sprites/AnimatedSprite";
|
||||||
import Sprite from "../Nodes/Sprites/Sprite";
|
import Sprite from "../Nodes/Sprites/Sprite";
|
||||||
import Tilemap from "../Nodes/Tilemap";
|
import Tilemap from "../Nodes/Tilemap";
|
||||||
import UIElement from "../Nodes/UIElement";
|
import UIElement from "../Nodes/UIElement";
|
||||||
|
import Label from "../Nodes/UIElements/Label";
|
||||||
import ShaderRegistry from "../Registry/Registries/ShaderRegistry";
|
import ShaderRegistry from "../Registry/Registries/ShaderRegistry";
|
||||||
import Registry from "../Registry/Registry";
|
import Registry from "../Registry/Registry";
|
||||||
import ResourceManager from "../ResourceManager/ResourceManager";
|
import ResourceManager from "../ResourceManager/ResourceManager";
|
||||||
|
import ParallaxLayer from "../Scene/Layers/ParallaxLayer";
|
||||||
import UILayer from "../Scene/Layers/UILayer";
|
import UILayer from "../Scene/Layers/UILayer";
|
||||||
|
import Color from "../Utils/Color";
|
||||||
import RenderingUtils from "../Utils/RenderingUtils";
|
import RenderingUtils from "../Utils/RenderingUtils";
|
||||||
import RenderingManager from "./RenderingManager";
|
import RenderingManager from "./RenderingManager";
|
||||||
import ShaderType from "./WebGLRendering/ShaderType";
|
import ShaderType from "./WebGLRendering/ShaderType";
|
||||||
|
@ -25,6 +29,7 @@ export default class WebGLRenderer extends RenderingManager {
|
||||||
protected worldSize: Vec2;
|
protected worldSize: Vec2;
|
||||||
|
|
||||||
protected gl: WebGLRenderingContext;
|
protected gl: WebGLRenderingContext;
|
||||||
|
protected textCtx: CanvasRenderingContext2D;
|
||||||
|
|
||||||
initializeCanvas(canvas: HTMLCanvasElement, width: number, height: number): WebGLRenderingContext {
|
initializeCanvas(canvas: HTMLCanvasElement, width: number, height: number): WebGLRenderingContext {
|
||||||
canvas.width = width;
|
canvas.width = width;
|
||||||
|
@ -47,6 +52,15 @@ export default class WebGLRenderer extends RenderingManager {
|
||||||
// Tell the resource manager we're using WebGL
|
// Tell the resource manager we're using WebGL
|
||||||
ResourceManager.getInstance().useWebGL(true, this.gl);
|
ResourceManager.getInstance().useWebGL(true, this.gl);
|
||||||
|
|
||||||
|
// Show the text canvas and get its context
|
||||||
|
let textCanvas = <HTMLCanvasElement>document.getElementById("text-canvas");
|
||||||
|
textCanvas.hidden = false;
|
||||||
|
this.textCtx = textCanvas.getContext("2d");
|
||||||
|
|
||||||
|
// Size the text canvas to be the same as the game canvas
|
||||||
|
textCanvas.height = height;
|
||||||
|
textCanvas.width = width;
|
||||||
|
|
||||||
return this.gl;
|
return this.gl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +68,18 @@ export default class WebGLRenderer extends RenderingManager {
|
||||||
for(let node of visibleSet){
|
for(let node of visibleSet){
|
||||||
this.renderNode(node);
|
this.renderNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uiLayers.forEach(key => {
|
||||||
|
if(!uiLayers.get(key).isHidden())
|
||||||
|
uiLayers.get(key).getItems().forEach(node => this.renderNode(<CanvasNode>node))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
clear(color: Color): void {
|
||||||
|
this.gl.clearColor(color.r, color.g, color.b, color.a);
|
||||||
|
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
this.textCtx.clearRect(0, 0, this.worldSize.x, this.worldSize.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderNode(node: CanvasNode): void {
|
protected renderNode(node: CanvasNode): void {
|
||||||
|
@ -74,44 +100,32 @@ export default class WebGLRenderer extends RenderingManager {
|
||||||
} else {
|
} else {
|
||||||
this.renderSprite(node);
|
this.renderSprite(node);
|
||||||
}
|
}
|
||||||
|
} else if(node instanceof UIElement){
|
||||||
|
this.renderUIElement(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderSprite(sprite: Sprite): void {
|
protected renderSprite(sprite: Sprite): void {
|
||||||
let shader = Registry.shaders.get(ShaderRegistry.SPRITE_SHADER);
|
let shader = Registry.shaders.get(ShaderRegistry.SPRITE_SHADER);
|
||||||
|
let options = this.addOptions(shader.getOptions(sprite), sprite);
|
||||||
let options = shader.getOptions(sprite);
|
|
||||||
options.worldSize = this.worldSize;
|
|
||||||
options.origin = this.origin;
|
|
||||||
|
|
||||||
shader.render(this.gl, options);
|
shader.render(this.gl, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderAnimatedSprite(sprite: AnimatedSprite): void {
|
protected renderAnimatedSprite(sprite: AnimatedSprite): void {
|
||||||
let shader = Registry.shaders.get(ShaderRegistry.SPRITE_SHADER);
|
let shader = Registry.shaders.get(ShaderRegistry.SPRITE_SHADER);
|
||||||
|
let options = this.addOptions(shader.getOptions(sprite), sprite);
|
||||||
let options = shader.getOptions(sprite);
|
shader.render(this.gl, options);
|
||||||
options.worldSize = this.worldSize;
|
|
||||||
options.origin = this.origin;
|
|
||||||
|
|
||||||
Registry.shaders.get(ShaderRegistry.SPRITE_SHADER).render(this.gl, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderGraphic(graphic: Graphic): void {
|
protected renderGraphic(graphic: Graphic): void {
|
||||||
|
|
||||||
if(graphic instanceof Point){
|
if(graphic instanceof Point){
|
||||||
let shader = Registry.shaders.get(ShaderRegistry.POINT_SHADER);
|
let shader = Registry.shaders.get(ShaderRegistry.POINT_SHADER);
|
||||||
let options = shader.getOptions(graphic);
|
let options = this.addOptions(shader.getOptions(graphic), graphic);
|
||||||
options.worldSize = this.worldSize;
|
|
||||||
options.origin = this.origin;
|
|
||||||
|
|
||||||
shader.render(this.gl, options);
|
shader.render(this.gl, options);
|
||||||
} else if(graphic instanceof Rect) {
|
} else if(graphic instanceof Rect) {
|
||||||
let shader = Registry.shaders.get(ShaderRegistry.RECT_SHADER);
|
let shader = Registry.shaders.get(ShaderRegistry.RECT_SHADER);
|
||||||
let options = shader.getOptions(graphic);
|
let options = this.addOptions(shader.getOptions(graphic), graphic);
|
||||||
options.worldSize = this.worldSize;
|
|
||||||
options.origin = this.origin;
|
|
||||||
|
|
||||||
shader.render(this.gl, options);
|
shader.render(this.gl, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,16 +135,48 @@ export default class WebGLRenderer extends RenderingManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderUIElement(uiElement: UIElement): void {
|
protected renderUIElement(uiElement: UIElement): void {
|
||||||
throw new Error("Method not implemented.");
|
if(uiElement instanceof Label){
|
||||||
|
let shader = Registry.shaders.get(ShaderRegistry.LABEL_SHADER);
|
||||||
|
let options = this.addOptions(shader.getOptions(uiElement), uiElement);
|
||||||
|
shader.render(this.gl, options);
|
||||||
|
|
||||||
|
this.textCtx.setTransform(1, 0, 0, 1, (uiElement.position.x - this.origin.x)*this.zoom, (uiElement.position.y - this.origin.y)*this.zoom);
|
||||||
|
this.textCtx.rotate(-uiElement.rotation);
|
||||||
|
let globalAlpha = this.textCtx.globalAlpha;
|
||||||
|
this.textCtx.globalAlpha = uiElement.alpha;
|
||||||
|
|
||||||
|
// Render text
|
||||||
|
this.textCtx.font = uiElement.getFontString();
|
||||||
|
let offset = uiElement.calculateTextOffset(this.textCtx);
|
||||||
|
this.textCtx.fillStyle = uiElement.calculateTextColor();
|
||||||
|
this.textCtx.globalAlpha = uiElement.textColor.a;
|
||||||
|
this.textCtx.fillText(uiElement.text, offset.x - uiElement.size.x/2, offset.y - uiElement.size.y/2);
|
||||||
|
|
||||||
|
this.textCtx.globalAlpha = globalAlpha;
|
||||||
|
this.textCtx.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderCustom(node: CanvasNode): void {
|
protected renderCustom(node: CanvasNode): void {
|
||||||
let shader = Registry.shaders.get(node.customShaderKey);
|
let shader = Registry.shaders.get(node.customShaderKey);
|
||||||
let options = shader.getOptions(node);
|
let options = this.addOptions(shader.getOptions(node), node);
|
||||||
options.worldSize = this.worldSize;
|
|
||||||
options.origin = this.origin;
|
|
||||||
|
|
||||||
shader.render(this.gl, options);
|
shader.render(this.gl, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected addOptions(options: Record<string, any>, node: CanvasNode): Record<string, any> {
|
||||||
|
// Give the shader access to the world size
|
||||||
|
options.worldSize = this.worldSize;
|
||||||
|
|
||||||
|
// Adjust the origin position to the parallax
|
||||||
|
let layer = node.getLayer();
|
||||||
|
let parallax = new Vec2(1, 1);
|
||||||
|
if(layer instanceof ParallaxLayer){
|
||||||
|
parallax = (<ParallaxLayer>layer).parallax;
|
||||||
|
}
|
||||||
|
|
||||||
|
options.origin = this.origin.clone().mult(parallax);
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
import Mat4x4 from "../../../DataTypes/Mat4x4";
|
||||||
|
import Vec2 from "../../../DataTypes/Vec2";
|
||||||
|
import Debug from "../../../Debug/Debug";
|
||||||
|
import Rect from "../../../Nodes/Graphics/Rect";
|
||||||
|
import Label from "../../../Nodes/UIElements/Label";
|
||||||
|
import ResourceManager from "../../../ResourceManager/ResourceManager";
|
||||||
|
import QuadShaderType from "./QuadShaderType";
|
||||||
|
|
||||||
|
export default class LabelShaderType extends QuadShaderType {
|
||||||
|
|
||||||
|
constructor(programKey: string){
|
||||||
|
super(programKey);
|
||||||
|
this.resourceManager = ResourceManager.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
initBufferObject(): void {
|
||||||
|
this.bufferObjectKey = "label";
|
||||||
|
this.resourceManager.createBuffer(this.bufferObjectKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
render(gl: WebGLRenderingContext, options: Record<string, any>): void {
|
||||||
|
const backgroundColor = options.backgroundColor.toWebGL();
|
||||||
|
const borderColor = options.borderColor.toWebGL();
|
||||||
|
|
||||||
|
const program = this.resourceManager.getShaderProgram(this.programKey);
|
||||||
|
const buffer = this.resourceManager.getBuffer(this.bufferObjectKey);
|
||||||
|
|
||||||
|
gl.useProgram(program);
|
||||||
|
|
||||||
|
const vertexData = this.getVertices(options.size.x, options.size.y);
|
||||||
|
|
||||||
|
const FSIZE = vertexData.BYTES_PER_ELEMENT;
|
||||||
|
|
||||||
|
// Bind the buffer
|
||||||
|
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||||
|
gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW);
|
||||||
|
|
||||||
|
// Attributes
|
||||||
|
const a_Position = gl.getAttribLocation(program, "a_Position");
|
||||||
|
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 2 * FSIZE, 0 * FSIZE);
|
||||||
|
gl.enableVertexAttribArray(a_Position);
|
||||||
|
|
||||||
|
// Uniforms
|
||||||
|
const u_BackgroundColor = gl.getUniformLocation(program, "u_BackgroundColor");
|
||||||
|
gl.uniform4fv(u_BackgroundColor, backgroundColor);
|
||||||
|
|
||||||
|
const u_BorderColor = gl.getUniformLocation(program, "u_BorderColor");
|
||||||
|
gl.uniform4fv(u_BorderColor, borderColor);
|
||||||
|
|
||||||
|
const u_MaxSize = gl.getUniformLocation(program, "u_MaxSize");
|
||||||
|
gl.uniform2f(u_MaxSize, -vertexData[0], vertexData[1]);
|
||||||
|
|
||||||
|
// Get transformation matrix
|
||||||
|
// We want a square for our rendering space, so get the maximum dimension of our quad
|
||||||
|
let maxDimension = Math.max(options.size.x, options.size.y);
|
||||||
|
|
||||||
|
const u_BorderWidth = gl.getUniformLocation(program, "u_BorderWidth");
|
||||||
|
gl.uniform1f(u_BorderWidth, options.borderWidth/maxDimension);
|
||||||
|
|
||||||
|
const u_BorderRadius = gl.getUniformLocation(program, "u_BorderRadius");
|
||||||
|
gl.uniform1f(u_BorderRadius, options.borderRadius/maxDimension);
|
||||||
|
|
||||||
|
// The size of the rendering space will be a square with this maximum dimension
|
||||||
|
let size = new Vec2(maxDimension, maxDimension).scale(2/options.worldSize.x, 2/options.worldSize.y);
|
||||||
|
|
||||||
|
// Center our translations around (0, 0)
|
||||||
|
const translateX = (options.position.x - options.origin.x - options.worldSize.x/2)/maxDimension;
|
||||||
|
const translateY = -(options.position.y - options.origin.y - options.worldSize.y/2)/maxDimension;
|
||||||
|
|
||||||
|
// Create our transformation matrix
|
||||||
|
this.translation.translate(new Float32Array([translateX, translateY]));
|
||||||
|
this.scale.scale(size);
|
||||||
|
this.rotation.rotate(options.rotation);
|
||||||
|
let transformation = Mat4x4.MULT(this.translation, this.scale, this.rotation);
|
||||||
|
|
||||||
|
// Pass the translation matrix to our shader
|
||||||
|
const u_Transform = gl.getUniformLocation(program, "u_Transform");
|
||||||
|
gl.uniformMatrix4fv(u_Transform, false, transformation.toArray());
|
||||||
|
|
||||||
|
// Draw the quad
|
||||||
|
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rendering space always has to be a square, so make sure its square w.r.t to the largest dimension
|
||||||
|
* @param w The width of the quad in pixels
|
||||||
|
* @param h The height of the quad in pixels
|
||||||
|
* @returns An array of the vertices of the quad
|
||||||
|
*/
|
||||||
|
getVertices(w: number, h: number): Float32Array {
|
||||||
|
let x, y;
|
||||||
|
|
||||||
|
if(h > w){
|
||||||
|
y = 0.5;
|
||||||
|
x = w/(2*h);
|
||||||
|
} else {
|
||||||
|
x = 0.5;
|
||||||
|
y = h/(2*w);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Float32Array([
|
||||||
|
-x, y,
|
||||||
|
-x, -y,
|
||||||
|
x, y,
|
||||||
|
x, -y
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
getOptions(rect: Label): Record<string, any> {
|
||||||
|
let options: Record<string, any> = {
|
||||||
|
position: rect.position,
|
||||||
|
backgroundColor: rect.calculateBackgroundColor(),
|
||||||
|
borderColor: rect.calculateBorderColor(),
|
||||||
|
borderWidth: rect.borderWidth,
|
||||||
|
borderRadius: rect.borderRadius,
|
||||||
|
size: rect.size,
|
||||||
|
rotation: rect.rotation
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,24 +22,9 @@ export default class SpriteShaderType extends QuadShaderType {
|
||||||
const program = this.resourceManager.getShaderProgram(this.programKey);
|
const program = this.resourceManager.getShaderProgram(this.programKey);
|
||||||
const buffer = this.resourceManager.getBuffer(this.bufferObjectKey);
|
const buffer = this.resourceManager.getBuffer(this.bufferObjectKey);
|
||||||
const texture = this.resourceManager.getTexture(options.imageKey);
|
const texture = this.resourceManager.getTexture(options.imageKey);
|
||||||
const image = this.resourceManager.getImage(options.imageKey);
|
|
||||||
|
|
||||||
gl.useProgram(program);
|
gl.useProgram(program);
|
||||||
|
|
||||||
// Enable texture0
|
|
||||||
gl.activeTexture(gl.TEXTURE0);
|
|
||||||
|
|
||||||
// Bind our texture to texture 0
|
|
||||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
||||||
|
|
||||||
// Set the texture parameters
|
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
||||||
|
|
||||||
// Set the texture image
|
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
|
|
||||||
|
|
||||||
const vertexData = this.getVertices(options.size.x, options.size.y, options.scale);
|
const vertexData = this.getVertices(options.size.x, options.size.y, options.scale);
|
||||||
|
|
||||||
const FSIZE = vertexData.BYTES_PER_ELEMENT;
|
const FSIZE = vertexData.BYTES_PER_ELEMENT;
|
||||||
|
@ -79,9 +64,9 @@ export default class SpriteShaderType extends QuadShaderType {
|
||||||
const u_Transform = gl.getUniformLocation(program, "u_Transform");
|
const u_Transform = gl.getUniformLocation(program, "u_Transform");
|
||||||
gl.uniformMatrix4fv(u_Transform, false, transformation.toArray());
|
gl.uniformMatrix4fv(u_Transform, false, transformation.toArray());
|
||||||
|
|
||||||
// Set texture unit 0 to the sampler
|
// Set up our sampler with our assigned texture unit
|
||||||
const u_Sampler = gl.getUniformLocation(program, "u_Sampler");
|
const u_Sampler = gl.getUniformLocation(program, "u_Sampler");
|
||||||
gl.uniform1i(u_Sampler, 0);
|
gl.uniform1i(u_Sampler, texture);
|
||||||
|
|
||||||
// Pass in texShift
|
// Pass in texShift
|
||||||
const u_texShift = gl.getUniformLocation(program, "u_texShift");
|
const u_texShift = gl.getUniformLocation(program, "u_texShift");
|
||||||
|
|
|
@ -5,7 +5,6 @@ import StringUtils from "../Utils/StringUtils";
|
||||||
import AudioManager from "../Sound/AudioManager";
|
import AudioManager from "../Sound/AudioManager";
|
||||||
import Spritesheet from "../DataTypes/Spritesheet";
|
import Spritesheet from "../DataTypes/Spritesheet";
|
||||||
import WebGLProgramType from "../DataTypes/Rendering/WebGLProgramType";
|
import WebGLProgramType from "../DataTypes/Rendering/WebGLProgramType";
|
||||||
import PhysicsManager from "../Physics/PhysicsManager";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The resource manager for the game engine.
|
* The resource manager for the game engine.
|
||||||
|
@ -80,7 +79,8 @@ export default class ResourceManager {
|
||||||
private gl_DefaultShaderPrograms: Map<WebGLProgramType>;
|
private gl_DefaultShaderPrograms: Map<WebGLProgramType>;
|
||||||
private gl_ShaderPrograms: Map<WebGLProgramType>;
|
private gl_ShaderPrograms: Map<WebGLProgramType>;
|
||||||
|
|
||||||
private gl_Textures: Map<WebGLTexture>;
|
private gl_Textures: Map<number>;
|
||||||
|
private gl_NextTextureID: number;
|
||||||
private gl_Buffers: Map<WebGLBuffer>;
|
private gl_Buffers: Map<WebGLBuffer>;
|
||||||
|
|
||||||
private gl: WebGLRenderingContext;
|
private gl: WebGLRenderingContext;
|
||||||
|
@ -117,6 +117,7 @@ export default class ResourceManager {
|
||||||
this.gl_ShaderPrograms = new Map();
|
this.gl_ShaderPrograms = new Map();
|
||||||
|
|
||||||
this.gl_Textures = new Map();
|
this.gl_Textures = new Map();
|
||||||
|
this.gl_NextTextureID = 0;
|
||||||
this.gl_Buffers = new Map();
|
this.gl_Buffers = new Map();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -226,7 +227,7 @@ export default class ResourceManager {
|
||||||
* @param callback The function to cal when the resources are finished loading
|
* @param callback The function to cal when the resources are finished loading
|
||||||
*/
|
*/
|
||||||
loadResourcesFromQueue(callback: Function): void {
|
loadResourcesFromQueue(callback: Function): void {
|
||||||
this.loadonly_typesToLoad = 3;
|
this.loadonly_typesToLoad = 5;
|
||||||
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
||||||
|
@ -443,7 +444,9 @@ export default class ResourceManager {
|
||||||
this.images.add(key, image);
|
this.images.add(key, image);
|
||||||
|
|
||||||
// If WebGL is active, create a texture
|
// If WebGL is active, create a texture
|
||||||
this.createWebGLTexture(key);
|
if(this.gl_WebGLActive){
|
||||||
|
this.createWebGLTexture(key, image);
|
||||||
|
}
|
||||||
|
|
||||||
// Finish image load
|
// Finish image load
|
||||||
this.finishLoadingImage(callbackIfLast);
|
this.finishLoadingImage(callbackIfLast);
|
||||||
|
@ -526,7 +529,7 @@ export default class ResourceManager {
|
||||||
|
|
||||||
/* ########## WEBGL SPECIFIC FUNCTIONS ########## */
|
/* ########## WEBGL SPECIFIC FUNCTIONS ########## */
|
||||||
|
|
||||||
public getTexture(key: string): WebGLTexture {
|
public getTexture(key: string): number {
|
||||||
return this.gl_Textures.get(key);
|
return this.gl_Textures.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,10 +541,49 @@ export default class ResourceManager {
|
||||||
return this.gl_Buffers.get(key);
|
return this.gl_Buffers.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private createWebGLTexture(key:string): void {
|
private createWebGLTexture(imageKey: string, image: HTMLImageElement): void {
|
||||||
if(this.gl_WebGLActive){
|
// Get the texture ID
|
||||||
|
const textureID = this.getTextureID(this.gl_NextTextureID);
|
||||||
|
|
||||||
|
// Create the texture
|
||||||
const texture = this.gl.createTexture();
|
const texture = this.gl.createTexture();
|
||||||
this.gl_Textures.add(key, texture);
|
|
||||||
|
// Set up the texture
|
||||||
|
// Enable texture0
|
||||||
|
this.gl.activeTexture(textureID);
|
||||||
|
|
||||||
|
// Bind our texture to texture 0
|
||||||
|
this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
|
||||||
|
|
||||||
|
// Set the texture parameters
|
||||||
|
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
|
||||||
|
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
|
||||||
|
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
|
||||||
|
|
||||||
|
// Set the texture image
|
||||||
|
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image);
|
||||||
|
|
||||||
|
// Add the texture to our map with the same key as the image
|
||||||
|
this.gl_Textures.add(imageKey, this.gl_NextTextureID);
|
||||||
|
|
||||||
|
// Increment the key
|
||||||
|
this.gl_NextTextureID += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTextureID(id: number): number {
|
||||||
|
// Start with 9 cases - this can be expanded if needed, but for the best performance,
|
||||||
|
// Textures should be stitched into an atlas
|
||||||
|
switch(id){
|
||||||
|
case 0: return this.gl.TEXTURE0;
|
||||||
|
case 1: return this.gl.TEXTURE1;
|
||||||
|
case 2: return this.gl.TEXTURE2;
|
||||||
|
case 3: return this.gl.TEXTURE3;
|
||||||
|
case 4: return this.gl.TEXTURE4;
|
||||||
|
case 5: return this.gl.TEXTURE5;
|
||||||
|
case 6: return this.gl.TEXTURE6;
|
||||||
|
case 7: return this.gl.TEXTURE7;
|
||||||
|
case 8: return this.gl.TEXTURE8;
|
||||||
|
default: return this.gl.TEXTURE9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ export default class Scene implements Updateable {
|
||||||
* @param options The options for Scene initialization
|
* @param options The options for Scene initialization
|
||||||
*/
|
*/
|
||||||
constructor(viewport: Viewport, sceneManager: SceneManager, renderingManager: RenderingManager, options: Record<string, any>){
|
constructor(viewport: Viewport, sceneManager: SceneManager, renderingManager: RenderingManager, options: Record<string, any>){
|
||||||
this.sceneOptions = SceneOptions.parse(options);
|
this.sceneOptions = SceneOptions.parse(options? options : {});
|
||||||
|
|
||||||
this.worldSize = new Vec2(500, 500);
|
this.worldSize = new Vec2(500, 500);
|
||||||
this.viewport = viewport;
|
this.viewport = viewport;
|
||||||
|
@ -121,6 +121,9 @@ export default class Scene implements Updateable {
|
||||||
this.load = ResourceManager.getInstance();
|
this.load = ResourceManager.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A lifecycle method that gets called immediately after a new scene is created, before anything else. */
|
||||||
|
initScene(init: Record<string, any>): void {}
|
||||||
|
|
||||||
/** A lifecycle method that gets called when a new scene is created. Load all files you wish to access in the scene here. */
|
/** A lifecycle method that gets called when a new scene is created. Load all files you wish to access in the scene here. */
|
||||||
loadScene(): void {}
|
loadScene(): void {}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import Scene from "./Scene";
|
import Scene from "./Scene";
|
||||||
import ResourceManager from "../ResourceManager/ResourceManager";
|
import ResourceManager from "../ResourceManager/ResourceManager";
|
||||||
import Viewport from "../SceneGraph/Viewport";
|
import Viewport from "../SceneGraph/Viewport";
|
||||||
import Game from "../Loop/Game";
|
|
||||||
import RenderingManager from "../Rendering/RenderingManager";
|
import RenderingManager from "../Rendering/RenderingManager";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,11 +40,14 @@ export default class SceneManager {
|
||||||
* Add a scene as the main scene.
|
* Add a scene as the main scene.
|
||||||
* Use this method if you've created a subclass of Scene, and you want to add it as the main Scene.
|
* Use this method if you've created a subclass of Scene, and you want to add it as the main Scene.
|
||||||
* @param constr The constructor of the scene to add
|
* @param constr The constructor of the scene to add
|
||||||
|
* @param init An object to pass to the init function of the new scene
|
||||||
*/
|
*/
|
||||||
public addScene<T extends Scene>(constr: new (...args: any) => T, options: Record<string, any>): void {
|
public addScene<T extends Scene>(constr: new (...args: any) => T, init?: Record<string, any>, options?: Record<string, any>): void {
|
||||||
let scene = new constr(this.viewport, this, this.renderingManager, options);
|
let scene = new constr(this.viewport, this, this.renderingManager, options);
|
||||||
this.currentScene = scene;
|
this.currentScene = scene;
|
||||||
|
|
||||||
|
scene.initScene(init);
|
||||||
|
|
||||||
// Enqueue all scene asset loads
|
// Enqueue all scene asset loads
|
||||||
scene.loadScene();
|
scene.loadScene();
|
||||||
|
|
||||||
|
@ -64,16 +66,12 @@ export default class SceneManager {
|
||||||
* Change from the current scene to this new scene.
|
* Change from the current scene to this new scene.
|
||||||
* Use this method if you've created a subclass of Scene, and you want to add it as the main Scene.
|
* Use this method if you've created a subclass of Scene, and you want to add it as the main Scene.
|
||||||
* @param constr The constructor of the scene to change to
|
* @param constr The constructor of the scene to change to
|
||||||
|
* @param init An object to pass to the init function of the new scene
|
||||||
*/
|
*/
|
||||||
public changeScene<T extends Scene>(constr: new (...args: any) => T, options: Record<string, any>): void {
|
public changeScene<T extends Scene>(constr: new (...args: any) => T, init?: Record<string, any>, options?: Record<string, any>): void {
|
||||||
// unload current scene
|
this.viewport.setCenter(this.viewport.getHalfSize().x, this.viewport.getHalfSize().y);
|
||||||
this.currentScene.unloadScene();
|
|
||||||
|
|
||||||
this.resourceManager.unloadAllResources();
|
this.addScene(constr, init, options);
|
||||||
|
|
||||||
this.viewport.setCenter(0, 0);
|
|
||||||
|
|
||||||
this.addScene(constr, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,10 +86,8 @@ export default class SceneManager {
|
||||||
* Renders the current Scene
|
* Renders the current Scene
|
||||||
*/
|
*/
|
||||||
public render(): void {
|
public render(): void {
|
||||||
if(this.currentScene.isRunning()){
|
|
||||||
this.currentScene.render();
|
this.currentScene.render();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the current Scene
|
* Updates the current Scene
|
||||||
|
|
|
@ -49,14 +49,10 @@ export default class Viewport {
|
||||||
// Set the size of the canvas
|
// Set the size of the canvas
|
||||||
this.setCanvasSize(canvasSize);
|
this.setCanvasSize(canvasSize);
|
||||||
|
|
||||||
console.log(canvasSize, zoomLevel);
|
|
||||||
|
|
||||||
// Set the size of the viewport
|
// Set the size of the viewport
|
||||||
this.setSize(canvasSize);
|
this.setSize(canvasSize);
|
||||||
this.setZoomLevel(zoomLevel);
|
this.setZoomLevel(zoomLevel);
|
||||||
|
|
||||||
console.log(this.getHalfSize().toString());
|
|
||||||
|
|
||||||
// Set the center (and make the viewport stay there)
|
// Set the center (and make the viewport stay there)
|
||||||
this.setCenter(this.view.halfSize.clone());
|
this.setCenter(this.view.halfSize.clone());
|
||||||
this.setFocus(this.view.halfSize.clone());
|
this.setFocus(this.view.halfSize.clone());
|
||||||
|
|
|
@ -69,10 +69,10 @@ export default class Color {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Purple color
|
* Magenta color
|
||||||
* @returns rgb(255, 0, 255)
|
* @returns rgb(255, 0, 255)
|
||||||
*/
|
*/
|
||||||
static get PURPLE(): Color {
|
static get MAGENTA(): Color {
|
||||||
return new Color(255, 0, 255, 1);
|
return new Color(255, 0, 255, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ export default class Color {
|
||||||
* @returns A new lighter Color
|
* @returns A new lighter Color
|
||||||
*/
|
*/
|
||||||
lighten(): Color {
|
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);
|
return new Color(MathUtils.clamp(this.r + 40, 0, 255), MathUtils.clamp(this.g + 40, 0, 255), MathUtils.clamp(this.b + 40, 0, 255), MathUtils.clamp(this.a + 10, 0, 255));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -135,7 +135,7 @@ export default class Color {
|
||||||
* @returns A new darker Color
|
* @returns A new darker Color
|
||||||
*/
|
*/
|
||||||
darken(): Color {
|
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);
|
return new Color(MathUtils.clamp(this.r - 40, 0, 255), MathUtils.clamp(this.g - 40, 0, 255), MathUtils.clamp(this.b - 40, 0, 255), MathUtils.clamp(this.a + 10, 0, 255));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import MathUtils from "./MathUtils";
|
import MathUtils from "./MathUtils";
|
||||||
import Color from "./Color";
|
import Color from "./Color";
|
||||||
import Perlin from "./Rand/Perlin";
|
import Perlin from "./Rand/Perlin";
|
||||||
|
import Vec2 from "../DataTypes/Vec2";
|
||||||
|
|
||||||
class Noise {
|
class Noise {
|
||||||
p: Perlin = new Perlin();
|
p: Perlin = new Perlin();
|
||||||
|
@ -22,6 +23,16 @@ export default class RandUtils {
|
||||||
return Math.floor(Math.random()*(max - min) + min);
|
return Math.floor(Math.random()*(max - min) + min);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a random float in the specified range
|
||||||
|
* @param min The min of the range (inclusive)
|
||||||
|
* @param max The max of the range (exclusive)
|
||||||
|
* @returns A random float in the range [min, max)
|
||||||
|
*/
|
||||||
|
static randFloat(min: number, max: number): number {
|
||||||
|
return Math.random()*(max - min) + min;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a random hexadecimal number in the specified range
|
* Generates a random hexadecimal number in the specified range
|
||||||
* @param min The min of the range (inclusive)
|
* @param min The min of the range (inclusive)
|
||||||
|
@ -43,6 +54,10 @@ export default class RandUtils {
|
||||||
return new Color(r, g, b);
|
return new Color(r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static randVec(minX: number, maxX: number, minY: number, maxY: number): Vec2 {
|
||||||
|
return new Vec2(this.randFloat(minX, maxX), this.randFloat(minY, maxY));
|
||||||
|
}
|
||||||
|
|
||||||
/** A noise generator */
|
/** A noise generator */
|
||||||
static noise: Noise = new Noise();
|
static noise: Noise = new Noise();
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ export default class default_scene extends Scene {
|
||||||
// The first argument is the key of the sprite (you get to decide what it is).
|
// The first argument is the key of the sprite (you get to decide what it is).
|
||||||
// The second argument is the path to the actual image.
|
// The second argument is the path to the actual image.
|
||||||
// Paths start in the "dist/" folder, so start building your path from there
|
// Paths start in the "dist/" folder, so start building your path from there
|
||||||
this.load.image("logo", "demo_assets/wolfie2d_text.png");
|
this.load.image("logo", "demo_assets/images/wolfie2d_text.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
// startScene() is where you should build any game objects you wish to have in your scene,
|
// startScene() is where you should build any game objects you wish to have in your scene,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import PlayerController from "./PlatformerPlayerController";
|
import PlayerController from "./PlatformerPlayerController";
|
||||||
import Vec2 from "./Wolfie2D/DataTypes/Vec2";
|
import Vec2 from "../Wolfie2D/DataTypes/Vec2";
|
||||||
import AnimatedSprite from "./Wolfie2D/Nodes/Sprites/AnimatedSprite";
|
import AnimatedSprite from "../Wolfie2D/Nodes/Sprites/AnimatedSprite";
|
||||||
import Scene from "./Wolfie2D/Scene/Scene";
|
import Scene from "../Wolfie2D/Scene/Scene";
|
||||||
|
|
||||||
export default class Platformer extends Scene {
|
export default class Platformer extends Scene {
|
||||||
private player: AnimatedSprite;
|
private player: AnimatedSprite;
|
|
@ -1,9 +1,9 @@
|
||||||
import AI from "./Wolfie2D/DataTypes/Interfaces/AI";
|
import AI from "../Wolfie2D/DataTypes/Interfaces/AI";
|
||||||
import Emitter from "./Wolfie2D/Events/Emitter";
|
import Emitter from "../Wolfie2D/Events/Emitter";
|
||||||
import GameEvent from "./Wolfie2D/Events/GameEvent";
|
import GameEvent from "../Wolfie2D/Events/GameEvent";
|
||||||
import { GameEventType } from "./Wolfie2D/Events/GameEventType";
|
import { GameEventType } from "../Wolfie2D/Events/GameEventType";
|
||||||
import Input from "./Wolfie2D/Input/Input";
|
import Input from "../Wolfie2D/Input/Input";
|
||||||
import AnimatedSprite from "./Wolfie2D/Nodes/Sprites/AnimatedSprite";
|
import AnimatedSprite from "../Wolfie2D/Nodes/Sprites/AnimatedSprite";
|
||||||
|
|
||||||
export default class PlayerController implements AI {
|
export default class PlayerController implements AI {
|
||||||
protected owner: AnimatedSprite;
|
protected owner: AnimatedSprite;
|
||||||
|
@ -16,6 +16,8 @@ export default class PlayerController implements AI {
|
||||||
this.emitter = new Emitter();
|
this.emitter = new Emitter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
activate(options: Record<string, any>): void {}
|
||||||
|
|
||||||
handleEvent(event: GameEvent): void {
|
handleEvent(event: GameEvent): void {
|
||||||
// Do nothing for now
|
// Do nothing for now
|
||||||
}
|
}
|
|
@ -1,68 +0,0 @@
|
||||||
import Map from "../Wolfie2D/DataTypes/Map";
|
|
||||||
import Mat4x4 from "../Wolfie2D/DataTypes/Mat4x4";
|
|
||||||
import Vec2 from "../Wolfie2D/DataTypes/Vec2";
|
|
||||||
import RectShaderType from "../Wolfie2D/Rendering/WebGLRendering/ShaderTypes/RectShaderType";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The gradient circle is technically rendered on a quad, and is similar to a rect, so we'll extend the RectShaderType
|
|
||||||
*/
|
|
||||||
export default class GradientCircleShaderType extends RectShaderType {
|
|
||||||
|
|
||||||
initBufferObject(): void {
|
|
||||||
this.bufferObjectKey = "gradient_circle";
|
|
||||||
this.resourceManager.createBuffer(this.bufferObjectKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
render(gl: WebGLRenderingContext, options: Record<string, any>): void {
|
|
||||||
// Get our program and buffer object
|
|
||||||
const program = this.resourceManager.getShaderProgram(this.programKey);
|
|
||||||
const buffer = this.resourceManager.getBuffer(this.bufferObjectKey);
|
|
||||||
|
|
||||||
// Let WebGL know we're using our shader program
|
|
||||||
gl.useProgram(program);
|
|
||||||
|
|
||||||
// Get our vertex data
|
|
||||||
const vertexData = this.getVertices(options.size.x, options.size.y);
|
|
||||||
const FSIZE = vertexData.BYTES_PER_ELEMENT;
|
|
||||||
|
|
||||||
// Bind the buffer
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
||||||
gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW);
|
|
||||||
|
|
||||||
/* ##### ATTRIBUTES ##### */
|
|
||||||
// No texture, the only thing we care about is vertex position
|
|
||||||
const a_Position = gl.getAttribLocation(program, "a_Position");
|
|
||||||
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 2 * FSIZE, 0 * FSIZE);
|
|
||||||
gl.enableVertexAttribArray(a_Position);
|
|
||||||
|
|
||||||
/* ##### UNIFORMS ##### */
|
|
||||||
// Send the color to the gradient circle
|
|
||||||
const color = options.color.toWebGL();
|
|
||||||
const u_Color = gl.getUniformLocation(program, "u_Color");
|
|
||||||
gl.uniform4fv(u_Color, color);
|
|
||||||
|
|
||||||
// Get transformation matrix
|
|
||||||
// We have a square for our rendering space, so get the maximum dimension of our quad
|
|
||||||
let maxDimension = Math.max(options.size.x, options.size.y);
|
|
||||||
|
|
||||||
// The size of the rendering space will be a square with this maximum dimension
|
|
||||||
let size = new Vec2(maxDimension, maxDimension).scale(2/options.worldSize.x, 2/options.worldSize.y);
|
|
||||||
|
|
||||||
// Center our translations around (0, 0)
|
|
||||||
const translateX = (options.position.x - options.origin.x - options.worldSize.x/2)/maxDimension;
|
|
||||||
const translateY = -(options.position.y - options.origin.y - options.worldSize.y/2)/maxDimension;
|
|
||||||
|
|
||||||
// Create our transformation matrix
|
|
||||||
this.translation.translate(new Float32Array([translateX, translateY]));
|
|
||||||
this.scale.scale(size);
|
|
||||||
this.rotation.rotate(options.rotation);
|
|
||||||
let transformation = Mat4x4.MULT(this.translation, this.scale, this.rotation);
|
|
||||||
|
|
||||||
// Pass the translation matrix to our shader
|
|
||||||
const u_Transform = gl.getUniformLocation(program, "u_Transform");
|
|
||||||
gl.uniformMatrix4fv(u_Transform, false, transformation.toArray());
|
|
||||||
|
|
||||||
// Draw the quad
|
|
||||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
export enum Homework1Event {
|
|
||||||
PLAYER_DAMAGE = "PLAYER_DAMAGE",
|
|
||||||
SPAWN_FLEET = "SPAWN_FLEET"
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum Homework1Shaders {
|
|
||||||
GRADIENT_CIRCLE = "GRADIENT_CIRCLE"
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
import AABB from "../Wolfie2D/DataTypes/Shapes/AABB";
|
|
||||||
import Vec2 from "../Wolfie2D/DataTypes/Vec2";
|
|
||||||
import Graphic from "../Wolfie2D/Nodes/Graphic";
|
|
||||||
import { GraphicType } from "../Wolfie2D/Nodes/Graphics/GraphicTypes";
|
|
||||||
import AnimatedSprite from "../Wolfie2D/Nodes/Sprites/AnimatedSprite";
|
|
||||||
import Scene from "../Wolfie2D/Scene/Scene";
|
|
||||||
import { Homework1Event, Homework1Shaders } from "./HW1_Enums";
|
|
||||||
import SpaceshipPlayerController from "./SpaceshipPlayerController";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In Wolfie2D, custom scenes extend the original scene class.
|
|
||||||
* This gives us access to lifecycle methods to control our game.
|
|
||||||
*/
|
|
||||||
export default class Homework1_Scene extends Scene {
|
|
||||||
// Here we define member variables of our game, and object pools for adding in game objects
|
|
||||||
private player: AnimatedSprite;
|
|
||||||
|
|
||||||
// Create an object pool for our fleet
|
|
||||||
private MAX_FLEET_SIZE = 20;
|
|
||||||
private fleet: Array<AnimatedSprite> = new Array(this.MAX_FLEET_SIZE);
|
|
||||||
|
|
||||||
// Create an object pool for our fleet
|
|
||||||
private MAX_NUM_ASTEROIDS = 6;
|
|
||||||
private asteroids: Array<Graphic> = new Array(this.MAX_NUM_ASTEROIDS);
|
|
||||||
|
|
||||||
// Create an object pool for our fleet
|
|
||||||
private MAX_NUM_MINERALS = 20;
|
|
||||||
private minerals: Array<Graphic> = new Array(this.MAX_NUM_MINERALS);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* loadScene() overrides the parent class method. It allows us to load in custom assets for
|
|
||||||
* use in our scene.
|
|
||||||
*/
|
|
||||||
loadScene(){
|
|
||||||
/* ##### DO NOT MODIFY ##### */
|
|
||||||
// Load in the player spaceship spritesheet
|
|
||||||
this.load.spritesheet("player", "hw1_assets/spritesheets/player_spaceship.json");
|
|
||||||
|
|
||||||
/* ##### YOUR CODE GOES BELOW THIS LINE ##### */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* startScene() allows us to add in the assets we loaded in loadScene() as game objects.
|
|
||||||
* Everything here happens strictly before update
|
|
||||||
*/
|
|
||||||
startScene(){
|
|
||||||
/* ##### DO NOT MODIFY ##### */
|
|
||||||
// Create a layer to serve as our main game - Feel free to use this for your own assets
|
|
||||||
// It is given a depth of 5 to be above our background
|
|
||||||
this.addLayer("primary", 5);
|
|
||||||
|
|
||||||
// Add in the player as an animated sprite
|
|
||||||
// We give it the key specified in our load function and the name of the layer
|
|
||||||
this.player = this.add.animatedSprite("player", "primary");
|
|
||||||
|
|
||||||
// Set the player's position to the middle of the screen, and scale it down
|
|
||||||
this.player.position.set(this.viewport.getCenter().x, this.viewport.getCenter().y);
|
|
||||||
this.player.scale.set(0.5, 0.5);
|
|
||||||
|
|
||||||
// Play the idle animation by default
|
|
||||||
this.player.animation.play("idle");
|
|
||||||
|
|
||||||
// Add physics to the player
|
|
||||||
let playerCollider = new AABB(Vec2.ZERO, new Vec2(64, 64));
|
|
||||||
|
|
||||||
// We'll specify a smaller collider centered on the player.
|
|
||||||
// Also, we don't need collision handling, so disable it.
|
|
||||||
this.player.addPhysics(playerCollider, Vec2.ZERO, false);
|
|
||||||
|
|
||||||
// Add a a playerController to the player
|
|
||||||
this.player.addAI(SpaceshipPlayerController, {owner: this.player, spawnFleetEventKey: "spawnFleet"});
|
|
||||||
|
|
||||||
/* ##### YOUR CODE GOES BELOW THIS LINE ##### */
|
|
||||||
// Initialize the fleet object pool
|
|
||||||
|
|
||||||
// Initialize the mineral object pool
|
|
||||||
for(let i = 0; i < this.minerals.length; i++){
|
|
||||||
this.minerals[i] = this.add.graphic(GraphicType.RECT, "primary", {position: new Vec2(0, 0), size: new Vec2(32, 32)});
|
|
||||||
this.minerals[i].visible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the asteroid object pool
|
|
||||||
let gc = this.add.graphic(GraphicType.RECT, "primary", {position: new Vec2(400, 400), size: new Vec2(100, 100)});
|
|
||||||
gc.useCustomShader(Homework1Shaders.GRADIENT_CIRCLE);
|
|
||||||
|
|
||||||
// Subscribe to events
|
|
||||||
this.receiver.subscribe(Homework1Event.PLAYER_DAMAGE);
|
|
||||||
this.receiver.subscribe(Homework1Event.SPAWN_FLEET);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* updateScene() is where the real work is done. This is where any custom behavior goes.
|
|
||||||
*/
|
|
||||||
updateScene(){
|
|
||||||
// Handle events we care about
|
|
||||||
while(this.receiver.hasNextEvent()){
|
|
||||||
let event = this.receiver.getNextEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for collisions
|
|
||||||
for(let i = 0; i < this.minerals.length; i++){
|
|
||||||
if(this.player.collisionShape.overlaps(this.minerals[i].boundary)){
|
|
||||||
console.log(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
import AI from "../Wolfie2D/DataTypes/Interfaces/AI";
|
|
||||||
import Vec2 from "../Wolfie2D/DataTypes/Vec2";
|
|
||||||
import Debug from "../Wolfie2D/Debug/Debug";
|
|
||||||
import Emitter from "../Wolfie2D/Events/Emitter";
|
|
||||||
import GameEvent from "../Wolfie2D/Events/GameEvent";
|
|
||||||
import Input from "../Wolfie2D/Input/Input";
|
|
||||||
import AnimatedSprite from "../Wolfie2D/Nodes/Sprites/AnimatedSprite";
|
|
||||||
import MathUtils from "../Wolfie2D/Utils/MathUtils";
|
|
||||||
import { Homework1Event } from "./HW1_Enums";
|
|
||||||
|
|
||||||
export default class SpaceshipPlayerController implements AI {
|
|
||||||
// We want to be able to control our owner, so keep track of them
|
|
||||||
private owner: AnimatedSprite;
|
|
||||||
|
|
||||||
// The direction the spaceship is moving
|
|
||||||
private direction: Vec2;
|
|
||||||
private MIN_SPEED: number = 0;
|
|
||||||
private MAX_SPEED: number = 300;
|
|
||||||
private speed: number;
|
|
||||||
private ACCELERATION: number = 4;
|
|
||||||
private rotationSpeed: number;
|
|
||||||
|
|
||||||
// An emitter to hook into the event queue
|
|
||||||
private emitter: Emitter;
|
|
||||||
|
|
||||||
initializeAI(owner: AnimatedSprite, options: Record<string, any>): void {
|
|
||||||
this.owner = owner;
|
|
||||||
|
|
||||||
// Start facing up
|
|
||||||
this.direction = new Vec2(0, 1);
|
|
||||||
this.speed = 0;
|
|
||||||
this.rotationSpeed = 2;
|
|
||||||
|
|
||||||
this.emitter = new Emitter();
|
|
||||||
}
|
|
||||||
|
|
||||||
handleEvent(event: GameEvent): void {
|
|
||||||
// We need to handle animations when we get hurt
|
|
||||||
if(event.type === Homework1Event.PLAYER_DAMAGE){
|
|
||||||
this.owner.animation.play("shield");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
update(deltaT: number): void {
|
|
||||||
// We need to handle player input
|
|
||||||
let forwardAxis = (Input.isPressed('forward') ? 1 : 0) + (Input.isPressed('backward') ? -1 : 0);
|
|
||||||
let turnDirection = (Input.isPressed('turn_ccw') ? -1 : 0) + (Input.isPressed('turn_cw') ? 1 : 0);
|
|
||||||
|
|
||||||
// Space controls - speed stays the same if nothing happens
|
|
||||||
// Forward to speed up, backward to slow down
|
|
||||||
this.speed += this.ACCELERATION * forwardAxis;
|
|
||||||
this.speed = MathUtils.clamp(this.speed, this.MIN_SPEED, this.MAX_SPEED);
|
|
||||||
|
|
||||||
// Rotate the player
|
|
||||||
this.direction.rotateCCW(turnDirection * this.rotationSpeed * deltaT);
|
|
||||||
|
|
||||||
// Update the visual direction of the player
|
|
||||||
this.owner.rotation = -(Math.atan2(this.direction.y, this.direction.x) - Math.PI/2);
|
|
||||||
|
|
||||||
// Move the player with physics
|
|
||||||
this.owner.move(this.direction.scaled(-this.speed * deltaT));
|
|
||||||
|
|
||||||
// If the player clicked, we need to spawn in a fleet member
|
|
||||||
if(Input.isMouseJustPressed()){
|
|
||||||
this.emitter.fireEvent(Homework1Event.SPAWN_FLEET, {position: Input.getGlobalMousePosition()});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Animations
|
|
||||||
if(!this.owner.animation.isPlaying("shield")){
|
|
||||||
if(this.speed > 0){
|
|
||||||
this.owner.animation.playIfNotAlready("boost");
|
|
||||||
} else {
|
|
||||||
this.owner.animation.playIfNotAlready("idle");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,6 +22,15 @@
|
||||||
left: 0px;
|
left: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#text-canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
#debug-canvas {
|
#debug-canvas {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -38,6 +47,8 @@
|
||||||
<div id="game-window">
|
<div id="game-window">
|
||||||
<!-- This is the canvas where the actual game is rendered -->
|
<!-- This is the canvas where the actual game is rendered -->
|
||||||
<canvas id="game-canvas"></canvas>
|
<canvas id="game-canvas"></canvas>
|
||||||
|
<!-- This is the canvas where text is rendered in WebGL -->
|
||||||
|
<canvas id="text-canvas" hidden></canvas>
|
||||||
<!-- This is the canvas where the debug text and graphics are rendered -->
|
<!-- This is the canvas where the debug text and graphics are rendered -->
|
||||||
<canvas id="debug-canvas"></canvas>
|
<canvas id="debug-canvas"></canvas>
|
||||||
</div>
|
</div>
|
||||||
|
|
38
src/main.ts
38
src/main.ts
|
@ -1,36 +1,24 @@
|
||||||
import Game from "./Wolfie2D/Loop/Game";
|
import Game from "./Wolfie2D/Loop/Game";
|
||||||
import Homework1_Scene from "./hw1/HW1_Scene";
|
import default_scene from "./default_scene";
|
||||||
import Registry from "./Wolfie2D/Registry/Registry";
|
|
||||||
import { Homework1Shaders } from "./hw1/HW1_Enums";
|
|
||||||
import GradientCircleShaderType from "./hw1/GradientCircleShaderType";
|
|
||||||
|
|
||||||
// The main function is your entrypoint into Wolfie2D. Specify your first scene and any options here.
|
// The main function is your entrypoint into Wolfie2D. Specify your first scene and any options here.
|
||||||
(function main(){
|
(function main(){
|
||||||
// Set up options
|
// Run any tests
|
||||||
let options = {
|
runTests();
|
||||||
canvasSize: {x: 1200, y: 800},
|
|
||||||
clearColor: {r: 0.1, g: 0.1, b: 0.1},
|
|
||||||
inputs: [
|
|
||||||
{ name: "forward", keys: ["w"] },
|
|
||||||
{ name: "backward", keys: ["s"] },
|
|
||||||
{ name: "turn_ccw", keys: ["a"] },
|
|
||||||
{ name: "turn_cw", keys: ["d"] },
|
|
||||||
],
|
|
||||||
useWebGL: true,
|
|
||||||
showDebug: false
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have a custom shader, so lets add it to the registry and preload it
|
// Set up options for our game
|
||||||
Registry.shaders.registerAndPreloadItem(
|
let options = {
|
||||||
Homework1Shaders.GRADIENT_CIRCLE, // The key of the shader program
|
canvasSize: {x: 1200, y: 800}, // The size of the game
|
||||||
GradientCircleShaderType, // The constructor of the shader program
|
clearColor: {r: 0.1, g: 0.1, b: 0.1}, // The color the game clears to
|
||||||
"hw1_assets/shaders/gradient_circle.vshader", // The path to the vertex shader
|
useWebGL: true, // Tell the game we want to use webgl
|
||||||
"hw1_assets/shaders/gradient_circle.fshader"); // the path to the fragment shader
|
showDebug: false // Whether to show debug messages. You can change this to true if you want
|
||||||
|
}
|
||||||
|
|
||||||
// Create a game with the options specified
|
// Create a game with the options specified
|
||||||
const game = new Game(options);
|
const game = new Game(options);
|
||||||
|
|
||||||
// Start our game
|
// Start our game
|
||||||
game.start();
|
game.start(default_scene, {});
|
||||||
game.getSceneManager().addScene(Homework1_Scene, {});
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
function runTests(){};
|
Loading…
Reference in New Issue
Block a user