diff --git a/src/DataTypes/Tilesets/Tileset.ts b/src/DataTypes/Tilesets/Tileset.ts index 4ab6dd3..14bd41c 100644 --- a/src/DataTypes/Tilesets/Tileset.ts +++ b/src/DataTypes/Tilesets/Tileset.ts @@ -102,8 +102,8 @@ export default class Tileset { let top = row * height; // Calculate the position in the world to render the tile - let x = (dataIndex % worldSize.x) * width * scale.x; - let y = Math.floor(dataIndex / worldSize.x) * height * scale.y; + let x = Math.floor((dataIndex % worldSize.x) * width * scale.x); + 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); } } \ No newline at end of file diff --git a/src/Events/GameEvent.ts b/src/Events/GameEvent.ts index 79959bd..4d2dd67 100644 --- a/src/Events/GameEvent.ts +++ b/src/Events/GameEvent.ts @@ -26,6 +26,10 @@ export default class GameEvent { this.time = Date.now(); } + isType(type: string): boolean { + return this.type === type; + } + toString(): string { return this.type + ": @" + this.time; } diff --git a/src/Input/InputReceiver.ts b/src/Input/InputReceiver.ts index eeac2f5..4dcbae8 100644 --- a/src/Input/InputReceiver.ts +++ b/src/Input/InputReceiver.ts @@ -68,7 +68,11 @@ export default class InputReceiver{ } 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)){ this.keyJustPressed.set(key, true); this.keyPressed.set(key, true); @@ -76,7 +80,11 @@ export default class InputReceiver{ } 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); } diff --git a/src/MainScene.ts b/src/MainScene.ts index d847c3e..15acf0c 100644 --- a/src/MainScene.ts +++ b/src/MainScene.ts @@ -61,6 +61,8 @@ export default class MainScene extends Scene { let player = this.add.physics(Player, mainLayer, "platformer"); let playerSprite = this.add.sprite("player", mainLayer) player.setSprite(playerSprite); + playerSprite.position = player.position.clone(); + playerSprite.setSize(new Vec2(64, 64)); this.viewport.follow(player); diff --git a/src/Physics/PhysicsManager.ts b/src/Physics/PhysicsManager.ts index 41a420b..3a80909 100644 --- a/src/Physics/PhysicsManager.ts +++ b/src/Physics/PhysicsManager.ts @@ -144,7 +144,17 @@ export default class PhysicsManager { // 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 if(yScale !== 1){ - node.setGrounded(true); + // If the collider is below us + if(collision.collider.getPosition().y > node.position.y){ + node.setGrounded(true); + } else { + console.log("On ceiling") + node.setOnCeiling(true); + } + } + + if(xScale !== 1){ + node.setOnWall(true); } // 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 // Maybe feed in a downward direction to check to be sure if(yScale !== 1){ - movingNode.setGrounded(true); + // If the collider is below us + if(staticNode.position.y > movingNode.position.y){ + movingNode.setGrounded(true); + } else { + movingNode.setOnCeiling(true); + } + } + + if(xScale !== 1){ + movingNode.setOnWall(true); } // 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(let movingNode of dynamicSet){ movingNode.setGrounded(false); + movingNode.setOnCeiling(false); + movingNode.setOnWall(false); // Get velocity of node let velocity = null; for(let data of this.movements){ diff --git a/src/Physics/PhysicsNode.ts b/src/Physics/PhysicsNode.ts index deb2e37..94fd456 100644 --- a/src/Physics/PhysicsNode.ts +++ b/src/Physics/PhysicsNode.ts @@ -14,11 +14,15 @@ export default abstract class PhysicsNode extends GameNode { private manager: PhysicsManager; protected moving: boolean; protected grounded: boolean; + protected onCeiling: boolean; + protected onWall: boolean; constructor(){ super(); this.children = new Array(); this.grounded = false; + this.onCeiling = false; + this.onWall = false; this.moving = false; } @@ -26,6 +30,26 @@ export default abstract class PhysicsNode extends GameNode { 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 { 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 * @param velocity */ - protected move(velocity: Vec2): void { + move(velocity: Vec2): void { this.moving = true; this.manager.addMovement(this, velocity); } diff --git a/src/SceneGraph/Viewport.ts b/src/SceneGraph/Viewport.ts index af9f43f..468dfbd 100644 --- a/src/SceneGraph/Viewport.ts +++ b/src/SceneGraph/Viewport.ts @@ -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.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); } else { 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.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); } } diff --git a/src/_DemoClasses/CustomGameEventType.ts b/src/_DemoClasses/CustomGameEventType.ts index f7bd102..d53efbb 100644 --- a/src/_DemoClasses/CustomGameEventType.ts +++ b/src/_DemoClasses/CustomGameEventType.ts @@ -1,3 +1,4 @@ export enum CustomGameEventType { PLAYER_MOVE = "player_move", + PLAYER_JUMP = "player_jump", } \ No newline at end of file diff --git a/src/_DemoClasses/Enemies/GoombaController.ts b/src/_DemoClasses/Enemies/GoombaController.ts new file mode 100644 index 0000000..6bc1fdb --- /dev/null +++ b/src/_DemoClasses/Enemies/GoombaController.ts @@ -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"); + } + } +} \ No newline at end of file diff --git a/src/_DemoClasses/Enemies/GoombaState.ts b/src/_DemoClasses/Enemies/GoombaState.ts new file mode 100644 index 0000000..876b760 --- /dev/null +++ b/src/_DemoClasses/Enemies/GoombaState.ts @@ -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; + } +} \ No newline at end of file diff --git a/src/_DemoClasses/Enemies/Idle.ts b/src/_DemoClasses/Enemies/Idle.ts new file mode 100644 index 0000000..6dc8923 --- /dev/null +++ b/src/_DemoClasses/Enemies/Idle.ts @@ -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)); + } +} \ No newline at end of file diff --git a/src/_DemoClasses/Enemies/Jump.ts b/src/_DemoClasses/Enemies/Jump.ts new file mode 100644 index 0000000..a6cf237 --- /dev/null +++ b/src/_DemoClasses/Enemies/Jump.ts @@ -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 {} +} \ No newline at end of file diff --git a/src/_DemoClasses/Enemies/OnGround.ts b/src/_DemoClasses/Enemies/OnGround.ts new file mode 100644 index 0000000..d8ec629 --- /dev/null +++ b/src/_DemoClasses/Enemies/OnGround.ts @@ -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 && (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 {} +} \ No newline at end of file diff --git a/src/_DemoClasses/Enemies/Walk.ts b/src/_DemoClasses/Enemies/Walk.ts new file mode 100644 index 0000000..ffcc4ce --- /dev/null +++ b/src/_DemoClasses/Enemies/Walk.ts @@ -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)); + } +} \ No newline at end of file diff --git a/src/_DemoClasses/MarioClone/Goomba.ts b/src/_DemoClasses/MarioClone/Goomba.ts new file mode 100644 index 0000000..6574bc2 --- /dev/null +++ b/src/_DemoClasses/MarioClone/Goomba.ts @@ -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); + } +} \ No newline at end of file diff --git a/src/_DemoClasses/MarioClone/MarioClone.ts b/src/_DemoClasses/MarioClone/MarioClone.ts new file mode 100644 index 0000000..9c8d725 --- /dev/null +++ b/src/_DemoClasses/MarioClone/MarioClone.ts @@ -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); + } + } + +} \ No newline at end of file diff --git a/src/_DemoClasses/MarioClone/Player.ts b/src/_DemoClasses/MarioClone/Player.ts new file mode 100644 index 0000000..7d09a93 --- /dev/null +++ b/src/_DemoClasses/MarioClone/Player.ts @@ -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()) + } +} \ No newline at end of file diff --git a/src/_DemoClasses/Player/PlayerStates/Platformer/Idle.ts b/src/_DemoClasses/Player/PlayerStates/Platformer/Idle.ts new file mode 100644 index 0000000..26f0b73 --- /dev/null +++ b/src/_DemoClasses/Player/PlayerStates/Platformer/Idle.ts @@ -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)); + } +} \ No newline at end of file diff --git a/src/_DemoClasses/Player/PlayerStates/Platformer/Jump.ts b/src/_DemoClasses/Player/PlayerStates/Platformer/Jump.ts new file mode 100644 index 0000000..b0ee81c --- /dev/null +++ b/src/_DemoClasses/Player/PlayerStates/Platformer/Jump.ts @@ -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 {} +} \ No newline at end of file diff --git a/src/_DemoClasses/Player/PlayerStates/Platformer/OnGround.ts b/src/_DemoClasses/Player/PlayerStates/Platformer/OnGround.ts new file mode 100644 index 0000000..2bbf4a5 --- /dev/null +++ b/src/_DemoClasses/Player/PlayerStates/Platformer/OnGround.ts @@ -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 {} +} \ No newline at end of file diff --git a/src/_DemoClasses/Player/PlayerStates/Platformer/PlayerController.ts b/src/_DemoClasses/Player/PlayerStates/Platformer/PlayerController.ts new file mode 100644 index 0000000..c75dbe2 --- /dev/null +++ b/src/_DemoClasses/Player/PlayerStates/Platformer/PlayerController.ts @@ -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"); + } + } +} \ No newline at end of file diff --git a/src/_DemoClasses/Player/PlayerStates/Platformer/PlayerState.ts b/src/_DemoClasses/Player/PlayerStates/Platformer/PlayerState.ts new file mode 100644 index 0000000..1ee2ae8 --- /dev/null +++ b/src/_DemoClasses/Player/PlayerStates/Platformer/PlayerState.ts @@ -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; + } +} \ No newline at end of file diff --git a/src/_DemoClasses/Player/PlayerStates/Platformer/Run.ts b/src/_DemoClasses/Player/PlayerStates/Platformer/Run.ts new file mode 100644 index 0000000..3e320a3 --- /dev/null +++ b/src/_DemoClasses/Player/PlayerStates/Platformer/Run.ts @@ -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)); + } +} \ No newline at end of file diff --git a/src/_DemoClasses/Player/PlayerStates/Platformer/Walk.ts b/src/_DemoClasses/Player/PlayerStates/Platformer/Walk.ts new file mode 100644 index 0000000..f69b33d --- /dev/null +++ b/src/_DemoClasses/Player/PlayerStates/Platformer/Walk.ts @@ -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)); + } +} \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 0b06493..8533bd5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,13 +3,14 @@ import {} from "./index"; import MainScene from "./MainScene" import QuadTreeScene from "./QuadTreeScene"; import BoidDemo from "./BoidDemo"; +import MarioClone from "./_DemoClasses/MarioClone/MarioClone"; function main(){ // Create the game object let game = new GameLoop({viewportSize: {x: 800, y: 600}}); game.start(); 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 {