fixed issues with tilemaps and physics
This commit is contained in:
		
							parent
							
								
									033680cf52
								
							
						
					
					
						commit
						bd961d04d3
					
				|  | @ -8,6 +8,12 @@ export class TiledTilemapData { | ||||||
|     tilesets: TiledTilesetData[]; |     tilesets: TiledTilesetData[]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export class TiledLayerProperty { | ||||||
|  |     name: string; | ||||||
|  |     type: string; | ||||||
|  |     value: any; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export class TiledTilesetData { | export class TiledTilesetData { | ||||||
|     columns: number; |     columns: number; | ||||||
|     tilewidth: number; |     tilewidth: number; | ||||||
|  | @ -31,5 +37,6 @@ export class TiledLayerData { | ||||||
|     name: string; |     name: string; | ||||||
|     opacity: number; |     opacity: number; | ||||||
|     visible: boolean; |     visible: boolean; | ||||||
|  |     properties: TiledLayerProperty[]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -27,6 +27,8 @@ export default class TilemapFactory { | ||||||
|                 // Add to scene
 |                 // Add to scene
 | ||||||
|                 this.scene.addTilemap(tilemap); |                 this.scene.addTilemap(tilemap); | ||||||
| 
 | 
 | ||||||
|  |                 if(tilemap.isCollidable()){ | ||||||
|  |                     // Create colliders
 | ||||||
|                     let worldSize = tilemap.getWorldSize(); |                     let worldSize = tilemap.getWorldSize(); | ||||||
|                     let tileSize = tilemap.getTileSize(); |                     let tileSize = tilemap.getTileSize(); | ||||||
| 
 | 
 | ||||||
|  | @ -37,6 +39,7 @@ export default class TilemapFactory { | ||||||
|                             this.scene.physics.add(StaticBody, new Vec2(x, y), new Vec2(tileSize.x * 4, tileSize.y * 4)); |                             this.scene.physics.add(StaticBody, new Vec2(x, y), new Vec2(tileSize.x * 4, tileSize.y * 4)); | ||||||
|                         } |                         } | ||||||
|                     }); |                     }); | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
|                 // Load images for the tilesets
 |                 // Load images for the tilesets
 | ||||||
|                 tilemap.getTilesets().forEach(tileset => { |                 tilemap.getTilesets().forEach(tileset => { | ||||||
|  |  | ||||||
|  | @ -13,7 +13,7 @@ export default class GameState{ | ||||||
|         this.worldSize = new Vec2(1600, 1000); |         this.worldSize = new Vec2(1600, 1000); | ||||||
|         this.viewport = new Viewport(); |         this.viewport = new Viewport(); | ||||||
|         this.viewport.setSize(800, 500); |         this.viewport.setSize(800, 500); | ||||||
|         this.viewport.setBounds(0, 0, 1600, 1000); |         this.viewport.setBounds(0, 0, 2560, 1280); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     createScene(): Scene{ |     createScene(): Scene{ | ||||||
|  |  | ||||||
|  | @ -102,15 +102,15 @@ export default class Scene { | ||||||
|             let origin = new Vec2(viewportOrigin.x*this.parallax.x, viewportOrigin.y*this.parallax.y); |             let origin = new Vec2(viewportOrigin.x*this.parallax.x, viewportOrigin.y*this.parallax.y); | ||||||
|             let size = this.viewport.getSize(); |             let size = this.viewport.getSize(); | ||||||
| 
 | 
 | ||||||
|             // Render visible set
 |  | ||||||
|             visibleSet.forEach(node => node.render(ctx, origin)); |  | ||||||
| 
 |  | ||||||
|             // Render tilemaps
 |             // Render tilemaps
 | ||||||
|             this.tilemaps.forEach(tilemap => { |             this.tilemaps.forEach(tilemap => { | ||||||
|                 if(tilemap.isReady()){ |                 if(tilemap.isReady() && tilemap.isVisible()){ | ||||||
|                     tilemap.render(ctx, origin, size); |                     tilemap.render(ctx, origin, size); | ||||||
|                 } |                 } | ||||||
|             }); |             }); | ||||||
|  | 
 | ||||||
|  |             // Render visible set
 | ||||||
|  |             visibleSet.forEach(node => node.render(ctx, origin)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -58,9 +58,11 @@ export default class InputReceiver{ | ||||||
| 
 | 
 | ||||||
| 			if(event.type === "key_down"){ | 			if(event.type === "key_down"){ | ||||||
| 				let key = event.data.get("key") | 				let key = event.data.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); | ||||||
| 				} | 				} | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			if(event.type === "key_up"){ | 			if(event.type === "key_up"){ | ||||||
| 				let key = event.data.get("key") | 				let key = event.data.get("key") | ||||||
|  |  | ||||||
|  | @ -11,6 +11,8 @@ export default abstract class Tilemap extends GameNode { | ||||||
|     protected tilesets: Tileset[]; |     protected tilesets: Tileset[]; | ||||||
|     protected worldSize: Vec2; |     protected worldSize: Vec2; | ||||||
|     protected tileSize: Vec2; |     protected tileSize: Vec2; | ||||||
|  |     protected visible: boolean; | ||||||
|  |     protected collidable: boolean; | ||||||
| 
 | 
 | ||||||
|     constructor(tilemapData: TiledTilemapData, layerData: TiledLayerData){ |     constructor(tilemapData: TiledTilemapData, layerData: TiledLayerData){ | ||||||
|         super(); |         super(); | ||||||
|  | @ -20,6 +22,14 @@ export default abstract class Tilemap extends GameNode { | ||||||
|         this.parseTilemapData(tilemapData, layerData); |         this.parseTilemapData(tilemapData, layerData); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     isCollidable(): boolean { | ||||||
|  |         return this.collidable; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     isVisible(): boolean { | ||||||
|  |         return this.visible; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     getTilesets(): Tileset[] { |     getTilesets(): Tileset[] { | ||||||
|         return this.tilesets; |         return this.tilesets; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -5,10 +5,18 @@ import Tileset from "../../DataTypes/Tilesets/Tileset"; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| export default class OrthogonalTilemap extends Tilemap { | export default class OrthogonalTilemap extends Tilemap { | ||||||
|  | 
 | ||||||
|     parseTilemapData(tilemapData: TiledTilemapData, layer: TiledLayerData): void { |     parseTilemapData(tilemapData: TiledTilemapData, layer: TiledLayerData): void { | ||||||
|         this.worldSize.set(tilemapData.width, tilemapData.height); |         this.worldSize.set(tilemapData.width, tilemapData.height); | ||||||
|         this.tileSize.set(tilemapData.tilewidth, tilemapData.tileheight); |         this.tileSize.set(tilemapData.tilewidth, tilemapData.tileheight); | ||||||
|         this.data = layer.data; |         this.data = layer.data; | ||||||
|  |         this.visible = layer.visible; | ||||||
|  |         this.collidable = false; | ||||||
|  |         for(let item of layer.properties){ | ||||||
|  |             if(item.name === "Collidable"){ | ||||||
|  |                 this.collidable = item.value; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|         tilemapData.tilesets.forEach(tilesetData => this.tilesets.push(new Tileset(tilesetData))); |         tilemapData.tilesets.forEach(tilesetData => this.tilesets.push(new Tileset(tilesetData))); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -20,6 +28,7 @@ export default class OrthogonalTilemap extends Tilemap { | ||||||
| 
 | 
 | ||||||
|     update(deltaT: number): void {} |     update(deltaT: number): void {} | ||||||
| 
 | 
 | ||||||
|  |     // TODO: Don't render tiles that aren't on screen
 | ||||||
|     render(ctx: CanvasRenderingContext2D, origin: Vec2, viewportSize: Vec2) { |     render(ctx: CanvasRenderingContext2D, origin: Vec2, viewportSize: Vec2) { | ||||||
|         for(let i = 0; i < this.data.length; i++){ |         for(let i = 0; i < this.data.length; i++){ | ||||||
|             let tileIndex = this.data[i]; |             let tileIndex = this.data[i]; | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ import PhysicsNode from "./PhysicsNode"; | ||||||
| import Vec2 from "../DataTypes/Vec2"; | import Vec2 from "../DataTypes/Vec2"; | ||||||
| import StaticBody from "./StaticBody"; | import StaticBody from "./StaticBody"; | ||||||
| import Debug from "../Debug/Debug"; | import Debug from "../Debug/Debug"; | ||||||
|  | import MathUtils from "../Utils/MathUtils"; | ||||||
| 
 | 
 | ||||||
| export default class PhysicsManager { | export default class PhysicsManager { | ||||||
| 
 | 
 | ||||||
|  | @ -41,6 +42,7 @@ 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.setIsGrounded(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){ | ||||||
|  | @ -141,12 +143,34 @@ export default class PhysicsManager { | ||||||
|             collidingY = true; |             collidingY = true; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         if(B.x < A.x){ | ||||||
|  |             // Swap, because B is to the left of A
 | ||||||
|  |             let temp: Vec2; | ||||||
|  |             temp = sizeA; | ||||||
|  |             sizeA = sizeB; | ||||||
|  |             sizeB = temp; | ||||||
|  | 
 | ||||||
|  |             temp = A; | ||||||
|  |             A = B; | ||||||
|  |             B = temp; | ||||||
|  | 
 | ||||||
|  |             temp = velA; | ||||||
|  |             velA = velB; | ||||||
|  |             velB = temp; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         if( (firstContact.x < 1 || collidingX) && (firstContact.y < 1 || collidingY)){ |         if( (firstContact.x < 1 || collidingX) && (firstContact.y < 1 || collidingY)){ | ||||||
|             if(collidingX && collidingY){ |             if(collidingX && collidingY){ | ||||||
|                 // If we're already intersecting, freak out I guess?
 |                 // If we're already intersecting, freak out I guess?
 | ||||||
|             } else { |             } else { | ||||||
|                 let contactTime = Math.min(firstContact.x, firstContact.y); |                 // let contactTime = Math.min(firstContact.x, firstContact.y);
 | ||||||
|                 velocity.scale(contactTime); |                 // velocity.scale(contactTime);
 | ||||||
|  |                 let xScale = MathUtils.clamp(firstContact.x, 0, 1); | ||||||
|  |                 let yScale = MathUtils.clamp(firstContact.y, 0, 1); | ||||||
|  |                 if(yScale !== 1){ | ||||||
|  |                     movingNode.setIsGrounded(true); | ||||||
|  |                 }  | ||||||
|  |                 velocity.scale(xScale, yScale); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ export default abstract class PhysicsNode extends GameNode { | ||||||
|     protected children: Array<GameNode>; |     protected children: Array<GameNode>; | ||||||
|     private manager: PhysicsManager; |     private manager: PhysicsManager; | ||||||
|     isMoving: boolean; |     isMoving: boolean; | ||||||
|  |     protected isGrounded: boolean; | ||||||
| 
 | 
 | ||||||
|     constructor(){ |     constructor(){ | ||||||
|         super(); |         super(); | ||||||
|  | @ -16,6 +17,10 @@ export default abstract class PhysicsNode extends GameNode { | ||||||
|         this.isMoving = false; |         this.isMoving = false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     setIsGrounded(isGrounded: boolean): void { | ||||||
|  |         this.isGrounded = isGrounded; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     addManager(manager: PhysicsManager): void { |     addManager(manager: PhysicsManager): void { | ||||||
|         this.manager = manager; |         this.manager = manager; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -9,15 +9,21 @@ export default class Player extends PhysicsNode { | ||||||
| 	speed: number; | 	speed: number; | ||||||
|     debug: Debug; |     debug: Debug; | ||||||
|     size: Vec2; |     size: Vec2; | ||||||
|  |     gravity: number = 7000; | ||||||
|  |     type: string; | ||||||
| 
 | 
 | ||||||
|     constructor(){ |     constructor(type: string){ | ||||||
|         super(); |         super(); | ||||||
|  |         this.type = type; | ||||||
|         this.velocity = new Vec2(0, 0); |         this.velocity = new Vec2(0, 0); | ||||||
|         this.speed = 300; |         this.speed = 500; | ||||||
|         this.size = new Vec2(50, 50); |         this.size = new Vec2(50, 50); | ||||||
|         this.collider = new AABB(); |         this.collider = new AABB(); | ||||||
|         this.collider.setSize(this.size); |         this.collider.setSize(this.size); | ||||||
|         this.position = new Vec2(0, 0); |         this.position = new Vec2(0, 0); | ||||||
|  |         if(this.type === "topdown"){ | ||||||
|  |             this.position = new Vec2(100, 100); | ||||||
|  |         } | ||||||
| 		this.debug = Debug.getInstance(); | 		this.debug = Debug.getInstance(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -29,18 +35,60 @@ export default class Player extends PhysicsNode { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     update(deltaT: number): void { |     update(deltaT: number): void { | ||||||
|  |         if(this.type === "topdown"){ | ||||||
|  |             let dir = this.topdown_computeDirection(); | ||||||
|  |             this.velocity = this.topdown_computeVelocity(dir, deltaT); | ||||||
|  |         } else { | ||||||
|  |             let dir = this.platformer_computeDirection(); | ||||||
|  |             this.velocity = this.platformer_computeVelocity(dir, deltaT); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 		this.move(new Vec2(this.velocity.x * deltaT, this.velocity.y * deltaT)); | ||||||
|  | 
 | ||||||
|  | 		this.debug.log("player", "Player Pos: " + this.position.toFixed() + ", Player Vel: " + this.velocity.toFixed()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     topdown_computeDirection(): Vec2 { | ||||||
|         let dir = new Vec2(0, 0); |         let dir = new Vec2(0, 0); | ||||||
| 		dir.x += this.input.isPressed('a') ? -1 : 0; | 		dir.x += this.input.isPressed('a') ? -1 : 0; | ||||||
|         dir.x += this.input.isPressed('d') ? 1 : 0; |         dir.x += this.input.isPressed('d') ? 1 : 0; | ||||||
| 		dir.y += this.input.isPressed('s') ? 1 : 0; |  | ||||||
|         dir.y += this.input.isPressed('w') ? -1 : 0; |         dir.y += this.input.isPressed('w') ? -1 : 0; | ||||||
|  |         dir.y += this.input.isPressed('s') ? 1 : 0; | ||||||
| 
 | 
 | ||||||
|         dir.normalize();         |         dir.normalize();         | ||||||
| 
 | 
 | ||||||
|         this.velocity = dir.scale(this.speed); |         return dir; | ||||||
| 		this.move(this.velocity.scale(deltaT)); |     } | ||||||
| 
 | 
 | ||||||
| 		this.debug.log("player", "Player Pos: " + this.position.toFixed() + " " + this.velocity.toFixed()); |     topdown_computeVelocity(dir: Vec2, deltaT: number): Vec2 { | ||||||
|  |         let vel = new Vec2(dir.x * this.speed, dir.y * this.speed); | ||||||
|  |         return vel | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     platformer_computeDirection(): Vec2 { | ||||||
|  |         let dir = new Vec2(0, 0); | ||||||
|  | 		dir.x += this.input.isPressed('a') ? -1 : 0; | ||||||
|  |         dir.x += this.input.isPressed('d') ? 1 : 0; | ||||||
|  |          | ||||||
|  |         if(this.isGrounded){ | ||||||
|  |             dir.y += this.input.isJustPressed('w') ? -1 : 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return dir; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     platformer_computeVelocity(dir: Vec2, deltaT: number): Vec2 { | ||||||
|  |         let vel = new Vec2(0, this.velocity.y); | ||||||
|  | 
 | ||||||
|  |         if(this.isGrounded){ | ||||||
|  |             vel.y = dir.y*1800; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         vel.y += this.gravity * deltaT; | ||||||
|  | 
 | ||||||
|  |         vel.x = dir.x * this.speed; | ||||||
|  | 
 | ||||||
|  |         return vel | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
							
								
								
									
										14
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								src/main.ts
									
									
									
									
									
								
							|  | @ -15,17 +15,12 @@ function main(){ | ||||||
|     let backgroundScene = gameState.createScene(); |     let backgroundScene = gameState.createScene(); | ||||||
|     backgroundScene.setParallax(0.5, 0.5); |     backgroundScene.setParallax(0.5, 0.5); | ||||||
|     let mainScene = gameState.createScene(); |     let mainScene = gameState.createScene(); | ||||||
|     let foregroundLayer = gameState.createScene(); |  | ||||||
|     foregroundLayer.setParallax(1.5, 1.5); |  | ||||||
|     let uiLayer = gameState.createScene(); |     let uiLayer = gameState.createScene(); | ||||||
|     uiLayer.setParallax(0, 0); |     uiLayer.setParallax(0, 0); | ||||||
|     let pauseMenu = gameState.createScene(); |     let pauseMenu = gameState.createScene(); | ||||||
|     pauseMenu.setParallax(0, 0); |     pauseMenu.setParallax(0, 0); | ||||||
| 
 | 
 | ||||||
|     // Initialize GameObjects
 |     // Initialize GameObjects
 | ||||||
|     let player = mainScene.physics.add(Player); |  | ||||||
|     mainScene.getViewport().follow(player); |  | ||||||
| 
 |  | ||||||
|     let recordButton = uiLayer.canvasNode.add(Button); |     let recordButton = uiLayer.canvasNode.add(Button); | ||||||
|     recordButton.setSize(100, 50); |     recordButton.setSize(100, 50); | ||||||
|     recordButton.setText("Record"); |     recordButton.setText("Record"); | ||||||
|  | @ -79,13 +74,8 @@ function main(){ | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     mainScene.tilemap.add(OrthogonalTilemap, "assets/tilemaps/Platformer.json"); |     mainScene.tilemap.add(OrthogonalTilemap, "assets/tilemaps/Platformer.json"); | ||||||
| 
 |     let player = mainScene.physics.add(Player, "platformer"); | ||||||
|     for(let i = 0; i < 30; i++){ |     mainScene.getViewport().follow(player); | ||||||
|         let cc = foregroundLayer.canvasNode.add(ColoredCircle); |  | ||||||
|         cc.setSize(80, 80); |  | ||||||
|         cc.setColor(cc.getColor().lighten().lighten()) |  | ||||||
|         cc.getColor().a = 0.5; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     pauseMenu.disable(); |     pauseMenu.disable(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user