added demo level and started work on physics layer support
This commit is contained in:
		
							parent
							
								
									ff5a2896fe
								
							
						
					
					
						commit
						9dc8cd29d1
					
				|  | @ -114,7 +114,7 @@ export interface Physical { | |||
|  */ | ||||
| export interface AI extends Updateable { | ||||
|     /** Initializes the AI with the actor and any additional config */ | ||||
|     initializeAI: (owner: GameNode, config: Record<string, any>) => void; | ||||
|     initializeAI: (owner: GameNode, options: Record<string, any>) => void; | ||||
| } | ||||
| 
 | ||||
| export interface Actor { | ||||
|  |  | |||
|  | @ -8,8 +8,11 @@ import Viewport from "../SceneGraph/Viewport"; | |||
| import SceneManager from "../Scene/SceneManager"; | ||||
| import AudioManager from "../Sound/AudioManager"; | ||||
| import Stats from "../Debug/Stats"; | ||||
| import ArrayUtils from "../Utils/ArrayUtils"; | ||||
| 
 | ||||
| export default class GameLoop { | ||||
|     gameOptions: GameOptions; | ||||
| 
 | ||||
| 	/** The max allowed update fps.*/ | ||||
|     private maxUpdateFPS: number; | ||||
|      | ||||
|  | @ -68,9 +71,9 @@ export default class GameLoop { | |||
|     private sceneManager: SceneManager; | ||||
|     private audioManager: AudioManager; | ||||
| 
 | ||||
|     constructor(config?: object){ | ||||
|     constructor(options?: Record<string, any>){ | ||||
|         // Typecast the config object to a GameConfig object
 | ||||
|         let gameConfig = config ? <GameConfig>config : new GameConfig(); | ||||
|         this.gameOptions = GameOptions.parse(options); | ||||
| 
 | ||||
|         this.maxUpdateFPS = 60; | ||||
|         this.simulationTimestep = Math.floor(1000/this.maxUpdateFPS); | ||||
|  | @ -95,8 +98,8 @@ export default class GameLoop { | |||
|         this.GAME_CANVAS.style.setProperty("background-color", "whitesmoke"); | ||||
|      | ||||
|         // Give the canvas a size and get the rendering context
 | ||||
|         this.WIDTH = gameConfig.canvasSize ? gameConfig.canvasSize.x : 800; | ||||
|         this.HEIGHT = gameConfig.canvasSize ? gameConfig.canvasSize.y : 500; | ||||
|         this.WIDTH = this.gameOptions.viewportSize.x; | ||||
|         this.HEIGHT = this.gameOptions.viewportSize.y; | ||||
|         this.ctx = this.initializeCanvas(this.GAME_CANVAS, this.WIDTH, this.HEIGHT); | ||||
| 
 | ||||
|         // Size the viewport to the game canvas
 | ||||
|  | @ -281,6 +284,31 @@ export default class GameLoop { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| class GameConfig { | ||||
|     canvasSize: {x: number, y: number} | ||||
| class GameOptions { | ||||
|     viewportSize: {x: number, y: number} | ||||
|     physics: { | ||||
|         numPhysicsLayers: number, | ||||
|         physicsLayerNames: Array<string>, | ||||
|         physicsLayerCollisions: Array<Array<number>>; | ||||
|     } | ||||
| 
 | ||||
|     static parse(options: Record<string, any>): GameOptions { | ||||
|         let gOpt = new GameOptions(); | ||||
| 
 | ||||
|         gOpt.viewportSize = options.viewportSize ? options.viewportSize : {x: 800, y: 600}; | ||||
| 
 | ||||
|         gOpt.physics = { | ||||
|             numPhysicsLayers: 10, | ||||
|             physicsLayerNames: null, | ||||
|             physicsLayerCollisions: ArrayUtils.ones2d(10, 10) | ||||
|         }; | ||||
| 
 | ||||
|         if(options.physics){ | ||||
|             if(options.physics.numPhysicsLayers)        gOpt.physics.numPhysicsLayers = options.physics.numPhysicsLayers; | ||||
|             if(options.physics.physicsLayerNames)       gOpt.physics.physicsLayerNames = options.physics.physicsLayerNames; | ||||
|             if(options.physics.physicsLayerCollisions)  gOpt.physics.physicsLayerCollisions = options.physics.physicsLayerCollisions; | ||||
|         } | ||||
| 
 | ||||
|         return gOpt; | ||||
|     } | ||||
| } | ||||
|  | @ -11,6 +11,8 @@ export default abstract class CanvasNode extends GameNode implements Region { | |||
| 	private _scale: Vec2; | ||||
| 	private _boundary: AABB; | ||||
| 
 | ||||
| 	visible = true; | ||||
| 
 | ||||
| 	constructor(){ | ||||
| 		super(); | ||||
| 		this.position.setOnChange(this.positionChanged); | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ import MathUtils from "../Utils/MathUtils"; | |||
| import OrthogonalTilemap from "../Nodes/Tilemaps/OrthogonalTilemap"; | ||||
| import Debug from "../Debug/Debug"; | ||||
| import AABB from "../DataTypes/Shapes/AABB"; | ||||
| import Map from "../DataTypes/Map"; | ||||
| 
 | ||||
| export default class BasicPhysicsManager extends PhysicsManager { | ||||
| 
 | ||||
|  | @ -25,12 +26,37 @@ export default class BasicPhysicsManager extends PhysicsManager { | |||
| 	/** The broad phase collision detection algorithm used by this physics system */ | ||||
| 	protected broadPhase: BroadPhase; | ||||
| 
 | ||||
| 	constructor(){ | ||||
| 	protected layerMap: Map<number>; | ||||
| 	protected layerNames: Array<string>; | ||||
| 
 | ||||
| 	constructor(physicsOptions: Record<string, any>){ | ||||
| 		super(); | ||||
| 		this.staticNodes = new Array(); | ||||
| 		this.dynamicNodes = new Array(); | ||||
| 		this.tilemaps = new Array(); | ||||
| 		this.broadPhase = new SweepAndPrune(); | ||||
| 		this.layerMap = new Map(); | ||||
| 		this.layerNames = new Array(); | ||||
| 
 | ||||
| 		let i = 0; | ||||
| 		if(physicsOptions.physicsLayerNames !== null){ | ||||
| 			for(let layer of physicsOptions.physicsLayerNames){ | ||||
| 				if(i >= physicsOptions.numPhysicsLayers){ | ||||
| 					// If we have too many string layers, don't add extras
 | ||||
| 				} | ||||
| 
 | ||||
| 				this.layerNames[i] = layer; | ||||
| 				this.layerMap.add(layer, i); | ||||
| 				i += 1; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		for(i; i < physicsOptions.numPhysicsLayers; i++){ | ||||
| 			this.layerNames[i] = "" + i; | ||||
| 			this.layerMap.add("" + i, i); | ||||
| 		} | ||||
| 
 | ||||
| 		console.log(this.layerNames); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
|  | @ -271,14 +297,15 @@ export default class BasicPhysicsManager extends PhysicsManager { | |||
| 		for(let pair of potentialCollidingPairs){ | ||||
| 			let node1 = pair[0]; | ||||
| 			let node2 = pair[1]; | ||||
| 			 | ||||
| 			// Make sure both nodes are active
 | ||||
| 			if(!node1.active || !node2.active){ | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| 			// Get Collision (which may or may not happen)
 | ||||
| 			let [firstContact, lastContact, collidingX, collidingY] = Shape.getTimeOfCollision(node1.collisionShape, node1._velocity, node2.collisionShape, node2._velocity); | ||||
| 
 | ||||
| 			if(collidingX && collidingY){ | ||||
| 				console.log("overlapping") | ||||
| 			} | ||||
| 
 | ||||
| 			if(node1.isPlayer){ | ||||
| 				if(firstContact.x !== Infinity || firstContact.y !== Infinity) | ||||
| 					Debug.log("playercol", "First Contact: " + firstContact.toFixed(4)) | ||||
|  |  | |||
|  | @ -21,6 +21,10 @@ export default class TilemapFactory { | |||
|         this.resourceManager = ResourceManager.getInstance(); | ||||
|     } | ||||
| 
 | ||||
|     // TODO - This is specifically catered to Tiled tilemaps right now. In the future,
 | ||||
|     // it would be good to have a "parseTilemap" function that would convert the tilemap
 | ||||
|     // data into a standard format. This could allow for support from other programs
 | ||||
|     // or the development of an internal level builder tool
 | ||||
|     /** | ||||
|      * Adds a tilemap to the scene | ||||
|      * @param key The key of the loaded tilemap to load | ||||
|  | @ -63,8 +67,24 @@ export default class TilemapFactory { | |||
| 
 | ||||
|         // Loop over the layers of the tilemap and create tiledlayers or object layers
 | ||||
|         for(let layer of tilemapData.layers){ | ||||
| 
 | ||||
|             let sceneLayer; | ||||
|             let isParallaxLayer = false; | ||||
|              | ||||
|             let sceneLayer = this.scene.addLayer(layer.name); | ||||
|             if(layer.properties){ | ||||
|                 for(let prop of layer.properties){ | ||||
|                     if(prop.name === "Parallax"){ | ||||
|                         isParallaxLayer = prop.value; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if(isParallaxLayer){ | ||||
|                 console.log("Adding parallax layer: " + layer.name) | ||||
|                 sceneLayer = this.scene.addParallaxLayer(layer.name, new Vec2(1, 1)); | ||||
|             } else { | ||||
|                 sceneLayer = this.scene.addLayer(layer.name); | ||||
|             } | ||||
|              | ||||
|             if(layer.type === "tilelayer"){ | ||||
|                 // Create a new tilemap object for the layer
 | ||||
|  |  | |||
|  | @ -90,7 +90,7 @@ export default class Scene implements Updateable, Renderable { | |||
|         this.uiLayers = new Map(); | ||||
|         this.parallaxLayers = new Map(); | ||||
| 
 | ||||
|         this.physicsManager = new BasicPhysicsManager(); | ||||
|         this.physicsManager = new BasicPhysicsManager(this.game.gameOptions.physics); | ||||
|         this.navManager = new NavigationManager(); | ||||
|         this.aiManager = new AIManager(); | ||||
| 
 | ||||
|  | @ -170,7 +170,7 @@ export default class Scene implements Updateable, Renderable { | |||
|         }); | ||||
| 
 | ||||
|         // Render visible set
 | ||||
|         visibleSet.forEach(node => node.render(ctx)); | ||||
|         visibleSet.forEach(node => node.visible ? node.render(ctx) : ""); | ||||
| 
 | ||||
|         // Debug render the physicsManager
 | ||||
|         this.physicsManager.debug_render(ctx); | ||||
|  |  | |||
							
								
								
									
										34
									
								
								src/Utils/ArrayUtils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/Utils/ArrayUtils.ts
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | |||
| export default class ArrayUtils { | ||||
|     /** | ||||
|      * Returns a 2d array of dim1 x dim2 filled with 1s | ||||
|      * @param dim1  | ||||
|      * @param dim2  | ||||
|      */ | ||||
|     static ones2d(dim1: number, dim2: number): number[][] { | ||||
|         let arr = new Array<Array<number>>(dim1); | ||||
| 
 | ||||
|         for(let i = 0; i < arr.length; i++){ | ||||
|             arr[i] = new Array<number>(dim2); | ||||
| 
 | ||||
|             for(let j = 0; j < arr[i].length; j++){ | ||||
|                 arr[i][j] = 1; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return arr; | ||||
|     } | ||||
| 
 | ||||
|     static bool2d(dim1: number, dim2: number, flag: boolean): boolean[][] { | ||||
|         let arr = new Array<Array<boolean>>(dim1); | ||||
| 
 | ||||
|         for(let i = 0; i < arr.length; i++){ | ||||
|             arr[i] = new Array<boolean>(dim2); | ||||
| 
 | ||||
|             for(let j = 0; j < arr[i].length; j++){ | ||||
|                 arr[i][j] = flag; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return arr; | ||||
|     } | ||||
| } | ||||
|  | @ -1,12 +1,12 @@ | |||
| import StateMachine from "../../DataTypes/State/StateMachine"; | ||||
| import { CustomGameEventType } from "../CustomGameEventType"; | ||||
| import Idle from "../Enemies/Idle"; | ||||
| import Jump from "../Enemies/Jump"; | ||||
| import Walk from "../Enemies/Walk"; | ||||
| import Afraid from "../Enemies/Afraid"; | ||||
| import Debug from "../../Debug/Debug"; | ||||
| import GameNode from "../../Nodes/GameNode"; | ||||
| import Vec2 from "../../DataTypes/Vec2"; | ||||
| import StateMachineAI from "../../AI/StateMachineAI"; | ||||
| import GoombaState from "./GoombaState"; | ||||
| 
 | ||||
| export enum GoombaStates { | ||||
| 	IDLE = "idle", | ||||
|  | @ -16,18 +16,16 @@ export enum GoombaStates { | |||
| 	AFRAID = "afraid" | ||||
| } | ||||
| 
 | ||||
| export default class GoombaController extends StateMachine { | ||||
| export default class GoombaController extends StateMachineAI { | ||||
| 	owner: GameNode; | ||||
| 	jumpy: boolean; | ||||
| 	direction: Vec2 = Vec2.ZERO; | ||||
| 	velocity: Vec2 = Vec2.ZERO; | ||||
| 	speed: number = 200; | ||||
| 
 | ||||
| 	constructor(owner: GameNode, jumpy: boolean){ | ||||
| 		super(); | ||||
| 
 | ||||
| 	initializeAI(owner: GameNode, options: Record<string, any>){ | ||||
| 		this.owner = owner; | ||||
| 		this.jumpy = jumpy; | ||||
| 		this.jumpy = options.jumpy ? options.jumpy : false; | ||||
| 
 | ||||
| 		this.receiver.subscribe(CustomGameEventType.PLAYER_MOVE); | ||||
| 		this.receiver.subscribe("playerHitCoinBlock"); | ||||
|  | @ -41,8 +39,8 @@ export default class GoombaController extends StateMachine { | |||
| 		this.addState(GoombaStates.WALK, walk); | ||||
| 		let jump = new Jump(this, owner); | ||||
| 		this.addState(GoombaStates.JUMP, jump); | ||||
| 		let afraid = new Afraid(this, owner); | ||||
| 		this.addState(GoombaStates.AFRAID, afraid); | ||||
| 
 | ||||
| 		this.initialize(GoombaStates.IDLE); | ||||
| 	} | ||||
| 
 | ||||
| 	changeState(stateName: string): void { | ||||
|  |  | |||
|  | @ -15,13 +15,7 @@ export default abstract class GoombaState extends State { | |||
| 		this.owner = owner; | ||||
| 	} | ||||
| 
 | ||||
| 	handleInput(event: GameEvent): void { | ||||
| 		if(event.type === "playerHitCoinBlock") { | ||||
| 			if(event.data.get("collision").firstContact.y < 1 && event.data.get("node").collisionShape.center.y > event.data.get("other").collisionShape.center.y){ | ||||
| 				this.finished(GoombaStates.AFRAID); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	handleInput(event: GameEvent): void {} | ||||
| 
 | ||||
| 	update(deltaT: number): void { | ||||
| 		// Do gravity
 | ||||
|  |  | |||
|  | @ -1,17 +1,11 @@ | |||
| import GameEvent from "../../Events/GameEvent"; | ||||
| import { CustomGameEventType } from "../CustomGameEventType"; | ||||
| import GoombaController, { GoombaStates } from "./GoombaController"; | ||||
| import { 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.parent).jumpy){ | ||||
| 			this.finished(GoombaStates.JUMP); | ||||
| 			this.parent.velocity.y = -2000; | ||||
| 		} | ||||
| 
 | ||||
| 		super.handleInput(event); | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,11 +1,16 @@ | |||
| import Vec2 from "../../DataTypes/Vec2"; | ||||
| import { GoombaStates } from "./GoombaController"; | ||||
| import OnGround from "./OnGround"; | ||||
| 
 | ||||
| export default class Walk extends OnGround { | ||||
| 	time: number; | ||||
| 	 | ||||
| 	onEnter(): void { | ||||
| 		if(this.parent.direction.isZero()){ | ||||
| 			this.parent.direction = new Vec2(-1, 0); | ||||
| 		} | ||||
| 
 | ||||
| 		this.time = Date.now(); | ||||
| 	} | ||||
| 
 | ||||
| 	update(deltaT: number): void { | ||||
|  | @ -16,6 +21,12 @@ export default class Walk extends OnGround { | |||
| 			this.parent.direction.x *= -1; | ||||
| 		} | ||||
| 
 | ||||
| 		if(this.parent.jumpy && (Date.now() - this.time > 500)){ | ||||
| 			console.log("Jump"); | ||||
| 			this.finished(GoombaStates.JUMP); | ||||
| 			this.parent.velocity.y = -2000; | ||||
| 		} | ||||
| 
 | ||||
| 		this.parent.velocity.x = this.parent.direction.x * this.parent.speed; | ||||
| 
 | ||||
| 		this.owner.move(this.parent.velocity.scaled(deltaT)); | ||||
|  |  | |||
							
								
								
									
										110
									
								
								src/_DemoClasses/Mario/Level1.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/_DemoClasses/Mario/Level1.ts
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,110 @@ | |||
| import Vec2 from "../../DataTypes/Vec2"; | ||||
| import GameNode from "../../Nodes/GameNode"; | ||||
| import { GraphicType } from "../../Nodes/Graphics/GraphicTypes"; | ||||
| import Label from "../../Nodes/UIElements/Label"; | ||||
| import { UIElementType } from "../../Nodes/UIElements/UIElementTypes"; | ||||
| import ParallaxLayer from "../../Scene/Layers/ParallaxLayer"; | ||||
| import Scene from "../../Scene/Scene"; | ||||
| import PlayerController from "../Player/PlayerController"; | ||||
| import GoombaController from "../Enemies/GoombaController"; | ||||
| 
 | ||||
| export enum MarioEvents { | ||||
|     PLAYER_HIT_COIN = "PlayerHitCoin", | ||||
|     PLAYER_HIT_COIN_BLOCK = "PlayerHitCoinBlock" | ||||
| } | ||||
| 
 | ||||
| export default class Level1 extends Scene { | ||||
|     player: GameNode; | ||||
|     coinCount: number = 0; | ||||
|     coinCountLabel: Label; | ||||
|     livesCount: number = 3; | ||||
|     livesCountLabel: Label; | ||||
| 
 | ||||
|     loadScene(): void { | ||||
|         this.load.tilemap("level1", "/assets/tilemaps/level1.json"); | ||||
|         this.load.image("goomba", "assets/sprites/Goomba.png"); | ||||
|         this.load.image("koopa", "assets/sprites/Koopa.png"); | ||||
|     } | ||||
| 
 | ||||
|     startScene(): void { | ||||
|         this.add.tilemap("level1", new Vec2(2, 2)); | ||||
|         this.viewport.setBounds(0, 0, 150*64, 20*64); | ||||
| 
 | ||||
|         // Give parallax to the parallax layers
 | ||||
|         (this.getLayer("Clouds") as ParallaxLayer).parallax.set(0.5, 1); | ||||
|         (this.getLayer("Hills") as ParallaxLayer).parallax.set(0.8, 1); | ||||
| 
 | ||||
|         // Add the player (a rect for now)
 | ||||
|         this.player = this.add.graphic(GraphicType.RECT, "Main", {position: new Vec2(192, 1152), size: new Vec2(64, 64)}); | ||||
|         this.player.addPhysics(); | ||||
|         this.player.addAI(PlayerController, {playerType: "platformer"}); | ||||
| 
 | ||||
|         // Add triggers on colliding with coins or coinBlocks
 | ||||
|         this.player.addTrigger("coin", MarioEvents.PLAYER_HIT_COIN); | ||||
|         this.player.addTrigger("coinBlock", MarioEvents.PLAYER_HIT_COIN_BLOCK); | ||||
| 
 | ||||
|         this.receiver.subscribe([MarioEvents.PLAYER_HIT_COIN, MarioEvents.PLAYER_HIT_COIN_BLOCK]); | ||||
| 
 | ||||
|         this.viewport.follow(this.player); | ||||
| 
 | ||||
|         // Add enemies
 | ||||
|         // Goombas
 | ||||
|         for(let pos of [{x: 21, y: 18}, {x: 30, y: 18}, {x: 37, y: 18}, {x: 41, y: 18}, {x: 105, y: 8}, {x: 107, y: 8}, {x: 125, y: 18}]){ | ||||
|             let goomba = this.add.sprite("goomba", "Main"); | ||||
|             goomba.position.set(pos.x*64, pos.y*64); | ||||
|             goomba.scale.set(2, 2); | ||||
|             goomba.addPhysics(); | ||||
|             goomba.addAI(GoombaController, {jumpy: false}); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         for(let pos of [{x: 67, y: 18}, {x: 86, y: 21}, {x: 128, y: 18}]){ | ||||
|             let koopa = this.add.sprite("koopa", "Main"); | ||||
|             koopa.position.set(pos.x*64, pos.y*64); | ||||
|             koopa.scale.set(2, 2); | ||||
|             koopa.addPhysics(); | ||||
|             koopa.addAI(GoombaController, {jumpy: true}); | ||||
|         } | ||||
| 
 | ||||
|         // Add UI
 | ||||
|         this.addUILayer("UI"); | ||||
| 
 | ||||
|         this.coinCountLabel = this.add.uiElement(UIElementType.LABEL, "UI", {position: new Vec2(80, 30), text: "Coins: 0"}); | ||||
|         this.livesCountLabel = this.add.uiElement(UIElementType.LABEL, "UI", {position: new Vec2(600, 30), text: "Lives: 3"}); | ||||
|     } | ||||
| 
 | ||||
|     updateScene(deltaT: number): void { | ||||
|         while(this.receiver.hasNextEvent()){ | ||||
|             let event = this.receiver.getNextEvent(); | ||||
|              | ||||
|             if(event.type === MarioEvents.PLAYER_HIT_COIN){ | ||||
|                 let coin; | ||||
|                 if(event.data.get("node") === this.player){ | ||||
|                     // Other is coin, disable
 | ||||
|                     coin = event.data.get("other");   | ||||
|                 } else { | ||||
|                     // Node is coin, disable
 | ||||
|                     coin = event.data.get("node"); | ||||
|                 } | ||||
| 
 | ||||
|                 // Remove from physics and scene
 | ||||
|                 coin.active = false; | ||||
|                 coin.visible = false; | ||||
|                 this.coinCount += 1; | ||||
| 
 | ||||
|                 this.coinCountLabel.setText("Coins: " + this.coinCount); | ||||
| 
 | ||||
|             } else if(event.type === MarioEvents.PLAYER_HIT_COIN_BLOCK){ | ||||
|                 console.log("Hit Coin Block") | ||||
|                 console.log(event.data.get("node") === this.player); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // If player falls into a pit, kill them off and reset their position
 | ||||
|         if(this.player.position.y > 21*64){ | ||||
|             this.player.position.set(192, 1152); | ||||
|             this.livesCount -= 1 | ||||
|             this.livesCountLabel.setText("Lives: " + this.livesCount); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -30,11 +30,11 @@ export default class PlayerController extends StateMachineAI { | |||
| 	MIN_SPEED: number = 400; | ||||
| 	MAX_SPEED: number = 1000; | ||||
| 
 | ||||
|     initializeAI(owner: GameNode, config: Record<string, any>){ | ||||
|     initializeAI(owner: GameNode, options: Record<string, any>){ | ||||
|         this.owner = owner; | ||||
| 
 | ||||
|         if(config.playerType === PlayerType.TOPDOWN){ | ||||
|             this.initializeTopDown(config.speed); | ||||
|         if(options.playerType === PlayerType.TOPDOWN){ | ||||
|             this.initializeTopDown(options.speed); | ||||
|         } else { | ||||
|             this.initializePlatformer(); | ||||
|         } | ||||
|  | @ -65,7 +65,9 @@ export default class PlayerController extends StateMachineAI { | |||
| 		let run = new Run(this, this.owner); | ||||
| 		this.addState(PlayerStates.RUN, run); | ||||
| 		let jump = new Jump(this, this.owner); | ||||
| 		this.addState(PlayerStates.JUMP, jump); | ||||
|         this.addState(PlayerStates.JUMP, jump); | ||||
|          | ||||
|         this.initialize(PlayerStates.IDLE); | ||||
|     } | ||||
| 
 | ||||
|     changeState(stateName: string): void { | ||||
|  |  | |||
							
								
								
									
										15
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/main.ts
									
									
									
									
									
								
							|  | @ -1,15 +1,20 @@ | |||
| import GameLoop from "./Loop/GameLoop"; | ||||
| import {} from "./index"; | ||||
| import BoidDemo from "./BoidDemo"; | ||||
| import MarioClone from "./_DemoClasses/MarioClone/MarioClone"; | ||||
| import PathfindingScene from "./_DemoClasses/Pathfinding/PathfindingScene"; | ||||
| import Level1 from "./_DemoClasses/Mario/Level1"; | ||||
| 
 | ||||
| function main(){ | ||||
|     // Create the game object
 | ||||
|     let game = new GameLoop({canvasSize: {x: 800, y: 600}}); | ||||
|     let options = { | ||||
|         viewportSize: {x: 800, y: 600}, | ||||
|         physics: { | ||||
|             physicsLayerNames: ["ground", "player", "enemy", "coin"] | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     let game = new GameLoop(options); | ||||
|     game.start(); | ||||
|     let sm = game.getSceneManager(); | ||||
|     sm.addScene(PathfindingScene); | ||||
|     sm.addScene(Level1); | ||||
| } | ||||
| 
 | ||||
| CanvasRenderingContext2D.prototype.roundedRect = function(x: number, y: number, w: number, h: number, r: number): void { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user