added state machine demo and added some features
This commit is contained in:
parent
25e0b8a39e
commit
7a0f9e5c95
|
@ -102,8 +102,8 @@ export default class Tileset {
|
||||||
let top = row * height;
|
let top = row * height;
|
||||||
|
|
||||||
// Calculate the position in the world to render the tile
|
// Calculate the position in the world to render the tile
|
||||||
let x = (dataIndex % worldSize.x) * width * scale.x;
|
let x = Math.floor((dataIndex % worldSize.x) * width * scale.x);
|
||||||
let y = Math.floor(dataIndex / worldSize.x) * height * scale.y;
|
let y = Math.floor(Math.floor(dataIndex / worldSize.x) * height * scale.y);
|
||||||
ctx.drawImage(image, left, top, width, height, x - origin.x, y - origin.y, width * scale.x, height * scale.y);
|
ctx.drawImage(image, left, top, width, height, x - origin.x, y - origin.y, width * scale.x, height * scale.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,6 +26,10 @@ export default class GameEvent {
|
||||||
this.time = Date.now();
|
this.time = Date.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isType(type: string): boolean {
|
||||||
|
return this.type === type;
|
||||||
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
return this.type + ": @" + this.time;
|
return this.type + ": @" + this.time;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,11 @@ export default class InputReceiver{
|
||||||
}
|
}
|
||||||
|
|
||||||
if(event.type === GameEventType.KEY_DOWN){
|
if(event.type === GameEventType.KEY_DOWN){
|
||||||
let key = event.data.get("key")
|
let key = event.data.get("key");
|
||||||
|
// Handle space bar
|
||||||
|
if(key === " "){
|
||||||
|
key = "space";
|
||||||
|
}
|
||||||
if(!this.keyPressed.get(key)){
|
if(!this.keyPressed.get(key)){
|
||||||
this.keyJustPressed.set(key, true);
|
this.keyJustPressed.set(key, true);
|
||||||
this.keyPressed.set(key, true);
|
this.keyPressed.set(key, true);
|
||||||
|
@ -76,7 +80,11 @@ export default class InputReceiver{
|
||||||
}
|
}
|
||||||
|
|
||||||
if(event.type === GameEventType.KEY_UP){
|
if(event.type === GameEventType.KEY_UP){
|
||||||
let key = event.data.get("key")
|
let key = event.data.get("key");
|
||||||
|
// Handle space bar
|
||||||
|
if(key === " "){
|
||||||
|
key = "space";
|
||||||
|
}
|
||||||
this.keyPressed.set(key, false);
|
this.keyPressed.set(key, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,8 @@ export default class MainScene extends Scene {
|
||||||
let player = this.add.physics(Player, mainLayer, "platformer");
|
let player = this.add.physics(Player, mainLayer, "platformer");
|
||||||
let playerSprite = this.add.sprite("player", mainLayer)
|
let playerSprite = this.add.sprite("player", mainLayer)
|
||||||
player.setSprite(playerSprite);
|
player.setSprite(playerSprite);
|
||||||
|
playerSprite.position = player.position.clone();
|
||||||
|
playerSprite.setSize(new Vec2(64, 64));
|
||||||
|
|
||||||
this.viewport.follow(player);
|
this.viewport.follow(player);
|
||||||
|
|
||||||
|
|
|
@ -144,7 +144,17 @@ export default class PhysicsManager {
|
||||||
// TODO - This is a bug, check to make sure our velocity is going downwards
|
// TODO - This is a bug, check to make sure our velocity is going downwards
|
||||||
// Maybe feed in a downward direction to check to be sure
|
// Maybe feed in a downward direction to check to be sure
|
||||||
if(yScale !== 1){
|
if(yScale !== 1){
|
||||||
|
// If the collider is below us
|
||||||
|
if(collision.collider.getPosition().y > node.position.y){
|
||||||
node.setGrounded(true);
|
node.setGrounded(true);
|
||||||
|
} else {
|
||||||
|
console.log("On ceiling")
|
||||||
|
node.setOnCeiling(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(xScale !== 1){
|
||||||
|
node.setOnWall(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale the velocity of the node
|
// Scale the velocity of the node
|
||||||
|
@ -175,7 +185,16 @@ export default class PhysicsManager {
|
||||||
// TODO - This is a bug, check to make sure our velocity is going downwards
|
// TODO - This is a bug, check to make sure our velocity is going downwards
|
||||||
// Maybe feed in a downward direction to check to be sure
|
// Maybe feed in a downward direction to check to be sure
|
||||||
if(yScale !== 1){
|
if(yScale !== 1){
|
||||||
|
// If the collider is below us
|
||||||
|
if(staticNode.position.y > movingNode.position.y){
|
||||||
movingNode.setGrounded(true);
|
movingNode.setGrounded(true);
|
||||||
|
} else {
|
||||||
|
movingNode.setOnCeiling(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(xScale !== 1){
|
||||||
|
movingNode.setOnWall(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale the velocity of the node
|
// Scale the velocity of the node
|
||||||
|
@ -207,6 +226,8 @@ export default class PhysicsManager {
|
||||||
// For now, we will only have the moving player, don't bother checking for collisions with other moving things
|
// For now, we will only have the moving player, don't bother checking for collisions with other moving things
|
||||||
for(let movingNode of dynamicSet){
|
for(let movingNode of dynamicSet){
|
||||||
movingNode.setGrounded(false);
|
movingNode.setGrounded(false);
|
||||||
|
movingNode.setOnCeiling(false);
|
||||||
|
movingNode.setOnWall(false);
|
||||||
// Get velocity of node
|
// Get velocity of node
|
||||||
let velocity = null;
|
let velocity = null;
|
||||||
for(let data of this.movements){
|
for(let data of this.movements){
|
||||||
|
|
|
@ -14,11 +14,15 @@ export default abstract class PhysicsNode extends GameNode {
|
||||||
private manager: PhysicsManager;
|
private manager: PhysicsManager;
|
||||||
protected moving: boolean;
|
protected moving: boolean;
|
||||||
protected grounded: boolean;
|
protected grounded: boolean;
|
||||||
|
protected onCeiling: boolean;
|
||||||
|
protected onWall: boolean;
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
super();
|
super();
|
||||||
this.children = new Array();
|
this.children = new Array();
|
||||||
this.grounded = false;
|
this.grounded = false;
|
||||||
|
this.onCeiling = false;
|
||||||
|
this.onWall = false;
|
||||||
this.moving = false;
|
this.moving = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +30,26 @@ export default abstract class PhysicsNode extends GameNode {
|
||||||
this.grounded = grounded;
|
this.grounded = grounded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isGrounded(): boolean {
|
||||||
|
return this.grounded;
|
||||||
|
}
|
||||||
|
|
||||||
|
setOnCeiling(onCeiling: boolean): void {
|
||||||
|
this.onCeiling = onCeiling;
|
||||||
|
}
|
||||||
|
|
||||||
|
isOnCeiling(): boolean {
|
||||||
|
return this.onCeiling;
|
||||||
|
}
|
||||||
|
|
||||||
|
setOnWall(onWall: boolean): void {
|
||||||
|
this.onWall = onWall;
|
||||||
|
}
|
||||||
|
|
||||||
|
isOnWall(): boolean {
|
||||||
|
return this.onWall;
|
||||||
|
}
|
||||||
|
|
||||||
addManager(manager: PhysicsManager): void {
|
addManager(manager: PhysicsManager): void {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +78,7 @@ export default abstract class PhysicsNode extends GameNode {
|
||||||
* Register a movement to the physics manager that can be handled at the end of the frame
|
* Register a movement to the physics manager that can be handled at the end of the frame
|
||||||
* @param velocity
|
* @param velocity
|
||||||
*/
|
*/
|
||||||
protected move(velocity: Vec2): void {
|
move(velocity: Vec2): void {
|
||||||
this.moving = true;
|
this.moving = true;
|
||||||
this.manager.addMovement(this, velocity);
|
this.manager.addMovement(this, velocity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,6 +158,12 @@ export default class Viewport {
|
||||||
pos.x = MathUtils.clamp(pos.x, this.boundary.left + this.view.hw, this.boundary.right - this.view.hw);
|
pos.x = MathUtils.clamp(pos.x, this.boundary.left + this.view.hw, this.boundary.right - this.view.hw);
|
||||||
pos.y = MathUtils.clamp(pos.y, this.boundary.top + this.view.hh, this.boundary.bottom - this.view.hh);
|
pos.y = MathUtils.clamp(pos.y, this.boundary.top + this.view.hh, this.boundary.bottom - this.view.hh);
|
||||||
|
|
||||||
|
// Assure there are no lines in the tilemap
|
||||||
|
pos.x = Math.floor(pos.x);
|
||||||
|
pos.y = Math.floor(pos.y);
|
||||||
|
|
||||||
|
Debug.log("vp", "Viewport pos: " + pos.toString())
|
||||||
|
|
||||||
this.view.setCenter(pos);
|
this.view.setCenter(pos);
|
||||||
} else {
|
} else {
|
||||||
if(this.lastPositions.getSize() > this.smoothingFactor){
|
if(this.lastPositions.getSize() > this.smoothingFactor){
|
||||||
|
@ -172,6 +178,11 @@ export default class Viewport {
|
||||||
pos.x = MathUtils.clamp(pos.x, this.boundary.left + this.view.hw, this.boundary.right - this.view.hw);
|
pos.x = MathUtils.clamp(pos.x, this.boundary.left + this.view.hw, this.boundary.right - this.view.hw);
|
||||||
pos.y = MathUtils.clamp(pos.y, this.boundary.top + this.view.hh, this.boundary.bottom - this.view.hh);
|
pos.y = MathUtils.clamp(pos.y, this.boundary.top + this.view.hh, this.boundary.bottom - this.view.hh);
|
||||||
|
|
||||||
|
// Assure there are no lines in the tilemap
|
||||||
|
pos.x = Math.floor(pos.x);
|
||||||
|
pos.y = Math.floor(pos.y);
|
||||||
|
|
||||||
|
Debug.log("vp", "Viewport pos: " + pos.toString())
|
||||||
this.view.setCenter(pos);
|
this.view.setCenter(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
export enum CustomGameEventType {
|
export enum CustomGameEventType {
|
||||||
PLAYER_MOVE = "player_move",
|
PLAYER_MOVE = "player_move",
|
||||||
|
PLAYER_JUMP = "player_jump",
|
||||||
}
|
}
|
58
src/_DemoClasses/Enemies/GoombaController.ts
Normal file
58
src/_DemoClasses/Enemies/GoombaController.ts
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import StateMachine from "../../DataTypes/State/StateMachine";
|
||||||
|
import { CustomGameEventType } from "../CustomGameEventType";
|
||||||
|
import Goomba from "../MarioClone/Goomba";
|
||||||
|
import Idle from "../Enemies/Idle";
|
||||||
|
import Jump from "../Enemies/Jump";
|
||||||
|
import Walk from "../Enemies/Walk";
|
||||||
|
import Debug from "../../Debug/Debug";
|
||||||
|
|
||||||
|
export enum GoombaStates {
|
||||||
|
IDLE = "idle",
|
||||||
|
WALK = "walk",
|
||||||
|
JUMP = "jump",
|
||||||
|
PREVIOUS = "previous"
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class GoombaController extends StateMachine {
|
||||||
|
owner: Goomba;
|
||||||
|
jumpy: boolean;
|
||||||
|
|
||||||
|
constructor(owner: Goomba, jumpy: boolean){
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.owner = owner;
|
||||||
|
this.jumpy = jumpy;
|
||||||
|
|
||||||
|
this.receiver.subscribe(CustomGameEventType.PLAYER_MOVE);
|
||||||
|
if(this.jumpy){
|
||||||
|
this.receiver.subscribe(CustomGameEventType.PLAYER_JUMP);
|
||||||
|
}
|
||||||
|
|
||||||
|
let idle = new Idle(this, owner);
|
||||||
|
this.addState(GoombaStates.IDLE, idle);
|
||||||
|
let walk = new Walk(this, owner);
|
||||||
|
this.addState(GoombaStates.WALK, walk);
|
||||||
|
let jump = new Jump(this, owner);
|
||||||
|
this.addState(GoombaStates.JUMP, jump);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeState(stateName: string): void {
|
||||||
|
|
||||||
|
if(stateName === GoombaStates.JUMP){
|
||||||
|
this.stack.push(this.stateMap.get(stateName));
|
||||||
|
}
|
||||||
|
super.changeState(stateName);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
super.update(deltaT);
|
||||||
|
|
||||||
|
if(this.currentState instanceof Jump){
|
||||||
|
Debug.log("goombastate", "GoombaState: Jump");
|
||||||
|
} else if (this.currentState instanceof Walk){
|
||||||
|
Debug.log("goombastate", "GoombaState: Walk");
|
||||||
|
} else {
|
||||||
|
Debug.log("goombastate", "GoombaState: Idle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
src/_DemoClasses/Enemies/GoombaState.ts
Normal file
19
src/_DemoClasses/Enemies/GoombaState.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import State from "../../DataTypes/State/State";
|
||||||
|
import StateMachine from "../../DataTypes/State/StateMachine";
|
||||||
|
import Goomba from "../MarioClone/Goomba";
|
||||||
|
|
||||||
|
export default abstract class GoombaState extends State {
|
||||||
|
owner: Goomba;
|
||||||
|
gravity: number = 7000;
|
||||||
|
|
||||||
|
constructor(parent: StateMachine, owner: Goomba){
|
||||||
|
super(parent);
|
||||||
|
|
||||||
|
this.owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
// Do gravity;
|
||||||
|
this.owner.velocity.y += this.gravity*deltaT;
|
||||||
|
}
|
||||||
|
}
|
29
src/_DemoClasses/Enemies/Idle.ts
Normal file
29
src/_DemoClasses/Enemies/Idle.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import Vec2 from "../../DataTypes/Vec2";
|
||||||
|
import GameEvent from "../../Events/GameEvent";
|
||||||
|
import { CustomGameEventType } from "../CustomGameEventType";
|
||||||
|
import { GoombaStates } from "./GoombaController";
|
||||||
|
import OnGround from "./OnGround";
|
||||||
|
|
||||||
|
export default class Idle extends OnGround {
|
||||||
|
onEnter(): void {
|
||||||
|
this.owner.speed = this.owner.speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleInput(event: GameEvent) {
|
||||||
|
if(event.type === CustomGameEventType.PLAYER_MOVE){
|
||||||
|
let pos = event.data.get("position");
|
||||||
|
if(this.owner.position.x - pos.x < (64*10)){
|
||||||
|
this.finished(GoombaStates.WALK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.handleInput(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
super.update(deltaT);
|
||||||
|
|
||||||
|
this.owner.velocity.x = 0;
|
||||||
|
|
||||||
|
this.owner.move(this.owner.velocity.scaled(deltaT));
|
||||||
|
}
|
||||||
|
}
|
28
src/_DemoClasses/Enemies/Jump.ts
Normal file
28
src/_DemoClasses/Enemies/Jump.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import GameEvent from "../../Events/GameEvent";
|
||||||
|
import { GoombaStates } from "./GoombaController";
|
||||||
|
import GoombaState from "./GoombaState";
|
||||||
|
|
||||||
|
export default class Jump extends GoombaState {
|
||||||
|
|
||||||
|
onEnter(): void {}
|
||||||
|
|
||||||
|
handleInput(event: GameEvent): void {}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
super.update(deltaT);
|
||||||
|
|
||||||
|
if(this.owner.isGrounded()){
|
||||||
|
this.finished(GoombaStates.PREVIOUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.owner.isOnCeiling()){
|
||||||
|
this.owner.velocity.y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.owner.velocity.x += this.owner.direction.x * this.owner.speed/3.5 - 0.3*this.owner.velocity.x;
|
||||||
|
|
||||||
|
this.owner.move(this.owner.velocity.scaled(deltaT));
|
||||||
|
}
|
||||||
|
|
||||||
|
onExit(): void {}
|
||||||
|
}
|
28
src/_DemoClasses/Enemies/OnGround.ts
Normal file
28
src/_DemoClasses/Enemies/OnGround.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import GameEvent from "../../Events/GameEvent";
|
||||||
|
import { CustomGameEventType } from "../CustomGameEventType";
|
||||||
|
import GoombaController, { GoombaStates } from "./GoombaController";
|
||||||
|
import GoombaState from "./GoombaState";
|
||||||
|
|
||||||
|
export default class OnGround extends GoombaState {
|
||||||
|
onEnter(): void {}
|
||||||
|
|
||||||
|
handleInput(event: GameEvent): void {
|
||||||
|
if(event.type === CustomGameEventType.PLAYER_JUMP && (<GoombaController>this.parentStateMachine).jumpy){
|
||||||
|
this.finished(GoombaStates.JUMP);
|
||||||
|
this.owner.velocity.y = -2000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
if(this.owner.velocity.y > 0){
|
||||||
|
this.owner.velocity.y = 0;
|
||||||
|
}
|
||||||
|
super.update(deltaT);
|
||||||
|
|
||||||
|
if(!this.owner.isGrounded()){
|
||||||
|
this.finished(GoombaStates.JUMP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onExit(): void {}
|
||||||
|
}
|
23
src/_DemoClasses/Enemies/Walk.ts
Normal file
23
src/_DemoClasses/Enemies/Walk.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import Vec2 from "../../DataTypes/Vec2";
|
||||||
|
import OnGround from "./OnGround";
|
||||||
|
|
||||||
|
export default class Walk extends OnGround {
|
||||||
|
onEnter(): void {
|
||||||
|
if(this.owner.direction.isZero()){
|
||||||
|
this.owner.direction = new Vec2(-1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
super.update(deltaT);
|
||||||
|
|
||||||
|
if(this.owner.isOnWall()){
|
||||||
|
// Flip around
|
||||||
|
this.owner.direction.x *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.owner.velocity.x = this.owner.direction.x * this.owner.speed;
|
||||||
|
|
||||||
|
this.owner.move(this.owner.velocity.scaled(deltaT));
|
||||||
|
}
|
||||||
|
}
|
30
src/_DemoClasses/MarioClone/Goomba.ts
Normal file
30
src/_DemoClasses/MarioClone/Goomba.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import AABB from "../../DataTypes/AABB";
|
||||||
|
import Vec2 from "../../DataTypes/Vec2";
|
||||||
|
import Sprite from "../../Nodes/Sprites/Sprite";
|
||||||
|
import Collider from "../../Physics/Colliders/Collider";
|
||||||
|
import PhysicsNode from "../../Physics/PhysicsNode";
|
||||||
|
import GoombaController, { GoombaStates } from "../Enemies/GoombaController";
|
||||||
|
|
||||||
|
export default class Goomba extends PhysicsNode {
|
||||||
|
controller: GoombaController;
|
||||||
|
velocity: Vec2 = Vec2.ZERO;
|
||||||
|
speed: number = 200;
|
||||||
|
direction: Vec2 = Vec2.ZERO;
|
||||||
|
|
||||||
|
constructor(position: Vec2, canJump: boolean){
|
||||||
|
super();
|
||||||
|
this.position.copy(position);
|
||||||
|
this.velocity = Vec2.ZERO;
|
||||||
|
this.controller = new GoombaController(this, canJump);
|
||||||
|
this.controller.initialize(GoombaStates.IDLE);
|
||||||
|
this.collider = new Collider(new AABB(position, new Vec2(32, 32)))
|
||||||
|
}
|
||||||
|
|
||||||
|
create(): void {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
this.controller.update(deltaT);
|
||||||
|
}
|
||||||
|
}
|
35
src/_DemoClasses/MarioClone/MarioClone.ts
Normal file
35
src/_DemoClasses/MarioClone/MarioClone.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import Scene from "../../Scene/Scene";
|
||||||
|
import Rect from "../../Nodes/Graphics/Rect";
|
||||||
|
import Vec2 from "../../DataTypes/Vec2";
|
||||||
|
import Player from "./Player";
|
||||||
|
import Color from "../../Utils/Color";
|
||||||
|
import Goomba from "./Goomba";
|
||||||
|
|
||||||
|
export default class MarioClone extends Scene {
|
||||||
|
|
||||||
|
loadScene(): void {
|
||||||
|
this.load.tilemap("level", "assets/tilemaps/MarioClone.json");
|
||||||
|
this.load.image("goomba", "assets/sprites/Goomba.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
startScene(): void {
|
||||||
|
let layer = this.addLayer();
|
||||||
|
this.add.tilemap("level", new Vec2(2, 2));
|
||||||
|
|
||||||
|
let player = this.add.physics(Player, layer, new Vec2(0, 0));
|
||||||
|
let playerSprite = this.add.graphic(Rect, layer, new Vec2(0, 0), new Vec2(64, 64));
|
||||||
|
playerSprite.setColor(Color.BLUE);
|
||||||
|
player.addChild(playerSprite);
|
||||||
|
this.viewport.follow(playerSprite);
|
||||||
|
this.viewport.setBounds(0, 0, 5120, 1280);
|
||||||
|
|
||||||
|
for(let xPos of [14, 20, 25, 30, 33, 37, 49, 55, 58, 70, 74]){
|
||||||
|
let goomba = this.add.physics(Goomba, layer, new Vec2(64*xPos, 0), true);
|
||||||
|
let goombaSprite = this.add.sprite("goomba", layer);
|
||||||
|
goombaSprite.setPosition(64*xPos, 0);
|
||||||
|
goombaSprite.setScale(new Vec2(2, 2));
|
||||||
|
goomba.addChild(goombaSprite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
33
src/_DemoClasses/MarioClone/Player.ts
Normal file
33
src/_DemoClasses/MarioClone/Player.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import AABB from "../../DataTypes/AABB";
|
||||||
|
import Vec2 from "../../DataTypes/Vec2";
|
||||||
|
import Debug from "../../Debug/Debug";
|
||||||
|
import Collider from "../../Physics/Colliders/Collider";
|
||||||
|
import PhysicsNode from "../../Physics/PhysicsNode";
|
||||||
|
import PlayerController from "../Player/PlayerStates/Platformer/PlayerController";
|
||||||
|
import { PlayerStates } from "../Player/PlayerStates/Platformer/PlayerController";
|
||||||
|
|
||||||
|
export default class Player extends PhysicsNode {
|
||||||
|
protected controller: PlayerController
|
||||||
|
velocity: Vec2;
|
||||||
|
speed: number = 400;
|
||||||
|
MIN_SPEED: number = 400;
|
||||||
|
MAX_SPEED: number = 1000;
|
||||||
|
|
||||||
|
constructor(position: Vec2){
|
||||||
|
super();
|
||||||
|
this.position.copy(position);
|
||||||
|
this.velocity = Vec2.ZERO;
|
||||||
|
this.controller = new PlayerController(this);
|
||||||
|
this.controller.initialize(PlayerStates.IDLE);
|
||||||
|
this.collider = new Collider(new AABB(Vec2.ZERO, new Vec2(32, 32)))
|
||||||
|
}
|
||||||
|
|
||||||
|
create(): void {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
this.controller.update(deltaT);
|
||||||
|
Debug.log("playerVel", "Pos: " + this.position.toString() + ", Vel: " + this.velocity.toString())
|
||||||
|
}
|
||||||
|
}
|
27
src/_DemoClasses/Player/PlayerStates/Platformer/Idle.ts
Normal file
27
src/_DemoClasses/Player/PlayerStates/Platformer/Idle.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import OnGround from "./OnGround";
|
||||||
|
import { PlayerStates } from "./PlayerController";
|
||||||
|
import PlayerState from "./PlayerState";
|
||||||
|
|
||||||
|
export default class Idle extends OnGround {
|
||||||
|
onEnter(): void {
|
||||||
|
this.owner.speed = this.owner.MIN_SPEED;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
super.update(deltaT);
|
||||||
|
|
||||||
|
let dir = this.getInputDirection();
|
||||||
|
|
||||||
|
if(!dir.isZero() && dir.y === 0){
|
||||||
|
if(this.input.isPressed("shift")){
|
||||||
|
this.finished(PlayerStates.RUN);
|
||||||
|
} else {
|
||||||
|
this.finished(PlayerStates.WALK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.owner.velocity.x = 0;
|
||||||
|
|
||||||
|
this.owner.move(this.owner.velocity.scaled(deltaT));
|
||||||
|
}
|
||||||
|
}
|
34
src/_DemoClasses/Player/PlayerStates/Platformer/Jump.ts
Normal file
34
src/_DemoClasses/Player/PlayerStates/Platformer/Jump.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import Vec2 from "../../../../DataTypes/Vec2";
|
||||||
|
import GameEvent from "../../../../Events/GameEvent";
|
||||||
|
import MathUtils from "../../../../Utils/MathUtils";
|
||||||
|
import { CustomGameEventType } from "../../../CustomGameEventType";
|
||||||
|
import { PlayerStates } from "./PlayerController";
|
||||||
|
import PlayerState from "./PlayerState";
|
||||||
|
|
||||||
|
export default class Jump extends PlayerState {
|
||||||
|
|
||||||
|
onEnter(): void {}
|
||||||
|
|
||||||
|
handleInput(event: GameEvent): void {}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
super.update(deltaT);
|
||||||
|
|
||||||
|
if(this.owner.isGrounded()){
|
||||||
|
this.finished(PlayerStates.PREVIOUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.owner.isOnCeiling()){
|
||||||
|
this.owner.velocity.y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let dir = this.getInputDirection();
|
||||||
|
|
||||||
|
this.owner.velocity.x += dir.x * this.owner.speed/3.5 - 0.3*this.owner.velocity.x;
|
||||||
|
|
||||||
|
this.emitter.fireEvent(CustomGameEventType.PLAYER_MOVE, {position: this.owner.position.clone()});
|
||||||
|
this.owner.move(this.owner.velocity.scaled(deltaT));
|
||||||
|
}
|
||||||
|
|
||||||
|
onExit(): void {}
|
||||||
|
}
|
26
src/_DemoClasses/Player/PlayerStates/Platformer/OnGround.ts
Normal file
26
src/_DemoClasses/Player/PlayerStates/Platformer/OnGround.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import GameEvent from "../../../../Events/GameEvent";
|
||||||
|
import { CustomGameEventType } from "../../../CustomGameEventType";
|
||||||
|
import PlayerState from "./PlayerState";
|
||||||
|
|
||||||
|
export default class OnGround extends PlayerState {
|
||||||
|
onEnter(): void {}
|
||||||
|
|
||||||
|
handleInput(event: GameEvent): void {}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
if(this.owner.velocity.y > 0){
|
||||||
|
this.owner.velocity.y = 0;
|
||||||
|
}
|
||||||
|
super.update(deltaT);
|
||||||
|
|
||||||
|
if(this.input.isJustPressed("w") || this.input.isJustPressed("space")){
|
||||||
|
this.finished("jump");
|
||||||
|
this.owner.velocity.y = -2000;
|
||||||
|
this.emitter.fireEvent(CustomGameEventType.PLAYER_JUMP)
|
||||||
|
} else if(!this.owner.isGrounded()){
|
||||||
|
this.finished("jump");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onExit(): void {}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
import StateMachine from "../../../../DataTypes/State/StateMachine";
|
||||||
|
import Debug from "../../../../Debug/Debug";
|
||||||
|
import Player from "../../../MarioClone/Player";
|
||||||
|
import Idle from "./Idle";
|
||||||
|
import Jump from "./Jump";
|
||||||
|
import Walk from "./Walk";
|
||||||
|
import Run from "./Run";
|
||||||
|
|
||||||
|
export enum PlayerStates {
|
||||||
|
WALK = "walk",
|
||||||
|
RUN = "run",
|
||||||
|
IDLE = "idle",
|
||||||
|
JUMP = "jump",
|
||||||
|
PREVIOUS = "previous"
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class PlayerController extends StateMachine {
|
||||||
|
protected owner: Player;
|
||||||
|
|
||||||
|
constructor(owner: Player){
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.owner = owner;
|
||||||
|
|
||||||
|
let idle = new Idle(this, owner);
|
||||||
|
this.addState(PlayerStates.IDLE, idle);
|
||||||
|
let walk = new Walk(this, owner);
|
||||||
|
this.addState(PlayerStates.WALK, walk);
|
||||||
|
let run = new Run(this, owner);
|
||||||
|
this.addState(PlayerStates.RUN, run);
|
||||||
|
let jump = new Jump(this, owner);
|
||||||
|
this.addState(PlayerStates.JUMP, jump);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentStateString: string = "";
|
||||||
|
|
||||||
|
changeState(stateName: string): void {
|
||||||
|
this.currentStateString = stateName;
|
||||||
|
|
||||||
|
if(stateName === PlayerStates.JUMP){
|
||||||
|
this.stack.push(this.stateMap.get(stateName));
|
||||||
|
}
|
||||||
|
super.changeState(stateName);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
super.update(deltaT);
|
||||||
|
|
||||||
|
if(this.currentState instanceof Jump){
|
||||||
|
Debug.log("playerstate", "Player State: Jump");
|
||||||
|
} else if (this.currentState instanceof Walk){
|
||||||
|
Debug.log("playerstate", "Player State: Walk");
|
||||||
|
} else if (this.currentState instanceof Run){
|
||||||
|
Debug.log("playerstate", "Player State: Run");
|
||||||
|
} else {
|
||||||
|
Debug.log("playerstate", "Player State: Idle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
import State from "../../../../DataTypes/State/State";
|
||||||
|
import StateMachine from "../../../../DataTypes/State/StateMachine";
|
||||||
|
import Vec2 from "../../../../DataTypes/Vec2";
|
||||||
|
import InputReceiver from "../../../../Input/InputReceiver";
|
||||||
|
import CanvasNode from "../../../../Nodes/CanvasNode";
|
||||||
|
import Player from "../../../MarioClone/Player";
|
||||||
|
|
||||||
|
export default abstract class PlayerState extends State {
|
||||||
|
input: InputReceiver = InputReceiver.getInstance();
|
||||||
|
owner: Player;
|
||||||
|
gravity: number = 7000;
|
||||||
|
|
||||||
|
constructor(parent: StateMachine, owner: Player){
|
||||||
|
super(parent);
|
||||||
|
this.owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInputDirection(): Vec2 {
|
||||||
|
let direction = Vec2.ZERO;
|
||||||
|
direction.x = (this.input.isPressed("a") ? -1 : 0) + (this.input.isPressed("d") ? 1 : 0);
|
||||||
|
direction.y = (this.input.isJustPressed("w") ? -1 : 0);
|
||||||
|
return direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLookDirection(direction: Vec2): void {
|
||||||
|
// Update the owners look direction
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
// Do gravity;
|
||||||
|
this.owner.velocity.y += this.gravity*deltaT;
|
||||||
|
}
|
||||||
|
}
|
28
src/_DemoClasses/Player/PlayerStates/Platformer/Run.ts
Normal file
28
src/_DemoClasses/Player/PlayerStates/Platformer/Run.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { CustomGameEventType } from "../../../CustomGameEventType";
|
||||||
|
import OnGround from "./OnGround";
|
||||||
|
import { PlayerStates } from "./PlayerController";
|
||||||
|
|
||||||
|
export default class Run extends OnGround {
|
||||||
|
onEnter(): void {
|
||||||
|
this.owner.speed = this.owner.MAX_SPEED;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
super.update(deltaT);
|
||||||
|
|
||||||
|
let dir = this.getInputDirection();
|
||||||
|
|
||||||
|
if(dir.isZero()){
|
||||||
|
this.finished(PlayerStates.IDLE);
|
||||||
|
} else {
|
||||||
|
if(!this.input.isPressed("shift")){
|
||||||
|
this.finished(PlayerStates.WALK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.owner.velocity.x = dir.x * this.owner.speed
|
||||||
|
|
||||||
|
this.emitter.fireEvent(CustomGameEventType.PLAYER_MOVE, {position: this.owner.position.clone()});
|
||||||
|
this.owner.move(this.owner.velocity.scaled(deltaT));
|
||||||
|
}
|
||||||
|
}
|
28
src/_DemoClasses/Player/PlayerStates/Platformer/Walk.ts
Normal file
28
src/_DemoClasses/Player/PlayerStates/Platformer/Walk.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { CustomGameEventType } from "../../../CustomGameEventType";
|
||||||
|
import OnGround from "./OnGround";
|
||||||
|
import { PlayerStates } from "./PlayerController";
|
||||||
|
|
||||||
|
export default class Walk extends OnGround {
|
||||||
|
onEnter(): void {
|
||||||
|
this.owner.speed = this.owner.MAX_SPEED/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
super.update(deltaT);
|
||||||
|
|
||||||
|
let dir = this.getInputDirection();
|
||||||
|
|
||||||
|
if(dir.isZero()){
|
||||||
|
this.finished(PlayerStates.IDLE);
|
||||||
|
} else {
|
||||||
|
if(this.input.isPressed("shift")){
|
||||||
|
this.finished(PlayerStates.RUN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.owner.velocity.x = dir.x * this.owner.speed
|
||||||
|
|
||||||
|
this.emitter.fireEvent(CustomGameEventType.PLAYER_MOVE, {position: this.owner.position.clone()});
|
||||||
|
this.owner.move(this.owner.velocity.scaled(deltaT));
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,13 +3,14 @@ import {} from "./index";
|
||||||
import MainScene from "./MainScene"
|
import MainScene from "./MainScene"
|
||||||
import QuadTreeScene from "./QuadTreeScene";
|
import QuadTreeScene from "./QuadTreeScene";
|
||||||
import BoidDemo from "./BoidDemo";
|
import BoidDemo from "./BoidDemo";
|
||||||
|
import MarioClone from "./_DemoClasses/MarioClone/MarioClone";
|
||||||
|
|
||||||
function main(){
|
function main(){
|
||||||
// Create the game object
|
// Create the game object
|
||||||
let game = new GameLoop({viewportSize: {x: 800, y: 600}});
|
let game = new GameLoop({viewportSize: {x: 800, y: 600}});
|
||||||
game.start();
|
game.start();
|
||||||
let sm = game.getSceneManager();
|
let sm = game.getSceneManager();
|
||||||
sm.addScene(BoidDemo);
|
sm.addScene(MarioClone);
|
||||||
}
|
}
|
||||||
|
|
||||||
CanvasRenderingContext2D.prototype.roundedRect = function(x: number, y: number, w: number, h: number, r: number): void {
|
CanvasRenderingContext2D.prototype.roundedRect = function(x: number, y: number, w: number, h: number, r: number): void {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user