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