fixed some bugs and added destroy() methods
This commit is contained in:
		
							parent
							
								
									c241aa99bc
								
							
						
					
					
						commit
						460d0e3643
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -11,7 +11,7 @@ dist/*
 | 
				
			||||||
!dist/builtin/
 | 
					!dist/builtin/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Include the hw1 assets
 | 
					# Include the hw1 assets
 | 
				
			||||||
!dist/hw1_assets/
 | 
					!dist/hw4_assets/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### IF YOU ARE MAKING A PROJECT, YOU MAY WANT TO UNCOMMENT THIS LINE ###
 | 
					### IF YOU ARE MAKING A PROJECT, YOU MAY WANT TO UNCOMMENT THIS LINE ###
 | 
				
			||||||
# !dist/assets/
 | 
					# !dist/assets/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								dist/hw4_assets/fonts/NoPixel.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dist/hw4_assets/fonts/NoPixel.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								dist/hw4_assets/sounds/jump-3.wav
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dist/hw4_assets/sounds/jump-3.wav
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								dist/hw4_assets/sprites/2bitbackground.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dist/hw4_assets/sprites/2bitbackground.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 4.7 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/hw4_assets/sprites/coin.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dist/hw4_assets/sprites/coin.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 190 B  | 
							
								
								
									
										22
									
								
								dist/hw4_assets/spritesheets/ghostBunny.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								dist/hw4_assets/spritesheets/ghostBunny.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    "name": "GhostBunny",
 | 
				
			||||||
 | 
					    "spriteSheetImage": "ghostBunny.png",
 | 
				
			||||||
 | 
					    "spriteWidth": 16,
 | 
				
			||||||
 | 
					    "spriteHeight": 16,
 | 
				
			||||||
 | 
					    "columns": 5,
 | 
				
			||||||
 | 
					    "rows": 1,
 | 
				
			||||||
 | 
					    "animations": [
 | 
				
			||||||
 | 
					        { 
 | 
				
			||||||
 | 
					            "name": "IDLE",
 | 
				
			||||||
 | 
					            "frames": [ {"index": 0, "duration": 1} ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "WALK",
 | 
				
			||||||
 | 
					            "frames": [ {"index": 0, "duration": 16}, {"index": 1, "duration": 16}]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "DYING",
 | 
				
			||||||
 | 
					            "frames": [ {"index": 2, "duration": 8}, {"index": 3, "duration": 8}, {"index": 4, "duration": 8}]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								dist/hw4_assets/spritesheets/ghostBunny.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dist/hw4_assets/spritesheets/ghostBunny.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 367 B  | 
							
								
								
									
										26
									
								
								dist/hw4_assets/spritesheets/hopper.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								dist/hw4_assets/spritesheets/hopper.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    "name": "Hopper",
 | 
				
			||||||
 | 
					    "spriteSheetImage": "hopper.png",
 | 
				
			||||||
 | 
					    "spriteWidth": 16,
 | 
				
			||||||
 | 
					    "spriteHeight": 16,
 | 
				
			||||||
 | 
					    "columns": 15,
 | 
				
			||||||
 | 
					    "rows": 1,
 | 
				
			||||||
 | 
					    "animations": [
 | 
				
			||||||
 | 
					        { 
 | 
				
			||||||
 | 
					            "name": "IDLE",
 | 
				
			||||||
 | 
					            "frames": [ {"index": 0, "duration": 1} ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "WALK",
 | 
				
			||||||
 | 
					            "frames": [ {"index": 0, "duration": 16}, {"index": 1, "duration": 16}, {"index": 2, "duration": 16}, {"index": 3, "duration": 16}, {"index": 4, "duration": 16}, {"index": 5, "duration": 16}, {"index": 6, "duration": 16}, {"index": 7, "duration": 16} ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "JUMP",
 | 
				
			||||||
 | 
					            "frames":[ {"index": 8, "duration": 8}, {"index": 9, "duration": 8}, {"index": 10, "duration": 8}, {"index": 11, "duration": 8}]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "DYING",
 | 
				
			||||||
 | 
					            "frames":[ {"index": 12, "duration": 8}, {"index": 13, "duration": 8}, {"index": 14, "duration": 8} ]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								dist/hw4_assets/spritesheets/hopper.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dist/hw4_assets/spritesheets/hopper.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 641 B  | 
							
								
								
									
										27
									
								
								dist/hw4_assets/spritesheets/platformPlayer.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								dist/hw4_assets/spritesheets/platformPlayer.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,27 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    "name": "PlatformPlayer",
 | 
				
			||||||
 | 
					    "spriteSheetImage": "platformPlayer.png",
 | 
				
			||||||
 | 
					    "spriteWidth": 16,
 | 
				
			||||||
 | 
					    "spriteHeight": 16,
 | 
				
			||||||
 | 
					    "columns": 7,
 | 
				
			||||||
 | 
					    "rows": 1,
 | 
				
			||||||
 | 
					    "durationType": "time",
 | 
				
			||||||
 | 
					    "animations": [
 | 
				
			||||||
 | 
					        { 
 | 
				
			||||||
 | 
					            "name": "IDLE",
 | 
				
			||||||
 | 
					            "frames": [ {"index": 0, "duration": 540}, {"index": 1, "duration": 16}, {"index": 2, "duration": 16}, {"index": 3, "duration": 16}, {"index": 0, "duration": 360}, {"index": 1, "duration": 16}, {"index": 2, "duration": 16}, {"index": 3, "duration": 16}]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "WALK",
 | 
				
			||||||
 | 
					            "frames": [ {"index": 0, "duration": 16}, {"index": 4, "duration": 16}, {"index": 0, "duration": 16}, {"index": 5, "duration": 16} ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "JUMP",
 | 
				
			||||||
 | 
					            "frames":[ {"index": 6, "duration": 32}]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": "FALL",
 | 
				
			||||||
 | 
					            "frames":[ {"index": 4, "duration": 32}]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								dist/hw4_assets/spritesheets/platformPlayer.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dist/hw4_assets/spritesheets/platformPlayer.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 300 B  | 
							
								
								
									
										558
									
								
								dist/hw4_assets/tilemaps/level1.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										558
									
								
								dist/hw4_assets/tilemaps/level1.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,558 @@
 | 
				
			||||||
 | 
					{ "compressionlevel":-1,
 | 
				
			||||||
 | 
					 "editorsettings":
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					     "export":
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					         "format":"json",
 | 
				
			||||||
 | 
					         "target":"platformer.json"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					 "height":20,
 | 
				
			||||||
 | 
					 "infinite":false,
 | 
				
			||||||
 | 
					 "layers":[
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					         "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 44, 44, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 0, 44, 44, 44, 44, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 43, 0, 44, 44, 44, 44, 44, 44, 0, 44, 44, 44, 44, 44, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 36, 0, 36, 36, 36, 36, 36, 36, 36, 36, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 43, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 54, 55, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 62, 63, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 | 
				
			||||||
 | 
					         "height":20,
 | 
				
			||||||
 | 
					         "id":2,
 | 
				
			||||||
 | 
					         "name":"Background",
 | 
				
			||||||
 | 
					         "opacity":1,
 | 
				
			||||||
 | 
					         "properties":[
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Collidable",
 | 
				
			||||||
 | 
					                 "type":"bool",
 | 
				
			||||||
 | 
					                 "value":false
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Depth",
 | 
				
			||||||
 | 
					                 "type":"int",
 | 
				
			||||||
 | 
					                 "value":0
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					         "type":"tilelayer",
 | 
				
			||||||
 | 
					         "visible":true,
 | 
				
			||||||
 | 
					         "width":64,
 | 
				
			||||||
 | 
					         "x":0,
 | 
				
			||||||
 | 
					         "y":0
 | 
				
			||||||
 | 
					        }, 
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					         "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 20, 20, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 11, 12, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 12, 12, 12, 12, 12, 12, 12, 9, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 12, 12, 23, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 16, 12, 12, 12, 31, 32, 12, 12, 12, 12, 12, 12, 9, 12, 12, 12, 12, 12, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 12, 12, 12, 7, 20, 20, 20, 20, 20, 20, 8, 12, 12, 12, 12, 10, 12, 23, 24, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 16, 12, 12, 13, 0, 0, 0, 0, 0, 0, 11, 12, 12, 12, 12, 12, 12, 31, 32, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 19, 20, 20, 20, 20, 13, 0, 0, 0, 0, 0, 0, 11, 20, 20, 20, 20, 20, 20, 20, 8, 12, 9, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 11, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 4, 4, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 2, 2, 2, 2, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 10, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 0, 0, 0, 0, 0, 0, 11, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11, 2, 2, 2, 2, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11, 12, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11, 10, 12, 12, 12, 12, 12, 12, 10, 15, 4, 4, 4, 4, 4, 4, 12, 12],
 | 
				
			||||||
 | 
					         "height":20,
 | 
				
			||||||
 | 
					         "id":1,
 | 
				
			||||||
 | 
					         "name":"Main",
 | 
				
			||||||
 | 
					         "opacity":1,
 | 
				
			||||||
 | 
					         "properties":[
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Collidable",
 | 
				
			||||||
 | 
					                 "type":"bool",
 | 
				
			||||||
 | 
					                 "value":true
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Depth",
 | 
				
			||||||
 | 
					                 "type":"int",
 | 
				
			||||||
 | 
					                 "value":1
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Group",
 | 
				
			||||||
 | 
					                 "type":"string",
 | 
				
			||||||
 | 
					                 "value":"ground"
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					         "type":"tilelayer",
 | 
				
			||||||
 | 
					         "visible":true,
 | 
				
			||||||
 | 
					         "width":64,
 | 
				
			||||||
 | 
					         "x":0,
 | 
				
			||||||
 | 
					         "y":0
 | 
				
			||||||
 | 
					        }, 
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					         "draworder":"topdown",
 | 
				
			||||||
 | 
					         "id":4,
 | 
				
			||||||
 | 
					         "name":"Coins",
 | 
				
			||||||
 | 
					         "objects":[
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":2,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":256,
 | 
				
			||||||
 | 
					                 "y":272
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":3,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":272,
 | 
				
			||||||
 | 
					                 "y":272
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":4,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":368,
 | 
				
			||||||
 | 
					                 "y":288
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":5,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":384,
 | 
				
			||||||
 | 
					                 "y":288
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":6,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":400,
 | 
				
			||||||
 | 
					                 "y":288
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":7,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":688,
 | 
				
			||||||
 | 
					                 "y":272
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":8,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":688,
 | 
				
			||||||
 | 
					                 "y":288
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":9,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":688,
 | 
				
			||||||
 | 
					                 "y":304
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":10,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":784,
 | 
				
			||||||
 | 
					                 "y":256
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":11,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":832,
 | 
				
			||||||
 | 
					                 "y":256
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					         "opacity":1,
 | 
				
			||||||
 | 
					         "properties":[
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Depth",
 | 
				
			||||||
 | 
					                 "type":"int",
 | 
				
			||||||
 | 
					                 "value":1
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					         "type":"objectgroup",
 | 
				
			||||||
 | 
					         "visible":true,
 | 
				
			||||||
 | 
					         "x":0,
 | 
				
			||||||
 | 
					         "y":0
 | 
				
			||||||
 | 
					        }, 
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					         "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 64, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 57, 0, 59, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 57, 0, 0, 0, 0, 61, 0, 40, 0, 0, 0, 0, 0, 0, 56, 59, 0, 59, 0, 0, 0, 58, 0, 0, 0, 0, 61, 0, 0, 49, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 | 
				
			||||||
 | 
					         "height":20,
 | 
				
			||||||
 | 
					         "id":3,
 | 
				
			||||||
 | 
					         "name":"Foreground",
 | 
				
			||||||
 | 
					         "opacity":1,
 | 
				
			||||||
 | 
					         "properties":[
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Collidable",
 | 
				
			||||||
 | 
					                 "type":"bool",
 | 
				
			||||||
 | 
					                 "value":false
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Depth",
 | 
				
			||||||
 | 
					                 "type":"int",
 | 
				
			||||||
 | 
					                 "value":2
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					         "type":"tilelayer",
 | 
				
			||||||
 | 
					         "visible":true,
 | 
				
			||||||
 | 
					         "width":64,
 | 
				
			||||||
 | 
					         "x":0,
 | 
				
			||||||
 | 
					         "y":0
 | 
				
			||||||
 | 
					        }],
 | 
				
			||||||
 | 
					 "nextlayerid":5,
 | 
				
			||||||
 | 
					 "nextobjectid":14,
 | 
				
			||||||
 | 
					 "orientation":"orthogonal",
 | 
				
			||||||
 | 
					 "renderorder":"right-down",
 | 
				
			||||||
 | 
					 "tiledversion":"1.3.4",
 | 
				
			||||||
 | 
					 "tileheight":16,
 | 
				
			||||||
 | 
					 "tilesets":[
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					         "columns":8,
 | 
				
			||||||
 | 
					         "firstgid":1,
 | 
				
			||||||
 | 
					         "image":"platformer.png",
 | 
				
			||||||
 | 
					         "imageheight":128,
 | 
				
			||||||
 | 
					         "imagewidth":128,
 | 
				
			||||||
 | 
					         "margin":0,
 | 
				
			||||||
 | 
					         "name":"platformer_tileset",
 | 
				
			||||||
 | 
					         "spacing":0,
 | 
				
			||||||
 | 
					         "tilecount":64,
 | 
				
			||||||
 | 
					         "tileheight":16,
 | 
				
			||||||
 | 
					         "tilewidth":16
 | 
				
			||||||
 | 
					        }],
 | 
				
			||||||
 | 
					 "tilewidth":16,
 | 
				
			||||||
 | 
					 "type":"map",
 | 
				
			||||||
 | 
					 "version":1.2,
 | 
				
			||||||
 | 
					 "width":64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										901
									
								
								dist/hw4_assets/tilemaps/level2.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										901
									
								
								dist/hw4_assets/tilemaps/level2.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,901 @@
 | 
				
			||||||
 | 
					{ "compressionlevel":-1,
 | 
				
			||||||
 | 
					 "editorsettings":
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					     "export":
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					         "target":"."
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					 "height":20,
 | 
				
			||||||
 | 
					 "infinite":false,
 | 
				
			||||||
 | 
					 "layers":[
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					         "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 36, 36, 36, 36, 36, 36, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 0, 0, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 0, 0, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 0, 0, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 44, 44, 44, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 44, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 36, 36, 36, 36, 36, 0, 0, 0, 0, 0, 0, 44, 44, 44, 54, 55, 44, 44, 44, 44, 44, 44, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 54, 55, 44, 44, 0, 0, 0, 0, 0, 0, 0, 44, 44, 62, 63, 44, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 62, 63, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 | 
				
			||||||
 | 
					         "height":20,
 | 
				
			||||||
 | 
					         "id":2,
 | 
				
			||||||
 | 
					         "name":"Background",
 | 
				
			||||||
 | 
					         "opacity":1,
 | 
				
			||||||
 | 
					         "properties":[
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Collidable",
 | 
				
			||||||
 | 
					                 "type":"bool",
 | 
				
			||||||
 | 
					                 "value":false
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Depth",
 | 
				
			||||||
 | 
					                 "type":"int",
 | 
				
			||||||
 | 
					                 "value":0
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					         "type":"tilelayer",
 | 
				
			||||||
 | 
					         "visible":true,
 | 
				
			||||||
 | 
					         "width":64,
 | 
				
			||||||
 | 
					         "x":0,
 | 
				
			||||||
 | 
					         "y":0
 | 
				
			||||||
 | 
					        }, 
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					         "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 4, 12, 13, 0, 0, 0, 0, 0, 30, 0, 0, 3, 4, 4, 4, 5, 0, 0, 0, 0, 0, 0, 3, 4, 4, 4, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 10, 12, 9, 13, 0, 0, 0, 0, 0, 0, 0, 0, 11, 10, 12, 12, 13, 0, 0, 0, 0, 0, 0, 11, 12, 7, 20, 20, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 11, 10, 13, 0, 0, 14, 0, 0, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 13, 0, 0, 30, 0, 0, 0, 0, 0, 11, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 11, 12, 13, 0, 0, 14, 0, 0, 11, 9, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 12, 10, 13, 0, 0, 0, 0, 0, 0, 19, 20, 20, 29, 0, 14, 0, 0, 19, 20, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 4, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 27, 20, 20, 20, 20, 21, 0, 0, 0, 0, 0, 0, 3, 5, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 11, 9, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 10, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 4, 5, 0, 0, 0, 0, 0, 0, 11, 12, 10, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 12, 12, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 13, 0, 0, 0, 0, 0, 0, 11, 12, 12, 12, 12, 12, 4, 5, 0, 0, 0, 0, 3, 4, 4, 4, 4, 4, 5, 0, 0, 0, 0, 0, 0, 11, 12, 12, 12, 9, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 0, 0, 0, 0, 0, 0, 11, 10, 12, 12, 12, 12, 12, 15, 4, 4, 4, 4, 16, 12, 12, 12, 12, 12, 13, 1, 1, 1, 1, 1, 1, 11, 12, 12, 12, 12, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
 | 
				
			||||||
 | 
					         "height":20,
 | 
				
			||||||
 | 
					         "id":3,
 | 
				
			||||||
 | 
					         "name":"Main",
 | 
				
			||||||
 | 
					         "opacity":1,
 | 
				
			||||||
 | 
					         "properties":[
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Collidable",
 | 
				
			||||||
 | 
					                 "type":"bool",
 | 
				
			||||||
 | 
					                 "value":true
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Depth",
 | 
				
			||||||
 | 
					                 "type":"int",
 | 
				
			||||||
 | 
					                 "value":1
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Group",
 | 
				
			||||||
 | 
					                 "type":"string",
 | 
				
			||||||
 | 
					                 "value":"ground"
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					         "type":"tilelayer",
 | 
				
			||||||
 | 
					         "visible":true,
 | 
				
			||||||
 | 
					         "width":64,
 | 
				
			||||||
 | 
					         "x":0,
 | 
				
			||||||
 | 
					         "y":0
 | 
				
			||||||
 | 
					        }, 
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					         "draworder":"topdown",
 | 
				
			||||||
 | 
					         "id":4,
 | 
				
			||||||
 | 
					         "name":"Coins",
 | 
				
			||||||
 | 
					         "objects":[
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":1,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":272,
 | 
				
			||||||
 | 
					                 "y":80
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":2,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":288,
 | 
				
			||||||
 | 
					                 "y":80
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":3,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":112,
 | 
				
			||||||
 | 
					                 "y":80
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":4,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":64,
 | 
				
			||||||
 | 
					                 "y":128
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":5,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":160,
 | 
				
			||||||
 | 
					                 "y":272
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":6,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":176,
 | 
				
			||||||
 | 
					                 "y":272
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":7,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":192,
 | 
				
			||||||
 | 
					                 "y":272
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":8,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":208,
 | 
				
			||||||
 | 
					                 "y":272
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":9,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":384,
 | 
				
			||||||
 | 
					                 "y":176
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":10,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":400,
 | 
				
			||||||
 | 
					                 "y":176
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":11,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":384,
 | 
				
			||||||
 | 
					                 "y":192
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":12,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":400,
 | 
				
			||||||
 | 
					                 "y":192
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":13,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":400,
 | 
				
			||||||
 | 
					                 "y":208
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":14,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":704,
 | 
				
			||||||
 | 
					                 "y":272
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":15,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":720,
 | 
				
			||||||
 | 
					                 "y":272
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":16,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":752,
 | 
				
			||||||
 | 
					                 "y":272
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":17,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":736,
 | 
				
			||||||
 | 
					                 "y":272
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "gid":25,
 | 
				
			||||||
 | 
					                 "height":16,
 | 
				
			||||||
 | 
					                 "id":18,
 | 
				
			||||||
 | 
					                 "name":"",
 | 
				
			||||||
 | 
					                 "properties":[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"Group",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"coin"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"HasPhysics",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsCollidable",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":false
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"IsTrigger",
 | 
				
			||||||
 | 
					                         "type":"bool",
 | 
				
			||||||
 | 
					                         "value":true
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerGroup",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"player"
 | 
				
			||||||
 | 
					                        }, 
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                         "name":"TriggerOnEnter",
 | 
				
			||||||
 | 
					                         "type":"string",
 | 
				
			||||||
 | 
					                         "value":"PlayerHitCoin"
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                 "rotation":0,
 | 
				
			||||||
 | 
					                 "type":"",
 | 
				
			||||||
 | 
					                 "visible":true,
 | 
				
			||||||
 | 
					                 "width":16,
 | 
				
			||||||
 | 
					                 "x":768,
 | 
				
			||||||
 | 
					                 "y":272
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					         "opacity":1,
 | 
				
			||||||
 | 
					         "properties":[
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Depth",
 | 
				
			||||||
 | 
					                 "type":"int",
 | 
				
			||||||
 | 
					                 "value":1
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					         "type":"objectgroup",
 | 
				
			||||||
 | 
					         "visible":true,
 | 
				
			||||||
 | 
					         "x":0,
 | 
				
			||||||
 | 
					         "y":0
 | 
				
			||||||
 | 
					        }, 
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					         "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 40, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 48, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 56, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 2, 2, 0, 64, 0, 0, 0, 0, 56, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 17, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 2, 2, 2, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 64, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 57, 2, 0, 0, 0, 0, 0, 0, 0, 64, 57, 0, 61, 60, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 59, 0, 0, 59, 0, 0, 0, 0, 0, 2, 59, 58, 0, 59, 0, 0, 58, 2, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 | 
				
			||||||
 | 
					         "height":20,
 | 
				
			||||||
 | 
					         "id":1,
 | 
				
			||||||
 | 
					         "name":"Foreground",
 | 
				
			||||||
 | 
					         "opacity":1,
 | 
				
			||||||
 | 
					         "properties":[
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Collidable",
 | 
				
			||||||
 | 
					                 "type":"bool",
 | 
				
			||||||
 | 
					                 "value":false
 | 
				
			||||||
 | 
					                }, 
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                 "name":"Depth",
 | 
				
			||||||
 | 
					                 "type":"int",
 | 
				
			||||||
 | 
					                 "value":2
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					         "type":"tilelayer",
 | 
				
			||||||
 | 
					         "visible":true,
 | 
				
			||||||
 | 
					         "width":64,
 | 
				
			||||||
 | 
					         "x":0,
 | 
				
			||||||
 | 
					         "y":0
 | 
				
			||||||
 | 
					        }],
 | 
				
			||||||
 | 
					 "nextlayerid":5,
 | 
				
			||||||
 | 
					 "nextobjectid":19,
 | 
				
			||||||
 | 
					 "orientation":"orthogonal",
 | 
				
			||||||
 | 
					 "renderorder":"right-down",
 | 
				
			||||||
 | 
					 "tiledversion":"1.3.4",
 | 
				
			||||||
 | 
					 "tileheight":16,
 | 
				
			||||||
 | 
					 "tilesets":[
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					         "columns":8,
 | 
				
			||||||
 | 
					         "firstgid":1,
 | 
				
			||||||
 | 
					         "image":"platformer.png",
 | 
				
			||||||
 | 
					         "imageheight":128,
 | 
				
			||||||
 | 
					         "imagewidth":128,
 | 
				
			||||||
 | 
					         "margin":0,
 | 
				
			||||||
 | 
					         "name":"platformer_tileset",
 | 
				
			||||||
 | 
					         "spacing":0,
 | 
				
			||||||
 | 
					         "tilecount":64,
 | 
				
			||||||
 | 
					         "tileheight":16,
 | 
				
			||||||
 | 
					         "tilewidth":16
 | 
				
			||||||
 | 
					        }],
 | 
				
			||||||
 | 
					 "tilewidth":16,
 | 
				
			||||||
 | 
					 "type":"map",
 | 
				
			||||||
 | 
					 "version":1.2,
 | 
				
			||||||
 | 
					 "width":64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								dist/hw4_assets/tilemaps/platformer.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dist/hw4_assets/tilemaps/platformer.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 2.0 KiB  | 
							
								
								
									
										71
									
								
								src/Homework4/Enemies/EnemyController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/Homework4/Enemies/EnemyController.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,71 @@
 | 
				
			||||||
 | 
					import Idle from "./Idle";
 | 
				
			||||||
 | 
					import Jump from "./Jump";
 | 
				
			||||||
 | 
					import Walk from "./Walk";
 | 
				
			||||||
 | 
					import GameNode from "../../Wolfie2D/Nodes/GameNode";
 | 
				
			||||||
 | 
					import Vec2 from "../../Wolfie2D/DataTypes/Vec2";
 | 
				
			||||||
 | 
					import StateMachineAI from "../../Wolfie2D/AI/StateMachineAI";
 | 
				
			||||||
 | 
					import { HW4_Events } from "../hw4_enums";
 | 
				
			||||||
 | 
					import { EaseFunctionType } from "../../Wolfie2D/Utils/EaseFunctions";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum EnemyStates {
 | 
				
			||||||
 | 
						IDLE = "idle",
 | 
				
			||||||
 | 
						WALK = "walk",
 | 
				
			||||||
 | 
						JUMP = "jump",
 | 
				
			||||||
 | 
						PREVIOUS = "previous"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class EnemyController extends StateMachineAI {
 | 
				
			||||||
 | 
						owner: GameNode;
 | 
				
			||||||
 | 
						jumpy: boolean;
 | 
				
			||||||
 | 
						direction: Vec2 = Vec2.ZERO;
 | 
				
			||||||
 | 
						velocity: Vec2 = Vec2.ZERO;
 | 
				
			||||||
 | 
						speed: number = 200;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						initializeAI(owner: GameNode, options: Record<string, any>){
 | 
				
			||||||
 | 
							this.owner = owner;
 | 
				
			||||||
 | 
							this.jumpy = options.jumpy ? options.jumpy : false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.receiver.subscribe(HW4_Events.PLAYER_MOVE);
 | 
				
			||||||
 | 
							if(this.jumpy){
 | 
				
			||||||
 | 
								this.receiver.subscribe(HW4_Events.PLAYER_JUMP);
 | 
				
			||||||
 | 
								this.speed = 100;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Give the owner a tween for the jump
 | 
				
			||||||
 | 
								owner.tweens.add("jump", {
 | 
				
			||||||
 | 
					                startDelay: 0,
 | 
				
			||||||
 | 
					                duration: 300,
 | 
				
			||||||
 | 
					                effects: [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        property: "rotation",
 | 
				
			||||||
 | 
					                        resetOnComplete: true,
 | 
				
			||||||
 | 
					                        start: -3.14/8,
 | 
				
			||||||
 | 
					                        end: 3.14/8,
 | 
				
			||||||
 | 
					                        ease: EaseFunctionType.IN_OUT_SINE
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                reverseOnComplete: true,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let idle = new Idle(this, owner);
 | 
				
			||||||
 | 
							this.addState(EnemyStates.IDLE, idle);
 | 
				
			||||||
 | 
							let walk = new Walk(this, owner);
 | 
				
			||||||
 | 
							this.addState(EnemyStates.WALK, walk);
 | 
				
			||||||
 | 
							let jump = new Jump(this, owner);
 | 
				
			||||||
 | 
							this.addState(EnemyStates.JUMP, jump);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.initialize(EnemyStates.IDLE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						changeState(stateName: string): void {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(stateName === EnemyStates.JUMP){
 | 
				
			||||||
 | 
					            this.stack.push(this.stateMap.get(stateName));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        super.changeState(stateName);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						update(deltaT: number): void {
 | 
				
			||||||
 | 
							super.update(deltaT);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										31
									
								
								src/Homework4/Enemies/EnemyState.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/Homework4/Enemies/EnemyState.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					import State from "../../Wolfie2D/DataTypes/State/State";
 | 
				
			||||||
 | 
					import StateMachine from "../../Wolfie2D/DataTypes/State/StateMachine";
 | 
				
			||||||
 | 
					import GameEvent from "../../Wolfie2D/Events/GameEvent";
 | 
				
			||||||
 | 
					import GameNode from "../../Wolfie2D/Nodes/GameNode";
 | 
				
			||||||
 | 
					import AnimatedSprite from "../../Wolfie2D/Nodes/Sprites/AnimatedSprite";
 | 
				
			||||||
 | 
					import EnemyController from "./EnemyController";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default abstract class EnemyState extends State {
 | 
				
			||||||
 | 
						owner: GameNode;
 | 
				
			||||||
 | 
						gravity: number = 1000;
 | 
				
			||||||
 | 
						parent: EnemyController
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						constructor(parent: StateMachine, owner: GameNode){
 | 
				
			||||||
 | 
							super(parent);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							this.owner = owner;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						handleInput(event: GameEvent): void {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						update(deltaT: number): void {
 | 
				
			||||||
 | 
							// Do gravity
 | 
				
			||||||
 | 
							this.parent.velocity.y += this.gravity*deltaT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(this.owner.onWall){
 | 
				
			||||||
 | 
								// Flip around
 | 
				
			||||||
 | 
								this.parent.direction.x *= -1;
 | 
				
			||||||
 | 
								(<AnimatedSprite>this.owner).invertX = !(<AnimatedSprite>this.owner).invertX;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										37
									
								
								src/Homework4/Enemies/Idle.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/Homework4/Enemies/Idle.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,37 @@
 | 
				
			||||||
 | 
					import GameEvent from "../../Wolfie2D/Events/GameEvent";
 | 
				
			||||||
 | 
					import AnimatedSprite from "../../Wolfie2D/Nodes/Sprites/AnimatedSprite";
 | 
				
			||||||
 | 
					import { HW4_Events } from "../hw4_enums";
 | 
				
			||||||
 | 
					import { EnemyStates } from "./EnemyController";
 | 
				
			||||||
 | 
					import OnGround from "./OnGround";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * The idle enemy state. Enemies don't do anything until the player comes near them. 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export default class Idle extends OnGround {
 | 
				
			||||||
 | 
						onEnter(): void {
 | 
				
			||||||
 | 
							this.parent.speed = this.parent.speed;
 | 
				
			||||||
 | 
							(<AnimatedSprite>this.owner).animation.play("IDLE", true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onExit(): Record<string, any> {
 | 
				
			||||||
 | 
							(<AnimatedSprite>this.owner).animation.stop();
 | 
				
			||||||
 | 
							return {};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						handleInput(event: GameEvent) {
 | 
				
			||||||
 | 
							if(event.type === HW4_Events.PLAYER_MOVE){
 | 
				
			||||||
 | 
								let pos = event.data.get("position");
 | 
				
			||||||
 | 
								if(this.owner.position.x - pos.x < (64*10)){
 | 
				
			||||||
 | 
									this.finished(EnemyStates.WALK);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						update(deltaT: number): void {
 | 
				
			||||||
 | 
							super.update(deltaT);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							this.parent.velocity.x = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.owner.move(this.parent.velocity.scaled(deltaT));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										34
									
								
								src/Homework4/Enemies/Jump.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/Homework4/Enemies/Jump.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,34 @@
 | 
				
			||||||
 | 
					import AnimatedSprite from "../../Wolfie2D/Nodes/Sprites/AnimatedSprite";
 | 
				
			||||||
 | 
					import { EnemyStates } from "./EnemyController";
 | 
				
			||||||
 | 
					import EnemyState from "./EnemyState";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class Jump extends EnemyState {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onEnter(): void {
 | 
				
			||||||
 | 
							(<AnimatedSprite>this.owner).animation.play("JUMP", true);
 | 
				
			||||||
 | 
							(<AnimatedSprite>this.owner).tweens.play("jump", true);
 | 
				
			||||||
 | 
							this.gravity = 500;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						update(deltaT: number): void {
 | 
				
			||||||
 | 
							super.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(this.owner.onGround){
 | 
				
			||||||
 | 
								this.finished(EnemyStates.PREVIOUS);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(this.owner.onCeiling){
 | 
				
			||||||
 | 
								this.parent.velocity.y = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.parent.velocity.x += this.parent.direction.x * this.parent.speed/3.5 - 0.3*this.parent.velocity.x;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.owner.move(this.parent.velocity.scaled(deltaT));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onExit(): Record<string, any> {
 | 
				
			||||||
 | 
							(<AnimatedSprite>this.owner).animation.stop();
 | 
				
			||||||
 | 
							(<AnimatedSprite>this.owner).tweens.stop("jump");
 | 
				
			||||||
 | 
							return {};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								src/Homework4/Enemies/OnGround.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/Homework4/Enemies/OnGround.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					import GameEvent from "../../Wolfie2D/Events/GameEvent";
 | 
				
			||||||
 | 
					import { EnemyStates } from "./EnemyController";
 | 
				
			||||||
 | 
					import EnemyState from "./EnemyState";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class OnGround extends EnemyState {
 | 
				
			||||||
 | 
						onEnter(): void {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						handleInput(event: GameEvent): void {
 | 
				
			||||||
 | 
							super.handleInput(event);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						update(deltaT: number): void {
 | 
				
			||||||
 | 
							if(this.parent.velocity.y > 0){
 | 
				
			||||||
 | 
								this.parent.velocity.y = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							super.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(!this.owner.onGround && this.parent.jumpy && this.owner.active){
 | 
				
			||||||
 | 
								this.finished(EnemyStates.JUMP);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onExit(): Record<string, any> {
 | 
				
			||||||
 | 
							return {};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										37
									
								
								src/Homework4/Enemies/Walk.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/Homework4/Enemies/Walk.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,37 @@
 | 
				
			||||||
 | 
					import Vec2 from "../../Wolfie2D/DataTypes/Vec2";
 | 
				
			||||||
 | 
					import AnimatedSprite from "../../Wolfie2D/Nodes/Sprites/AnimatedSprite";
 | 
				
			||||||
 | 
					import { EnemyStates } from "./EnemyController";
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
								(<AnimatedSprite>this.owner).invertX = true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							(<AnimatedSprite>this.owner).animation.play("WALK", true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.time = Date.now();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						update(deltaT: number): void {
 | 
				
			||||||
 | 
							super.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(this.parent.jumpy && (Date.now() - this.time > 500)){
 | 
				
			||||||
 | 
								this.finished(EnemyStates.JUMP);
 | 
				
			||||||
 | 
								this.parent.velocity.y = -300;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.parent.velocity.x = this.parent.direction.x * this.parent.speed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.owner.move(this.parent.velocity.scaled(deltaT));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onExit(): Record<string, any> {
 | 
				
			||||||
 | 
							(<AnimatedSprite>this.owner).animation.stop();
 | 
				
			||||||
 | 
							return {};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										89
									
								
								src/Homework4/Player/PlayerController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/Homework4/Player/PlayerController.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,89 @@
 | 
				
			||||||
 | 
					import StateMachineAI from "../../Wolfie2D/AI/StateMachineAI";
 | 
				
			||||||
 | 
					import Vec2 from "../../Wolfie2D/DataTypes/Vec2";
 | 
				
			||||||
 | 
					import Debug from "../../Wolfie2D/Debug/Debug";
 | 
				
			||||||
 | 
					import GameNode from "../../Wolfie2D/Nodes/GameNode";
 | 
				
			||||||
 | 
					import Sprite from "../../Wolfie2D/Nodes/Sprites/Sprite";
 | 
				
			||||||
 | 
					import OrthogonalTilemap from "../../Wolfie2D/Nodes/Tilemaps/OrthogonalTilemap";
 | 
				
			||||||
 | 
					import Fall from "./PlayerStates/Fall";
 | 
				
			||||||
 | 
					import Idle from "./PlayerStates/Idle";
 | 
				
			||||||
 | 
					import InAir from "./PlayerStates/InAir";
 | 
				
			||||||
 | 
					import Jump from "./PlayerStates/Jump";
 | 
				
			||||||
 | 
					import Run from "./PlayerStates/Run";
 | 
				
			||||||
 | 
					import Walk from "./PlayerStates/Walk";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum PlayerType {
 | 
				
			||||||
 | 
					    PLATFORMER = "platformer",
 | 
				
			||||||
 | 
					    TOPDOWN = "topdown"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum PlayerStates {
 | 
				
			||||||
 | 
					    IDLE = "idle",
 | 
				
			||||||
 | 
					    WALK = "walk",
 | 
				
			||||||
 | 
						RUN = "run",
 | 
				
			||||||
 | 
						JUMP = "jump",
 | 
				
			||||||
 | 
					    FALL = "fall",
 | 
				
			||||||
 | 
						PREVIOUS = "previous"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class PlayerController extends StateMachineAI {
 | 
				
			||||||
 | 
					    protected owner: GameNode;
 | 
				
			||||||
 | 
					    velocity: Vec2 = Vec2.ZERO;
 | 
				
			||||||
 | 
						speed: number = 200;
 | 
				
			||||||
 | 
						MIN_SPEED: number = 200;
 | 
				
			||||||
 | 
					    MAX_SPEED: number = 300;
 | 
				
			||||||
 | 
					    tilemap: OrthogonalTilemap;
 | 
				
			||||||
 | 
					    coin: Sprite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    initializeAI(owner: GameNode, options: Record<string, any>){
 | 
				
			||||||
 | 
					        this.owner = owner;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.initializePlatformer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.tilemap = this.owner.getScene().getTilemap(options.tilemap) as OrthogonalTilemap;
 | 
				
			||||||
 | 
					        this.coin = this.owner.getScene().add.sprite("coin", "coinLayer");
 | 
				
			||||||
 | 
					        this.coin.scale.set(2, 2);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    initializePlatformer(): void {
 | 
				
			||||||
 | 
					        this.speed = 400;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let idle = new Idle(this, this.owner);
 | 
				
			||||||
 | 
							this.addState(PlayerStates.IDLE, idle);
 | 
				
			||||||
 | 
							let walk = new Walk(this, this.owner);
 | 
				
			||||||
 | 
							this.addState(PlayerStates.WALK, walk);
 | 
				
			||||||
 | 
							let run = new Run(this, this.owner);
 | 
				
			||||||
 | 
							this.addState(PlayerStates.RUN, run);
 | 
				
			||||||
 | 
							let jump = new Jump(this, this.owner);
 | 
				
			||||||
 | 
					        this.addState(PlayerStates.JUMP, jump);
 | 
				
			||||||
 | 
					        let fall = new Fall(this, this.owner);
 | 
				
			||||||
 | 
					        this.addState(PlayerStates.FALL, fall);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        this.initialize(PlayerStates.IDLE);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    changeState(stateName: string): void {
 | 
				
			||||||
 | 
					        // If we jump or fall, push the state so we can go back to our current state later
 | 
				
			||||||
 | 
					        // unless we're going from jump to fall or something
 | 
				
			||||||
 | 
					        if((stateName === PlayerStates.JUMP || stateName === PlayerStates.FALL) && !(this.stack.peek() instanceof InAir)){
 | 
				
			||||||
 | 
					            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 if (this.currentState instanceof Idle){
 | 
				
			||||||
 | 
								Debug.log("playerstate", "Player State: Idle");
 | 
				
			||||||
 | 
							} else if(this.currentState instanceof Fall){
 | 
				
			||||||
 | 
					            Debug.log("playerstate", "Player State: Fall");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								src/Homework4/Player/PlayerStates/Fall.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Homework4/Player/PlayerStates/Fall.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,18 @@
 | 
				
			||||||
 | 
					import GameEvent from "../../../Wolfie2D/Events/GameEvent";
 | 
				
			||||||
 | 
					import AnimatedSprite from "../../../Wolfie2D/Nodes/Sprites/AnimatedSprite";
 | 
				
			||||||
 | 
					import InAir from "./InAir";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class Fall extends InAir {
 | 
				
			||||||
 | 
					    owner: AnimatedSprite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onEnter(options: Record<string, any>): void {
 | 
				
			||||||
 | 
							this.owner.animation.play("FALL", true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						handleInput(event: GameEvent): void {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    onExit(): Record<string, any> {
 | 
				
			||||||
 | 
							this.owner.animation.stop();
 | 
				
			||||||
 | 
					        return {};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										36
									
								
								src/Homework4/Player/PlayerStates/Idle.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/Homework4/Player/PlayerStates/Idle.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,36 @@
 | 
				
			||||||
 | 
					import Input from "../../../Wolfie2D/Input/Input";
 | 
				
			||||||
 | 
					import AnimatedSprite from "../../../Wolfie2D/Nodes/Sprites/AnimatedSprite";
 | 
				
			||||||
 | 
					import { PlayerStates } from "../PlayerController";
 | 
				
			||||||
 | 
					import OnGround from "./OnGround";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class Idle extends OnGround {
 | 
				
			||||||
 | 
						owner: AnimatedSprite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onEnter(options: Record<string, any>): void {
 | 
				
			||||||
 | 
							this.parent.speed = this.parent.MIN_SPEED;
 | 
				
			||||||
 | 
							this.owner.animation.play("IDLE", true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						update(deltaT: number): void {
 | 
				
			||||||
 | 
							super.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let dir = this.getInputDirection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(!dir.isZero() && dir.y === 0){
 | 
				
			||||||
 | 
								if(Input.isPressed("run")){
 | 
				
			||||||
 | 
									this.finished(PlayerStates.RUN);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									this.finished(PlayerStates.WALK);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							this.parent.velocity.x = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.owner.move(this.parent.velocity.scaled(deltaT));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onExit(): Record<string, any> {
 | 
				
			||||||
 | 
							this.owner.animation.stop();
 | 
				
			||||||
 | 
							return {};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								src/Homework4/Player/PlayerStates/InAir.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/Homework4/Player/PlayerStates/InAir.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					import GameEvent from "../../../Wolfie2D/Events/GameEvent";
 | 
				
			||||||
 | 
					import { PlayerStates } from "../PlayerController";
 | 
				
			||||||
 | 
					import PlayerState from "./PlayerState";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default abstract class InAir extends PlayerState {
 | 
				
			||||||
 | 
					    update(deltaT: number): void {
 | 
				
			||||||
 | 
					        super.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let dir = this.getInputDirection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.parent.velocity.x += dir.x * this.parent.speed/3.5 - 0.3*this.parent.velocity.x;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.owner.move(this.parent.velocity.scaled(deltaT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(this.owner.onGround){
 | 
				
			||||||
 | 
								this.finished(PlayerStates.PREVIOUS);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										108
									
								
								src/Homework4/Player/PlayerStates/Jump.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								src/Homework4/Player/PlayerStates/Jump.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,108 @@
 | 
				
			||||||
 | 
					import GameEvent from "../../../Wolfie2D/Events/GameEvent";
 | 
				
			||||||
 | 
					import AnimatedSprite from "../../../Wolfie2D/Nodes/Sprites/AnimatedSprite";
 | 
				
			||||||
 | 
					import { EaseFunctionType } from "../../../Wolfie2D/Utils/EaseFunctions";
 | 
				
			||||||
 | 
					import { HW4_Events } from "../../hw4_enums";
 | 
				
			||||||
 | 
					import { PlayerStates } from "../PlayerController";
 | 
				
			||||||
 | 
					import InAir from "./InAir";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class Jump extends InAir {
 | 
				
			||||||
 | 
						owner: AnimatedSprite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onEnter(options: Record<string, any>): void {
 | 
				
			||||||
 | 
							this.owner.animation.play("JUMP", true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						handleInput(event: GameEvent): void {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						update(deltaT: number): void {
 | 
				
			||||||
 | 
							super.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(this.owner.onCeiling){
 | 
				
			||||||
 | 
								this.parent.velocity.y = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// If we're falling, go to the fall state
 | 
				
			||||||
 | 
							if(this.parent.velocity.y >= 0){
 | 
				
			||||||
 | 
								this.finished(PlayerStates.FALL);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(this.owner.collidedWithTilemap && this.owner.onCeiling){
 | 
				
			||||||
 | 
								// We collided with a tilemap above us. First, get the tile right above us
 | 
				
			||||||
 | 
								this.handleCoinblockCollision();
 | 
				
			||||||
 | 
							}		
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onExit(): Record<string, any> {
 | 
				
			||||||
 | 
							this.owner.animation.stop();
 | 
				
			||||||
 | 
							return {};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						handleCoinblockCollision(){
 | 
				
			||||||
 | 
							let pos = this.owner.position.clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Go up plus some extra
 | 
				
			||||||
 | 
							pos.y -= (this.owner.collisionShape.halfSize.y + 10);
 | 
				
			||||||
 | 
							pos.x -= 16;
 | 
				
			||||||
 | 
							let rowCol = this.parent.tilemap.getColRowAt(pos);
 | 
				
			||||||
 | 
							let tile1 = this.parent.tilemap.getTileAtRowCol(rowCol);
 | 
				
			||||||
 | 
							pos.x += 16;
 | 
				
			||||||
 | 
							rowCol = this.parent.tilemap.getColRowAt(pos);
 | 
				
			||||||
 | 
							let tile2 = this.parent.tilemap.getTileAtRowCol(rowCol);
 | 
				
			||||||
 | 
							pos.x += 16;
 | 
				
			||||||
 | 
							rowCol = this.parent.tilemap.getColRowAt(pos);
 | 
				
			||||||
 | 
							let tile3 = this.parent.tilemap.getTileAtRowCol(rowCol);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let t1 = tile1 === 17;
 | 
				
			||||||
 | 
							let t2 = tile2 === 17;
 | 
				
			||||||
 | 
							let t3 = tile3 === 17;
 | 
				
			||||||
 | 
							let air1 = tile1 === 0;
 | 
				
			||||||
 | 
							let air2 = tile2 === 0;
 | 
				
			||||||
 | 
							let air3 = tile3 === 0;
 | 
				
			||||||
 | 
							let majority = (t1 && t2) || (t1 && t3) || (t2 && t3) || (t1 && t2 && t3);
 | 
				
			||||||
 | 
							let minorityButAir = (t1 && air2 && air3) || (air1 && t2 && air3) || (air1 && air2 && t3);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// If coin block, change to empty coin block
 | 
				
			||||||
 | 
							if(majority || minorityButAir){
 | 
				
			||||||
 | 
								if(minorityButAir){
 | 
				
			||||||
 | 
									// Get the correct position
 | 
				
			||||||
 | 
									if(t1){
 | 
				
			||||||
 | 
										pos.x -= 32;
 | 
				
			||||||
 | 
									} else if(t2){
 | 
				
			||||||
 | 
										pos.x -= 16;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									rowCol = this.parent.tilemap.getColRowAt(pos);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									pos.x -= 16;
 | 
				
			||||||
 | 
									rowCol = this.parent.tilemap.getColRowAt(pos);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								this.parent.tilemap.setTileAtRowCol(rowCol, 18);
 | 
				
			||||||
 | 
								this.emitter.fireEvent(HW4_Events.PLAYER_HIT_COIN_BLOCK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								let tileSize = this.parent.tilemap.getTileSize();
 | 
				
			||||||
 | 
								this.parent.coin.position.copy(rowCol.scale(tileSize.x, tileSize.y).add(tileSize.scaled(0.5)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Animate collision
 | 
				
			||||||
 | 
								this.parent.coin.tweens.add("coin", {
 | 
				
			||||||
 | 
									startDelay: 0,
 | 
				
			||||||
 | 
									duration: 300,
 | 
				
			||||||
 | 
									effects: [{
 | 
				
			||||||
 | 
										property: "positionY",
 | 
				
			||||||
 | 
										resetOnComplete: false,
 | 
				
			||||||
 | 
										start: this.parent.coin.position.y,
 | 
				
			||||||
 | 
										end: this.parent.coin.position.y - 2*tileSize.y,
 | 
				
			||||||
 | 
										ease: EaseFunctionType.OUT_SINE
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										property: "alpha",
 | 
				
			||||||
 | 
										resetOnComplete: false,
 | 
				
			||||||
 | 
										start: 1,
 | 
				
			||||||
 | 
										end: 0,
 | 
				
			||||||
 | 
										ease: EaseFunctionType.OUT_SINE
 | 
				
			||||||
 | 
									}]
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								this.parent.coin.tweens.play("coin");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										38
									
								
								src/Homework4/Player/PlayerStates/OnGround.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/Homework4/Player/PlayerStates/OnGround.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,38 @@
 | 
				
			||||||
 | 
					import GameEvent from "../../../Wolfie2D/Events/GameEvent";
 | 
				
			||||||
 | 
					import Input from "../../../Wolfie2D/Input/Input";
 | 
				
			||||||
 | 
					import Sprite from "../../../Wolfie2D/Nodes/Sprites/Sprite";
 | 
				
			||||||
 | 
					import MathUtils from "../../../Wolfie2D/Utils/MathUtils";
 | 
				
			||||||
 | 
					import PlayerState from "./PlayerState";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class OnGround extends PlayerState {
 | 
				
			||||||
 | 
						onEnter(options: Record<string, any>): void {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						handleInput(event: GameEvent): void {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						update(deltaT: number): void {
 | 
				
			||||||
 | 
							if(this.parent.velocity.y > 0){
 | 
				
			||||||
 | 
								this.parent.velocity.y = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							super.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let direction = this.getInputDirection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(direction.x !== 0){
 | 
				
			||||||
 | 
								(<Sprite>this.owner).invertX = MathUtils.sign(direction.x) < 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(Input.isJustPressed("jump")){
 | 
				
			||||||
 | 
								this.finished("jump");
 | 
				
			||||||
 | 
								this.parent.velocity.y = -500;
 | 
				
			||||||
 | 
								if(this.parent.velocity.x !== 0){
 | 
				
			||||||
 | 
									this.owner.tweens.play("flip");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else if(!this.owner.onGround){
 | 
				
			||||||
 | 
								this.finished("jump");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onExit(): Record<string, any> {
 | 
				
			||||||
 | 
							return {};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								src/Homework4/Player/PlayerStates/PlayerState.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/Homework4/Player/PlayerStates/PlayerState.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					import State from "../../../Wolfie2D/DataTypes/State/State";
 | 
				
			||||||
 | 
					import StateMachine from "../../../Wolfie2D/DataTypes/State/StateMachine";
 | 
				
			||||||
 | 
					import Vec2 from "../../../Wolfie2D/DataTypes/Vec2";
 | 
				
			||||||
 | 
					import Input from "../../../Wolfie2D/Input/Input";
 | 
				
			||||||
 | 
					import GameNode from "../../../Wolfie2D/Nodes/GameNode";
 | 
				
			||||||
 | 
					import PlayerController from "../PlayerController";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default abstract class PlayerState extends State {
 | 
				
			||||||
 | 
						owner: GameNode;
 | 
				
			||||||
 | 
						gravity: number = 1000;
 | 
				
			||||||
 | 
						parent: PlayerController;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						constructor(parent: StateMachine, owner: GameNode){
 | 
				
			||||||
 | 
							super(parent);
 | 
				
			||||||
 | 
							this.owner = owner;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						getInputDirection(): Vec2 {
 | 
				
			||||||
 | 
							let direction = Vec2.ZERO;
 | 
				
			||||||
 | 
							direction.x = (Input.isPressed("left") ? -1 : 0) + (Input.isPressed("right") ? 1 : 0);
 | 
				
			||||||
 | 
							direction.y = (Input.isJustPressed("jump") ? -1 : 0);
 | 
				
			||||||
 | 
							return direction;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						update(deltaT: number): void {
 | 
				
			||||||
 | 
							// Do gravity
 | 
				
			||||||
 | 
							this.parent.velocity.y += this.gravity*deltaT;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										38
									
								
								src/Homework4/Player/PlayerStates/Run.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/Homework4/Player/PlayerStates/Run.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,38 @@
 | 
				
			||||||
 | 
					import Input from "../../../Wolfie2D/Input/Input";
 | 
				
			||||||
 | 
					import AnimatedSprite from "../../../Wolfie2D/Nodes/Sprites/AnimatedSprite";
 | 
				
			||||||
 | 
					import { HW4_Events } from "../../hw4_enums";
 | 
				
			||||||
 | 
					import { PlayerStates } from "../PlayerController";
 | 
				
			||||||
 | 
					import OnGround from "./OnGround";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class Run extends OnGround {
 | 
				
			||||||
 | 
						owner: AnimatedSprite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onEnter(options: Record<string, any>): void {
 | 
				
			||||||
 | 
							this.parent.speed = this.parent.MAX_SPEED;
 | 
				
			||||||
 | 
							this.owner.animation.play("WALK", true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						update(deltaT: number): void {
 | 
				
			||||||
 | 
							super.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let dir = this.getInputDirection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(dir.isZero()){
 | 
				
			||||||
 | 
								this.finished(PlayerStates.IDLE);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if(!Input.isPressed("run")){
 | 
				
			||||||
 | 
									this.finished(PlayerStates.WALK);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.parent.velocity.x = dir.x * this.parent.speed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.emitter.fireEvent(HW4_Events.PLAYER_MOVE, {position: this.owner.position.clone()});
 | 
				
			||||||
 | 
							this.owner.move(this.parent.velocity.scaled(deltaT));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onExit(): Record<string, any> {
 | 
				
			||||||
 | 
							this.owner.animation.stop();
 | 
				
			||||||
 | 
							return {};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										38
									
								
								src/Homework4/Player/PlayerStates/Walk.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/Homework4/Player/PlayerStates/Walk.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,38 @@
 | 
				
			||||||
 | 
					import Input from "../../../Wolfie2D/Input/Input";
 | 
				
			||||||
 | 
					import AnimatedSprite from "../../../Wolfie2D/Nodes/Sprites/AnimatedSprite";
 | 
				
			||||||
 | 
					import { HW4_Events } from "../../hw4_enums";
 | 
				
			||||||
 | 
					import { PlayerStates } from "../PlayerController";
 | 
				
			||||||
 | 
					import OnGround from "./OnGround";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class Walk extends OnGround {
 | 
				
			||||||
 | 
						owner: AnimatedSprite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onEnter(options: Record<string, any>): void {
 | 
				
			||||||
 | 
							this.parent.speed = this.parent.MIN_SPEED;
 | 
				
			||||||
 | 
							this.owner.animation.play("WALK", true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						update(deltaT: number): void {
 | 
				
			||||||
 | 
							super.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let dir = this.getInputDirection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(dir.isZero()){
 | 
				
			||||||
 | 
								this.finished(PlayerStates.IDLE);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if(Input.isPressed("run")){
 | 
				
			||||||
 | 
									this.finished(PlayerStates.RUN);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.parent.velocity.x = dir.x * this.parent.speed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.emitter.fireEvent(HW4_Events.PLAYER_MOVE, {position: this.owner.position.clone()});
 | 
				
			||||||
 | 
							this.owner.move(this.parent.velocity.scaled(deltaT));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						onExit(): Record<string, any> {
 | 
				
			||||||
 | 
							this.owner.animation.stop();
 | 
				
			||||||
 | 
							return {};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										362
									
								
								src/Homework4/Scenes/GameLevel.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										362
									
								
								src/Homework4/Scenes/GameLevel.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,362 @@
 | 
				
			||||||
 | 
					import Vec2 from "../../Wolfie2D/DataTypes/Vec2";
 | 
				
			||||||
 | 
					import Input from "../../Wolfie2D/Input/Input";
 | 
				
			||||||
 | 
					import { TweenableProperties } from "../../Wolfie2D/Nodes/GameNode";
 | 
				
			||||||
 | 
					import { GraphicType } from "../../Wolfie2D/Nodes/Graphics/GraphicTypes";
 | 
				
			||||||
 | 
					import Rect from "../../Wolfie2D/Nodes/Graphics/Rect";
 | 
				
			||||||
 | 
					import AnimatedSprite from "../../Wolfie2D/Nodes/Sprites/AnimatedSprite";
 | 
				
			||||||
 | 
					import Label from "../../Wolfie2D/Nodes/UIElements/Label";
 | 
				
			||||||
 | 
					import { UIElementType } from "../../Wolfie2D/Nodes/UIElements/UIElementTypes";
 | 
				
			||||||
 | 
					import Scene from "../../Wolfie2D/Scene/Scene";
 | 
				
			||||||
 | 
					import Timer from "../../Wolfie2D/Timing/Timer";
 | 
				
			||||||
 | 
					import Color from "../../Wolfie2D/Utils/Color";
 | 
				
			||||||
 | 
					import { EaseFunctionType } from "../../Wolfie2D/Utils/EaseFunctions";
 | 
				
			||||||
 | 
					import EnemyController from "../Enemies/EnemyController";
 | 
				
			||||||
 | 
					import { HW4_Events } from "../hw4_enums";
 | 
				
			||||||
 | 
					import PlayerController from "../Player/PlayerController";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class GameLevel extends Scene {
 | 
				
			||||||
 | 
					    // Every level will have a player, which will be an animated sprite
 | 
				
			||||||
 | 
					    protected playerSpawn: Vec2;
 | 
				
			||||||
 | 
					    protected player: AnimatedSprite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Labels for the UI
 | 
				
			||||||
 | 
					    protected static coinCount: number = 0;
 | 
				
			||||||
 | 
					    protected coinCountLabel: Label;
 | 
				
			||||||
 | 
					    protected static livesCount: number = 3;
 | 
				
			||||||
 | 
					    protected livesCountLabel: Label;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Stuff to end the level and go to the next level
 | 
				
			||||||
 | 
					    protected levelEndArea: Rect;
 | 
				
			||||||
 | 
					    protected nextLevel: new (...args: any) => GameLevel;
 | 
				
			||||||
 | 
					    protected levelEndTimer: Timer;
 | 
				
			||||||
 | 
					    protected levelEndLabel: Label;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Screen fade in/out for level start and end
 | 
				
			||||||
 | 
					    protected levelTransitionTimer: Timer;
 | 
				
			||||||
 | 
					    protected levelTransitionScreen: Rect;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    startScene(): void {
 | 
				
			||||||
 | 
					        // Do the game level standard initializations
 | 
				
			||||||
 | 
					        this.initLayers();
 | 
				
			||||||
 | 
					        this.initViewport();
 | 
				
			||||||
 | 
					        this.initPlayer();
 | 
				
			||||||
 | 
					        this.subscribeToEvents();
 | 
				
			||||||
 | 
					        this.addUI();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Initialize the timers
 | 
				
			||||||
 | 
					        this.levelTransitionTimer = new Timer(500);
 | 
				
			||||||
 | 
					        this.levelEndTimer = new Timer(3000, () => {
 | 
				
			||||||
 | 
					            // After the level end timer ends, fade to black and then go to the next scene
 | 
				
			||||||
 | 
					            this.levelTransitionScreen.tweens.play("fadeIn");
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Start the black screen fade out
 | 
				
			||||||
 | 
					        this.levelTransitionScreen.tweens.play("fadeOut");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Initially disable player movement
 | 
				
			||||||
 | 
					        Input.disableInput();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    updateScene(deltaT: number){
 | 
				
			||||||
 | 
					        // Handle events and update the UI if needed
 | 
				
			||||||
 | 
					        while(this.receiver.hasNextEvent()){
 | 
				
			||||||
 | 
					            let event = this.receiver.getNextEvent();
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            switch(event.type){
 | 
				
			||||||
 | 
					                case HW4_Events.PLAYER_HIT_COIN:
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        // Hit a coin
 | 
				
			||||||
 | 
					                        let coin;
 | 
				
			||||||
 | 
					                        if(event.data.get("node") === this.player.id){
 | 
				
			||||||
 | 
					                            // Other is coin, disable
 | 
				
			||||||
 | 
					                            coin = this.sceneGraph.getNode(event.data.get("other"));
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            // Node is coin, disable
 | 
				
			||||||
 | 
					                            coin = this.sceneGraph.getNode(event.data.get("node"));
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        
 | 
				
			||||||
 | 
					                        // Remove from physics and scene
 | 
				
			||||||
 | 
					                        coin.active = false;
 | 
				
			||||||
 | 
					                        coin.visible = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        // Increment our number of coins
 | 
				
			||||||
 | 
					                        this.incPlayerCoins(1);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                case HW4_Events.PLAYER_HIT_COIN_BLOCK:
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        // Hit a coin block, so increment our number of coins
 | 
				
			||||||
 | 
					                        this.incPlayerCoins(1);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                case HW4_Events.PLAYER_HIT_ENEMY:
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        let node = this.sceneGraph.getNode(event.data.get("node"));
 | 
				
			||||||
 | 
					                        let other = this.sceneGraph.getNode(event.data.get("other"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if(node === this.player){
 | 
				
			||||||
 | 
					                            // Node is player, other is enemy
 | 
				
			||||||
 | 
					                            this.handlePlayerEnemyCollision(<AnimatedSprite>node, <AnimatedSprite>other);
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            // Other is player, node is enemy
 | 
				
			||||||
 | 
					                            this.handlePlayerEnemyCollision(<AnimatedSprite>other,<AnimatedSprite>node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                case HW4_Events.ENEMY_DIED:
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        // An enemy finished its dying animation, hide it
 | 
				
			||||||
 | 
					                        let node = this.sceneGraph.getNode(event.data.get("owner"));
 | 
				
			||||||
 | 
					                        node.visible = false;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                case HW4_Events.PLAYER_ENTERED_LEVEL_END:
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if(!this.levelEndTimer.hasRun() && this.levelEndTimer.isStopped()){
 | 
				
			||||||
 | 
					                            // The player has reached the end of the level
 | 
				
			||||||
 | 
					                            this.levelEndTimer.start();
 | 
				
			||||||
 | 
					                            this.levelEndLabel.tweens.play("slideIn");
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                case HW4_Events.LEVEL_START:
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        // Re-enable controls
 | 
				
			||||||
 | 
					                        console.log("Enabling input");
 | 
				
			||||||
 | 
					                        Input.enableInput();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                case HW4_Events.LEVEL_END:
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        // Go to the next level
 | 
				
			||||||
 | 
					                        if(this.nextLevel){
 | 
				
			||||||
 | 
					                            console.log("Going to next level!");
 | 
				
			||||||
 | 
					                            let sceneOptions = {
 | 
				
			||||||
 | 
					                                physics: {
 | 
				
			||||||
 | 
					                                    groupNames: ["ground", "player", "enemy", "coin"],
 | 
				
			||||||
 | 
					                                    collisions:
 | 
				
			||||||
 | 
					                                    [
 | 
				
			||||||
 | 
					                                        [0, 1, 1, 0],
 | 
				
			||||||
 | 
					                                        [1, 0, 0, 1],
 | 
				
			||||||
 | 
					                                        [1, 0, 0, 0],
 | 
				
			||||||
 | 
					                                        [0, 1, 0, 0]
 | 
				
			||||||
 | 
					                                    ]
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            this.sceneManager.changeToScene(this.nextLevel, {}, sceneOptions);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // If player falls into a pit, kill them off and reset their position
 | 
				
			||||||
 | 
					        if(this.player.position.y > 100*64){
 | 
				
			||||||
 | 
					            this.incPlayerLife(-1);
 | 
				
			||||||
 | 
					            this.respawnPlayer();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected initLayers(): void {
 | 
				
			||||||
 | 
					        // Add a layer behind the tilemap for coinblock animation
 | 
				
			||||||
 | 
					        this.addLayer("coinLayer", -50);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add a layer for UI
 | 
				
			||||||
 | 
					        this.addUILayer("UI");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add a layer for players and enemies
 | 
				
			||||||
 | 
					        this.addLayer("primary", 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected initViewport(): void {
 | 
				
			||||||
 | 
					        this.viewport.enableZoom();
 | 
				
			||||||
 | 
					        this.viewport.setZoomLevel(2);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected subscribeToEvents(){
 | 
				
			||||||
 | 
					        this.receiver.subscribe([
 | 
				
			||||||
 | 
					            HW4_Events.PLAYER_HIT_COIN,
 | 
				
			||||||
 | 
					            HW4_Events.PLAYER_HIT_COIN_BLOCK,
 | 
				
			||||||
 | 
					            HW4_Events.PLAYER_HIT_ENEMY,
 | 
				
			||||||
 | 
					            HW4_Events.ENEMY_DIED,
 | 
				
			||||||
 | 
					            HW4_Events.PLAYER_ENTERED_LEVEL_END,
 | 
				
			||||||
 | 
					            HW4_Events.LEVEL_START,
 | 
				
			||||||
 | 
					            HW4_Events.LEVEL_END
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected addUI(){
 | 
				
			||||||
 | 
					        // In-game labels
 | 
				
			||||||
 | 
					        this.coinCountLabel = <Label>this.add.uiElement(UIElementType.LABEL, "UI", {position: new Vec2(80, 30), text: "Coins: " + GameLevel.coinCount});
 | 
				
			||||||
 | 
					        this.coinCountLabel.textColor = Color.WHITE
 | 
				
			||||||
 | 
					        this.coinCountLabel.font = "NoPixel";
 | 
				
			||||||
 | 
					        this.livesCountLabel = <Label>this.add.uiElement(UIElementType.LABEL, "UI", {position: new Vec2(500, 30), text: "Lives: " + GameLevel.livesCount});
 | 
				
			||||||
 | 
					        this.livesCountLabel.textColor = Color.WHITE
 | 
				
			||||||
 | 
					        this.livesCountLabel.font = "NoPixel";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // End of level label (start off screen)
 | 
				
			||||||
 | 
					        this.levelEndLabel = <Label>this.add.uiElement(UIElementType.LABEL, "UI", {position: new Vec2(-300, 200), text: "Level Complete"});
 | 
				
			||||||
 | 
					        this.levelEndLabel.size.set(1200, 60);
 | 
				
			||||||
 | 
					        this.levelEndLabel.borderRadius = 0;
 | 
				
			||||||
 | 
					        this.levelEndLabel.backgroundColor = new Color(34, 32, 52);
 | 
				
			||||||
 | 
					        this.levelEndLabel.textColor = Color.WHITE;
 | 
				
			||||||
 | 
					        this.levelEndLabel.fontSize = 48;
 | 
				
			||||||
 | 
					        this.levelEndLabel.font = "NoPixel";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add a tween to move the label on screen
 | 
				
			||||||
 | 
					        this.levelEndLabel.tweens.add("slideIn", {
 | 
				
			||||||
 | 
					            startDelay: 0,
 | 
				
			||||||
 | 
					            duration: 1000,
 | 
				
			||||||
 | 
					            effects: [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    property: TweenableProperties.posX,
 | 
				
			||||||
 | 
					                    start: -300,
 | 
				
			||||||
 | 
					                    end: 300,
 | 
				
			||||||
 | 
					                    ease: EaseFunctionType.OUT_SINE
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.levelTransitionScreen = <Rect>this.add.graphic(GraphicType.RECT, "UI", {position: new Vec2(300, 200), size: new Vec2(600, 400)});
 | 
				
			||||||
 | 
					        this.levelTransitionScreen.color = new Color(34, 32, 52);
 | 
				
			||||||
 | 
					        this.levelTransitionScreen.alpha = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.levelTransitionScreen.tweens.add("fadeIn", {
 | 
				
			||||||
 | 
					            startDelay: 0,
 | 
				
			||||||
 | 
					            duration: 1000,
 | 
				
			||||||
 | 
					            effects: [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    property: TweenableProperties.alpha,
 | 
				
			||||||
 | 
					                    start: 0,
 | 
				
			||||||
 | 
					                    end: 1,
 | 
				
			||||||
 | 
					                    ease: EaseFunctionType.IN_OUT_QUAD
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            onEnd: HW4_Events.LEVEL_END
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.levelTransitionScreen.tweens.add("fadeOut", {
 | 
				
			||||||
 | 
					            startDelay: 0,
 | 
				
			||||||
 | 
					            duration: 1000,
 | 
				
			||||||
 | 
					            effects: [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    property: TweenableProperties.alpha,
 | 
				
			||||||
 | 
					                    start: 1,
 | 
				
			||||||
 | 
					                    end: 0,
 | 
				
			||||||
 | 
					                    ease: EaseFunctionType.IN_OUT_QUAD
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            onEnd: HW4_Events.LEVEL_START
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected initPlayer(): void {
 | 
				
			||||||
 | 
					        // Add the player
 | 
				
			||||||
 | 
					        this.player = this.add.animatedSprite("player", "primary");
 | 
				
			||||||
 | 
					        this.player.scale.set(2, 2);
 | 
				
			||||||
 | 
					        if(!this.playerSpawn){
 | 
				
			||||||
 | 
					            console.warn("Player spawn was never set - setting spawn to (0, 0)");
 | 
				
			||||||
 | 
					            this.playerSpawn = Vec2.ZERO;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.player.position.copy(this.playerSpawn);
 | 
				
			||||||
 | 
					        this.player.addPhysics();
 | 
				
			||||||
 | 
					        this.player.addAI(PlayerController, {playerType: "platformer", tilemap: "Main"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add triggers on colliding with coins or coinBlocks
 | 
				
			||||||
 | 
					        this.player.setGroup("player");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add a tween animation for the player jump
 | 
				
			||||||
 | 
					        this.player.tweens.add("flip", {
 | 
				
			||||||
 | 
					            startDelay: 0,
 | 
				
			||||||
 | 
					            duration: 500,
 | 
				
			||||||
 | 
					            effects: [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    property: "rotation",
 | 
				
			||||||
 | 
					                    start: 0,
 | 
				
			||||||
 | 
					                    end: 2*Math.PI,
 | 
				
			||||||
 | 
					                    ease: EaseFunctionType.IN_OUT_QUAD
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.viewport.follow(this.player);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected addLevelEnd(startingTile: Vec2, size: Vec2): void {
 | 
				
			||||||
 | 
					        this.levelEndArea = <Rect>this.add.graphic(GraphicType.RECT, "primary", {position: startingTile.add(size.scaled(0.5)).scale(32), size: size.scale(32)});
 | 
				
			||||||
 | 
					        this.levelEndArea.addPhysics(undefined, undefined, false, true);
 | 
				
			||||||
 | 
					        this.levelEndArea.setTrigger("player", HW4_Events.PLAYER_ENTERED_LEVEL_END, null);
 | 
				
			||||||
 | 
					        this.levelEndArea.color = new Color(0, 0, 0, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected addEnemy(spriteKey: string, tilePos: Vec2, aiOptions: Record<string, any>): void {
 | 
				
			||||||
 | 
					        let enemy = this.add.animatedSprite(spriteKey, "primary");
 | 
				
			||||||
 | 
					        enemy.position.set(tilePos.x*32, tilePos.y*32);
 | 
				
			||||||
 | 
					        enemy.scale.set(2, 2);
 | 
				
			||||||
 | 
					        enemy.addPhysics();
 | 
				
			||||||
 | 
					        enemy.addAI(EnemyController, aiOptions);
 | 
				
			||||||
 | 
					        enemy.setGroup("enemy");
 | 
				
			||||||
 | 
					        enemy.setTrigger("player", HW4_Events.PLAYER_HIT_ENEMY, null);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected handlePlayerEnemyCollision(player: AnimatedSprite, enemy: AnimatedSprite) {
 | 
				
			||||||
 | 
					        // Get the vector of the direction from the player to the enemy
 | 
				
			||||||
 | 
					        let dir = player.position.dirTo(enemy.position);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if((<EnemyController>enemy.ai).jumpy){
 | 
				
			||||||
 | 
					            // If it's a jumpy enemy, we want to hit it from the bottom
 | 
				
			||||||
 | 
					            if(dir.dot(Vec2.UP) > 0.5){
 | 
				
			||||||
 | 
					                enemy.disablePhysics();
 | 
				
			||||||
 | 
					                enemy.tweens.stopAll();
 | 
				
			||||||
 | 
					                enemy.animation.play("DYING", false, HW4_Events.ENEMY_DIED);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Stop the player's jump for some feedback
 | 
				
			||||||
 | 
					                (<PlayerController>player.ai).velocity.y = 0;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                this.incPlayerLife(-1);
 | 
				
			||||||
 | 
					                this.respawnPlayer();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // If not, we want to hit it from the top
 | 
				
			||||||
 | 
					            if(dir.dot(Vec2.DOWN) > 0.5){
 | 
				
			||||||
 | 
					                enemy.disablePhysics();
 | 
				
			||||||
 | 
					                enemy.animation.play("DYING", false, HW4_Events.ENEMY_DIED);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Give the player a slight jump boost
 | 
				
			||||||
 | 
					                let playerVel = (<PlayerController>player.ai).velocity;
 | 
				
			||||||
 | 
					                if(playerVel.y < 0){
 | 
				
			||||||
 | 
					                    // We're going up - unlikely, but still check
 | 
				
			||||||
 | 
					                    playerVel.y += 0.2*(<PlayerController>player.ai).velocity.y;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    // We're going down, invert our bounce, but dampen it
 | 
				
			||||||
 | 
					                    playerVel.y = -0.5 * (<PlayerController>player.ai).velocity.y;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                this.incPlayerLife(-1);
 | 
				
			||||||
 | 
					                this.respawnPlayer();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected incPlayerLife(amt: number): void {
 | 
				
			||||||
 | 
					        GameLevel.livesCount += amt;
 | 
				
			||||||
 | 
					        this.livesCountLabel.text = "Lives: " + GameLevel.livesCount;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected incPlayerCoins(amt: number): void {
 | 
				
			||||||
 | 
					        GameLevel.coinCount += amt;
 | 
				
			||||||
 | 
					        this.coinCountLabel.text = "Coins: " + GameLevel.coinCount;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected respawnPlayer(): void {
 | 
				
			||||||
 | 
					        this.player.position.copy(this.playerSpawn);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										51
									
								
								src/Homework4/Scenes/Level1.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/Homework4/Scenes/Level1.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,51 @@
 | 
				
			||||||
 | 
					import Vec2 from "../../Wolfie2D/DataTypes/Vec2";
 | 
				
			||||||
 | 
					import Debug from "../../Wolfie2D/Debug/Debug";
 | 
				
			||||||
 | 
					import GameLevel from "./GameLevel";
 | 
				
			||||||
 | 
					import Level2 from "./Level2";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class Level1 extends GameLevel {
 | 
				
			||||||
 | 
					    loadScene(): void {
 | 
				
			||||||
 | 
					        this.load.image("background", "hw4_assets/sprites/2bitbackground.png");
 | 
				
			||||||
 | 
					        this.load.image("coin", "hw4_assets/sprites/coin.png");
 | 
				
			||||||
 | 
					        this.load.tilemap("level1", "hw4_assets/tilemaps/level1.json");
 | 
				
			||||||
 | 
					        this.load.spritesheet("player", "hw4_assets/spritesheets/platformPlayer.json");
 | 
				
			||||||
 | 
					        this.load.spritesheet("hopper", "hw4_assets/spritesheets/hopper.json");
 | 
				
			||||||
 | 
					        this.load.spritesheet("bunny", "hw4_assets/spritesheets/ghostBunny.json");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    startScene(): void {
 | 
				
			||||||
 | 
					        // Add a background layer and set the background image on it
 | 
				
			||||||
 | 
					        this.addParallaxLayer("bg", new Vec2(0.25, 0), -100);
 | 
				
			||||||
 | 
					        let bg = this.add.sprite("background", "bg");
 | 
				
			||||||
 | 
					        bg.scale.set(2, 2);
 | 
				
			||||||
 | 
					        bg.position.set(bg.boundary.halfSize.x, 76);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add the level 1 tilemap
 | 
				
			||||||
 | 
					        this.add.tilemap("level1", new Vec2(2, 2));
 | 
				
			||||||
 | 
					        this.viewport.setBounds(0, 0, 64*32, 20*32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.playerSpawn = new Vec2(5*32, 18*32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Do generic setup for a GameLevel
 | 
				
			||||||
 | 
					        super.startScene();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.addLevelEnd(new Vec2(58, 17), new Vec2(2, 2));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.nextLevel = Level2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add enemies of various types
 | 
				
			||||||
 | 
					        for(let pos of [new Vec2(24, 18)]){
 | 
				
			||||||
 | 
					            this.addEnemy("bunny", pos, {});
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(let pos of [new Vec2(51, 17)]){
 | 
				
			||||||
 | 
					            this.addEnemy("hopper", pos, {jumpy: true});
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    updateScene(deltaT: number): void {
 | 
				
			||||||
 | 
					        super.updateScene(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Debug.log("playerpos", this.player.position.toString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										49
									
								
								src/Homework4/Scenes/Level2.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/Homework4/Scenes/Level2.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,49 @@
 | 
				
			||||||
 | 
					import Vec2 from "../../Wolfie2D/DataTypes/Vec2";
 | 
				
			||||||
 | 
					import Debug from "../../Wolfie2D/Debug/Debug";
 | 
				
			||||||
 | 
					import GameLevel from "./GameLevel";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class Level2 extends GameLevel {
 | 
				
			||||||
 | 
					    loadScene(): void {
 | 
				
			||||||
 | 
					        this.load.image("background", "hw4_assets/sprites/2bitbackground.png");
 | 
				
			||||||
 | 
					        this.load.image("coin", "hw4_assets/sprites/coin.png");
 | 
				
			||||||
 | 
					        this.load.tilemap("level2", "hw4_assets/tilemaps/level2.json");
 | 
				
			||||||
 | 
					        this.load.spritesheet("player", "hw4_assets/spritesheets/platformPlayer.json");
 | 
				
			||||||
 | 
					        this.load.spritesheet("hopper", "hw4_assets/spritesheets/hopper.json");
 | 
				
			||||||
 | 
					        this.load.spritesheet("bunny", "hw4_assets/spritesheets/ghostBunny.json");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    startScene(): void {
 | 
				
			||||||
 | 
					        console.log("Starting level2");
 | 
				
			||||||
 | 
					        // Add a background layer and set the background image on it
 | 
				
			||||||
 | 
					        this.addParallaxLayer("bg", new Vec2(0.25, 0), -100);
 | 
				
			||||||
 | 
					        let bg = this.add.sprite("background", "bg");
 | 
				
			||||||
 | 
					        bg.scale.set(2, 2);
 | 
				
			||||||
 | 
					        bg.position.set(bg.boundary.halfSize.x, 96);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add the level 1 tilemap
 | 
				
			||||||
 | 
					        this.add.tilemap("level2", new Vec2(2, 2));
 | 
				
			||||||
 | 
					        this.viewport.setBounds(0, 0, 64*32, 20*32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.playerSpawn = new Vec2(5*32, 18*32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Do generic setup for a GameLevel
 | 
				
			||||||
 | 
					        super.startScene();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.addLevelEnd(new Vec2(58, 17), new Vec2(2, 2));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add enemies of various types
 | 
				
			||||||
 | 
					        for(let pos of [new Vec2(24, 18)]){
 | 
				
			||||||
 | 
					            this.addEnemy("bunny", pos, {});
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(let pos of [new Vec2(51, 17)]){
 | 
				
			||||||
 | 
					            this.addEnemy("hopper", pos, {jumpy: true});
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    updateScene(deltaT: number): void {
 | 
				
			||||||
 | 
					        super.updateScene(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Debug.log("playerpos", this.player.position.toString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										63
									
								
								src/Homework4/Scenes/MainMenu.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/Homework4/Scenes/MainMenu.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,63 @@
 | 
				
			||||||
 | 
					import Vec2 from "../../Wolfie2D/DataTypes/Vec2";
 | 
				
			||||||
 | 
					import AnimatedSprite from "../../Wolfie2D/Nodes/Sprites/AnimatedSprite";
 | 
				
			||||||
 | 
					import Button from "../../Wolfie2D/Nodes/UIElements/Button";
 | 
				
			||||||
 | 
					import { UIElementType } from "../../Wolfie2D/Nodes/UIElements/UIElementTypes";
 | 
				
			||||||
 | 
					import Scene from "../../Wolfie2D/Scene/Scene";
 | 
				
			||||||
 | 
					import Color from "../../Wolfie2D/Utils/Color";
 | 
				
			||||||
 | 
					import Level1 from "./Level1";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class MainMenu extends Scene {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    animatedSprite: AnimatedSprite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loadScene(): void {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    startScene(): void {
 | 
				
			||||||
 | 
					        this.addUILayer("Main");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let size = this.viewport.getHalfSize();
 | 
				
			||||||
 | 
					        this.viewport.setFocus(size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let playBtn = <Button>this.add.uiElement(UIElementType.BUTTON, "Main", {position: new Vec2(size.x, size.y), text: "Play Game"});
 | 
				
			||||||
 | 
					        playBtn.setBackgroundColor(Color.GREEN);
 | 
				
			||||||
 | 
					        playBtn.setPadding(new Vec2(50, 10));
 | 
				
			||||||
 | 
					        playBtn.font = "NoPixel";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // When the play button is clicked, go to the next scene
 | 
				
			||||||
 | 
					        playBtn.onClick = () => {
 | 
				
			||||||
 | 
					            /*
 | 
				
			||||||
 | 
					                Init the next scene with physics collisions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        ground  player  enemy   coin
 | 
				
			||||||
 | 
					                ground    No      --      --     --
 | 
				
			||||||
 | 
					                player   Yes      No      --     --
 | 
				
			||||||
 | 
					                enemy    Yes      No      No     --
 | 
				
			||||||
 | 
					                coin      No     Yes      No     No
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                Each layer becomes a number. In this case, 4 bits matter for each
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                ground: self - 0001, collisions - 0110
 | 
				
			||||||
 | 
					                player: self - 0010, collisions - 1001
 | 
				
			||||||
 | 
					                enemy:  self - 0100, collisions - 0001
 | 
				
			||||||
 | 
					                coin:   self - 1000, collisions - 0010
 | 
				
			||||||
 | 
					            */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let sceneOptions = {
 | 
				
			||||||
 | 
					                physics: {
 | 
				
			||||||
 | 
					                    groupNames: ["ground", "player", "enemy", "coin"],
 | 
				
			||||||
 | 
					                    collisions:
 | 
				
			||||||
 | 
					                    [
 | 
				
			||||||
 | 
					                        [0, 1, 1, 0],
 | 
				
			||||||
 | 
					                        [1, 0, 0, 1],
 | 
				
			||||||
 | 
					                        [1, 0, 0, 0],
 | 
				
			||||||
 | 
					                        [0, 1, 0, 0]
 | 
				
			||||||
 | 
					                    ]
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            this.sceneManager.changeToScene(Level1, {}, sceneOptions);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    updateScene(): void {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/Homework4/hw4_enums.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/Homework4/hw4_enums.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					export enum HW4_Events {
 | 
				
			||||||
 | 
					    PLAYER_MOVE = "PlayerMove",
 | 
				
			||||||
 | 
					    PLAYER_JUMP = "PlayerJump",
 | 
				
			||||||
 | 
					    PLAYER_HIT_COIN = "PlayerHitCoin",
 | 
				
			||||||
 | 
					    PLAYER_HIT_COIN_BLOCK = "PlayerHitCoinBlock",
 | 
				
			||||||
 | 
					    PLAYER_HIT_ENEMY = "PlayerHitEnemy",
 | 
				
			||||||
 | 
					    ENEMY_DIED = "EnemyDied",
 | 
				
			||||||
 | 
					    PLAYER_ENTERED_LEVEL_END = "PlayerEnteredLevelEnd",
 | 
				
			||||||
 | 
					    LEVEL_START = "LevelStart",
 | 
				
			||||||
 | 
					    LEVEL_END = "LevelEnd",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -23,10 +23,17 @@ export default class AIManager implements Updateable {
 | 
				
			||||||
	 * @param actor The actor to register
 | 
						 * @param actor The actor to register
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	registerActor(actor: Actor): void {
 | 
						registerActor(actor: Actor): void {
 | 
				
			||||||
		actor.actorId = this.actors.length;
 | 
					 | 
				
			||||||
		this.actors.push(actor);
 | 
							this.actors.push(actor);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						removeActor(actor: Actor): void {
 | 
				
			||||||
 | 
							let index = this.actors.indexOf(actor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(index !== -1){
 | 
				
			||||||
 | 
								this.actors.splice(index, 1);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Registers an AI with the AIManager for use later on
 | 
						 * Registers an AI with the AIManager for use later on
 | 
				
			||||||
	 * @param name The name of the AI to register
 | 
						 * @param name The name of the AI to register
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										21
									
								
								src/Wolfie2D/AI/ControllerAI.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/Wolfie2D/AI/ControllerAI.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					import AI from "../DataTypes/Interfaces/AI";
 | 
				
			||||||
 | 
					import GameEvent from "../Events/GameEvent";
 | 
				
			||||||
 | 
					import GameNode from "../Nodes/GameNode";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default abstract class ControllerAI implements AI {
 | 
				
			||||||
 | 
					    /** The owner of this controller */
 | 
				
			||||||
 | 
					    owner: GameNode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Removes the instance of the owner of this AI */
 | 
				
			||||||
 | 
					    destroy(): void {
 | 
				
			||||||
 | 
					        delete this.owner;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    abstract initializeAI(owner: GameNode, options: Record<string, any>): void; 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    abstract activate(options: Record<string, any>): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    abstract handleEvent(event: GameEvent): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    abstract update(deltaT: number): void;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -13,5 +13,12 @@ export default class StateMachineAI extends StateMachine implements AI {
 | 
				
			||||||
	// @implemented
 | 
						// @implemented
 | 
				
			||||||
	initializeAI(owner: GameNode, config: Record<string, any>): void {}
 | 
						initializeAI(owner: GameNode, config: Record<string, any>): void {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// @implemented
 | 
				
			||||||
 | 
						destroy(){
 | 
				
			||||||
 | 
							// Get rid of our reference to the owner
 | 
				
			||||||
 | 
							delete this.owner;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// @implemented
 | 
				
			||||||
	activate(options: Record<string, any>): void {}
 | 
						activate(options: Record<string, any>): void {}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,5 @@
 | 
				
			||||||
import GameEvent from "../../Events/GameEvent";
 | 
					import GameEvent from "../../Events/GameEvent";
 | 
				
			||||||
import GameNode from "../../Nodes/GameNode";
 | 
					import GameNode from "../../Nodes/GameNode";
 | 
				
			||||||
import Actor from "./Actor";
 | 
					 | 
				
			||||||
import Updateable from "./Updateable";
 | 
					import Updateable from "./Updateable";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -10,6 +9,9 @@ export default interface AI extends Updateable {
 | 
				
			||||||
    /** Initializes the AI with the actor and any additional config */
 | 
					    /** Initializes the AI with the actor and any additional config */
 | 
				
			||||||
    initializeAI(owner: GameNode, options: Record<string, any>): void;
 | 
					    initializeAI(owner: GameNode, options: Record<string, any>): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Clears references from to the owner */
 | 
				
			||||||
 | 
					    destroy(): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** Activates this AI from a stopped state and allows variables to be passed in */
 | 
					    /** Activates this AI from a stopped state and allows variables to be passed in */
 | 
				
			||||||
    activate(options: Record<string, any>): void;
 | 
					    activate(options: Record<string, any>): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,9 +11,6 @@ export default interface Actor {
 | 
				
			||||||
    /** The activity status of the actor */
 | 
					    /** The activity status of the actor */
 | 
				
			||||||
    aiActive: boolean;
 | 
					    aiActive: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** The id of the actor according to the @reference[AIManager] */
 | 
					 | 
				
			||||||
    actorId: number;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** The path that navigation will follow */
 | 
					    /** The path that navigation will follow */
 | 
				
			||||||
    path: NavigationPath;
 | 
					    path: NavigationPath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,11 +40,14 @@ export default interface Physical {
 | 
				
			||||||
    /** Represnts whether this object is a trigger or not. */
 | 
					    /** Represnts whether this object is a trigger or not. */
 | 
				
			||||||
    isTrigger: boolean;
 | 
					    isTrigger: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** The physics group of this object. Used for triggers and for selective collisions. */
 | 
					    /** The trigger mask for this node */
 | 
				
			||||||
    group: string;
 | 
					    triggerMask: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** Associates different groups with trigger events. */
 | 
					    /** Events to trigger for collision enters. */
 | 
				
			||||||
    triggers: Map<string>;
 | 
					    triggerEnters: Array<string>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Events to trigger for collision exits */
 | 
				
			||||||
 | 
					    triggerExits: Array<string>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** A vector that allows velocity to be passed to the physics engine */
 | 
					    /** A vector that allows velocity to be passed to the physics engine */
 | 
				
			||||||
    _velocity: Vec2;
 | 
					    _velocity: Vec2;
 | 
				
			||||||
| 
						 | 
					@ -55,8 +58,8 @@ export default interface Physical {
 | 
				
			||||||
    /** A boolean representing whether or not the node just collided with the tilemap */
 | 
					    /** A boolean representing whether or not the node just collided with the tilemap */
 | 
				
			||||||
    collidedWithTilemap: boolean;
 | 
					    collidedWithTilemap: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** The physics layer this node belongs to */
 | 
					    /** The physics group this node belongs to */
 | 
				
			||||||
    physicsLayer: number;
 | 
					    group: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    isPlayer: boolean;
 | 
					    isPlayer: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,18 +87,28 @@ export default interface Physical {
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    addPhysics(collisionShape?: Shape, colliderOffset?: Vec2, isCollidable?: boolean, isStatic?: boolean): void;
 | 
					    addPhysics(collisionShape?: Shape, colliderOffset?: Vec2, isCollidable?: boolean, isStatic?: boolean): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /** Removes this object from the physics system */
 | 
				
			||||||
     * Adds a trigger to this object for a specific group
 | 
					    removePhysics(): void;
 | 
				
			||||||
     * @param group The name of the group that activates the trigger
 | 
					
 | 
				
			||||||
     * @param eventType The name of the event to send when this trigger is activated
 | 
					    /** Prevents this object from participating in all collisions and triggers. It can still move. */
 | 
				
			||||||
     */
 | 
					    disablePhysics(): void;
 | 
				
			||||||
    addTrigger(group: string, eventType: string): void;
 | 
					
 | 
				
			||||||
 | 
					    /** Enables this object to participate in collisions and triggers. This is only necessary if disablePhysics was called */
 | 
				
			||||||
 | 
					    enablePhysics(): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Sets the physics layer of this node
 | 
					     * Sets this object to be a trigger for a specific group
 | 
				
			||||||
     * @param layer The name of the layer
 | 
					     * @param group The name of the group that activates the trigger
 | 
				
			||||||
 | 
					     * @param onEnter The name of the event to send when this trigger is activated
 | 
				
			||||||
 | 
					     * @param onExit The name of the event to send when this trigger stops being activated
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    setPhysicsLayer(layer: string): void;
 | 
					    setTrigger(group: string, onEnter: string, onExit: string): void;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Sets the physics group of this node
 | 
				
			||||||
 | 
					     * @param group The name of the group
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    setGroup(group: string): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * If used before "move()", it will tell you the velocity of the node after its last movement
 | 
					     * If used before "move()", it will tell you the velocity of the node after its last movement
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										63
									
								
								src/Wolfie2D/DataTypes/List.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/Wolfie2D/DataTypes/List.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,63 @@
 | 
				
			||||||
 | 
					import Collection from "./Collection";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A doubly linked list
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export default class List<T> implements Collection {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private head: ListItem<T>;
 | 
				
			||||||
 | 
					    private tail: ListItem<T>;
 | 
				
			||||||
 | 
					    private _size: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(){
 | 
				
			||||||
 | 
					        this.head = null;
 | 
				
			||||||
 | 
					        this.tail = null;
 | 
				
			||||||
 | 
					        this._size = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get size(): number {
 | 
				
			||||||
 | 
					        return this._size;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    add(value: T){
 | 
				
			||||||
 | 
					        if(this._size === 0){
 | 
				
			||||||
 | 
					            // There were no items in the list previously, so head and tail are the same
 | 
				
			||||||
 | 
					            this.head = new ListItem(value, null, null);
 | 
				
			||||||
 | 
					            this.tail = this.head;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            this.tail.next = new ListItem(value, this.tail, null);
 | 
				
			||||||
 | 
					            this.tail = this.tail.next;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Increment the size
 | 
				
			||||||
 | 
					        this._size += 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    forEach(func: Function): void {
 | 
				
			||||||
 | 
					        let p = this.head;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while(p !== null){
 | 
				
			||||||
 | 
					            func(p.value);
 | 
				
			||||||
 | 
					            p = p.next;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    clear(): void {
 | 
				
			||||||
 | 
					        this.head = null
 | 
				
			||||||
 | 
					        this.tail = null
 | 
				
			||||||
 | 
					        this._size = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ListItem<T> {
 | 
				
			||||||
 | 
					    value: T;
 | 
				
			||||||
 | 
					    next: ListItem<T>;
 | 
				
			||||||
 | 
					    prev: ListItem<T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(value: T, next: ListItem<T>, prev: ListItem<T>){
 | 
				
			||||||
 | 
					        this.value = value;
 | 
				
			||||||
 | 
					        this.next = next;
 | 
				
			||||||
 | 
					        this.prev = prev;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -43,7 +43,6 @@ export default abstract class State implements Updateable {
 | 
				
			||||||
     * @param stateName The name of the state to transition to
 | 
					     * @param stateName The name of the state to transition to
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    protected finished(stateName: string): void {
 | 
					    protected finished(stateName: string): void {
 | 
				
			||||||
        console.log("Finished");
 | 
					 | 
				
			||||||
        this.parent.changeState(stateName);
 | 
					        this.parent.changeState(stateName);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,6 +73,26 @@ export default class EventQueue {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Unsubscribes the specified receiver from all events, or from whatever events are provided
 | 
				
			||||||
 | 
					     * @param receiver The receiver to unsubscribe
 | 
				
			||||||
 | 
					     * @param keys The events to unsubscribe from. If none are provided, unsubscribe from all
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    unsubscribe(receiver: Receiver, ...events: Array<string>): void {
 | 
				
			||||||
 | 
					        this.receivers.forEach(eventName => {
 | 
				
			||||||
 | 
					            // If keys were provided, only continue if this key is one of them
 | 
				
			||||||
 | 
					            if(events !== undefined && events.indexOf(eventName) === -1) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Find the index of our receiver for this key
 | 
				
			||||||
 | 
					            let index = this.receivers.get(eventName).indexOf(receiver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // If an index was found, remove the receiver
 | 
				
			||||||
 | 
					            if(index !== -1){
 | 
				
			||||||
 | 
					                this.receivers.get(eventName).splice(index, 1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Associate the receiver and the type
 | 
					    // Associate the receiver and the type
 | 
				
			||||||
	private addListener(receiver: Receiver, type: string): void {
 | 
						private addListener(receiver: Receiver, type: string): void {
 | 
				
			||||||
		if(this.receivers.has(type)){
 | 
							if(this.receivers.has(type)){
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,12 +18,17 @@ export default class Receiver {
 | 
				
			||||||
        this.q = new Queue(this.MAX_SIZE);
 | 
					        this.q = new Queue(this.MAX_SIZE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						destroy(){
 | 
				
			||||||
 | 
							EventQueue.getInstance().unsubscribe(this);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Adds these types of events to this receiver's queue every update.
 | 
						 * Adds these types of events to this receiver's queue every update.
 | 
				
			||||||
	 * @param eventTypes The types of events this receiver will be subscribed to
 | 
						 * @param eventTypes The types of events this receiver will be subscribed to
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	subscribe(eventTypes: string | Array<string>): void {
 | 
						subscribe(eventTypes: string | Array<string>): void {
 | 
				
			||||||
		EventQueue.getInstance().subscribe(this, eventTypes);
 | 
							EventQueue.getInstance().subscribe(this, eventTypes);
 | 
				
			||||||
 | 
							this.q.clear();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,6 +28,9 @@ export default class Input {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static keyMap: Map<Array<string>>;
 | 
						private static keyMap: Map<Array<string>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static keysDisabled: boolean;
 | 
				
			||||||
 | 
						private static mouseDisabled: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Initializes the Input object
 | 
						 * Initializes the Input object
 | 
				
			||||||
	 * @param viewport A reference to the viewport of the game
 | 
						 * @param viewport A reference to the viewport of the game
 | 
				
			||||||
| 
						 | 
					@ -43,6 +46,8 @@ export default class Input {
 | 
				
			||||||
		Input.mousePressPosition = new Vec2(0, 0);
 | 
							Input.mousePressPosition = new Vec2(0, 0);
 | 
				
			||||||
		Input.scrollDirection = 0;
 | 
							Input.scrollDirection = 0;
 | 
				
			||||||
		Input.justScrolled = false;
 | 
							Input.justScrolled = false;
 | 
				
			||||||
 | 
							Input.keysDisabled = false;
 | 
				
			||||||
 | 
							Input.mouseDisabled = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Initialize the keymap
 | 
							// Initialize the keymap
 | 
				
			||||||
		Input.keyMap = new Map();
 | 
							Input.keyMap = new Map();
 | 
				
			||||||
| 
						 | 
					@ -132,6 +137,8 @@ export default class Input {
 | 
				
			||||||
	 * @returns True if the key was just pressed, false otherwise
 | 
						 * @returns True if the key was just pressed, false otherwise
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	static isKeyJustPressed(key: string): boolean {
 | 
						static isKeyJustPressed(key: string): boolean {
 | 
				
			||||||
 | 
							if(Input.keysDisabled) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if(Input.keyJustPressed.has(key)){
 | 
							if(Input.keyJustPressed.has(key)){
 | 
				
			||||||
			return Input.keyJustPressed.get(key)
 | 
								return Input.keyJustPressed.get(key)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
| 
						 | 
					@ -145,6 +152,8 @@ export default class Input {
 | 
				
			||||||
	 * @returns An array of all of the newly pressed keys.
 | 
						 * @returns An array of all of the newly pressed keys.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	static getKeysJustPressed(): Array<string> {
 | 
						static getKeysJustPressed(): Array<string> {
 | 
				
			||||||
 | 
							if(Input.keysDisabled) return [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		let keys = Array<string>();
 | 
							let keys = Array<string>();
 | 
				
			||||||
		Input.keyJustPressed.forEach(key => {
 | 
							Input.keyJustPressed.forEach(key => {
 | 
				
			||||||
			if(Input.keyJustPressed.get(key)){
 | 
								if(Input.keyJustPressed.get(key)){
 | 
				
			||||||
| 
						 | 
					@ -160,6 +169,8 @@ export default class Input {
 | 
				
			||||||
	 * @returns True if the key is currently pressed, false otherwise
 | 
						 * @returns True if the key is currently pressed, false otherwise
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	static isKeyPressed(key: string): boolean {
 | 
						static isKeyPressed(key: string): boolean {
 | 
				
			||||||
 | 
							if(Input.keysDisabled) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if(Input.keyPressed.has(key)){
 | 
							if(Input.keyPressed.has(key)){
 | 
				
			||||||
			return Input.keyPressed.get(key)
 | 
								return Input.keyPressed.get(key)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
| 
						 | 
					@ -189,6 +200,8 @@ export default class Input {
 | 
				
			||||||
	 * @returns True if the input was just pressed, false otherwise
 | 
						 * @returns True if the input was just pressed, false otherwise
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	static isJustPressed(inputName: string): boolean {
 | 
						static isJustPressed(inputName: string): boolean {
 | 
				
			||||||
 | 
							if(Input.keysDisabled) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if(Input.keyMap.has(inputName)){
 | 
							if(Input.keyMap.has(inputName)){
 | 
				
			||||||
			const keys = Input.keyMap.get(inputName);
 | 
								const keys = Input.keyMap.get(inputName);
 | 
				
			||||||
			let justPressed = false;
 | 
								let justPressed = false;
 | 
				
			||||||
| 
						 | 
					@ -209,6 +222,8 @@ export default class Input {
 | 
				
			||||||
	 * @returns True if the input is pressed, false otherwise
 | 
						 * @returns True if the input is pressed, false otherwise
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	static isPressed(inputName: string): boolean {
 | 
						static isPressed(inputName: string): boolean {
 | 
				
			||||||
 | 
							if(Input.keysDisabled) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if(Input.keyMap.has(inputName)){
 | 
							if(Input.keyMap.has(inputName)){
 | 
				
			||||||
			const keys = Input.keyMap.get(inputName);
 | 
								const keys = Input.keyMap.get(inputName);
 | 
				
			||||||
			let pressed = false;
 | 
								let pressed = false;
 | 
				
			||||||
| 
						 | 
					@ -228,7 +243,7 @@ export default class Input {
 | 
				
			||||||
	 * @returns True if the mouse was just pressed, false otherwise
 | 
						 * @returns True if the mouse was just pressed, false otherwise
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	static isMouseJustPressed(): boolean {
 | 
						static isMouseJustPressed(): boolean {
 | 
				
			||||||
		return Input.mouseJustPressed;
 | 
							return Input.mouseJustPressed && !Input.mouseDisabled;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
| 
						 | 
					@ -236,7 +251,7 @@ export default class Input {
 | 
				
			||||||
	 * @returns True if the mouse is currently pressed, false otherwise
 | 
						 * @returns True if the mouse is currently pressed, false otherwise
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	static isMousePressed(): boolean {
 | 
						static isMousePressed(): boolean {
 | 
				
			||||||
		return Input.mousePressed;
 | 
							return Input.mousePressed && !Input.mouseDisabled;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
| 
						 | 
					@ -244,7 +259,7 @@ export default class Input {
 | 
				
			||||||
	 * @returns True if the user just scrolled Input frame, false otherwise
 | 
						 * @returns True if the user just scrolled Input frame, false otherwise
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	static didJustScroll(): boolean {
 | 
						static didJustScroll(): boolean {
 | 
				
			||||||
		return Input.justScrolled;
 | 
							return Input.justScrolled && !Input.mouseDisabled;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
| 
						 | 
					@ -288,4 +303,20 @@ export default class Input {
 | 
				
			||||||
	static getGlobalMousePressPosition(): Vec2 {
 | 
						static getGlobalMousePressPosition(): Vec2 {
 | 
				
			||||||
		return Input.mousePressPosition.clone().add(Input.viewport.getOrigin());
 | 
							return Input.mousePressPosition.clone().add(Input.viewport.getOrigin());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Disables all keypress and mouse click inputs
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static disableInput(): void {
 | 
				
			||||||
 | 
							Input.keysDisabled = true;
 | 
				
			||||||
 | 
							Input.mouseDisabled = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Enables all keypress and mouse click inputs
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static enableInput(): void {
 | 
				
			||||||
 | 
							Input.keysDisabled = false;
 | 
				
			||||||
 | 
							Input.mouseDisabled = false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -46,6 +46,9 @@ export default class FixedUpdateGameLoop extends GameLoop {
 | 
				
			||||||
    /** The status of whether or not the game loop has started. */
 | 
					    /** The status of whether or not the game loop has started. */
 | 
				
			||||||
    private started: boolean;
 | 
					    private started: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** The status of whether or not the game loop is paused */
 | 
				
			||||||
 | 
					    private paused: boolean;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    /** The status of whether or not the game loop is currently running. */
 | 
					    /** The status of whether or not the game loop is currently running. */
 | 
				
			||||||
    private running: boolean;
 | 
					    private running: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,6 +68,7 @@ export default class FixedUpdateGameLoop extends GameLoop {
 | 
				
			||||||
        this.lastFpsUpdate = 0;
 | 
					        this.lastFpsUpdate = 0;
 | 
				
			||||||
        this.framesSinceLastFpsUpdate = 0;
 | 
					        this.framesSinceLastFpsUpdate = 0;
 | 
				
			||||||
        this.started = false;
 | 
					        this.started = false;
 | 
				
			||||||
 | 
					        this.paused = false;
 | 
				
			||||||
        this.running = false;
 | 
					        this.running = false;
 | 
				
			||||||
        this.numUpdateSteps = 0;
 | 
					        this.numUpdateSteps = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -125,6 +129,14 @@ export default class FixedUpdateGameLoop extends GameLoop {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pause(): void {
 | 
				
			||||||
 | 
					        this.paused = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    resume(): void {
 | 
				
			||||||
 | 
					        this.paused = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
     * The first game frame - initializes the first frame time and begins the render
 | 
					     * The first game frame - initializes the first frame time and begins the render
 | 
				
			||||||
     * @param timestamp The current time in ms
 | 
					     * @param timestamp The current time in ms
 | 
				
			||||||
| 
						 | 
					@ -167,12 +179,17 @@ export default class FixedUpdateGameLoop extends GameLoop {
 | 
				
			||||||
     * @param timestamp The current time in ms
 | 
					     * @param timestamp The current time in ms
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    protected doFrame = (timestamp: number): void => {
 | 
					    protected doFrame = (timestamp: number): void => {
 | 
				
			||||||
 | 
					        // If a pause was executed, stop doing the loop.
 | 
				
			||||||
 | 
					        if(this.paused){ 
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Request animation frame to prepare for another update or render
 | 
					        // Request animation frame to prepare for another update or render
 | 
				
			||||||
        window.requestAnimationFrame((t) => this.doFrame(t));
 | 
					        window.requestAnimationFrame((t) => this.doFrame(t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // If we are trying to render too soon, do nothing.
 | 
					        // If we are trying to render too soon, do nothing.
 | 
				
			||||||
        if(timestamp < this.lastFrameTime + this.minFrameDelay){
 | 
					        if(timestamp < this.lastFrameTime + this.minFrameDelay){
 | 
				
			||||||
            return
 | 
					            return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		// A frame is actually happening
 | 
							// A frame is actually happening
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -145,7 +145,7 @@ export default class Game {
 | 
				
			||||||
        this.resourceManager.loadResourcesFromQueue(() => {
 | 
					        this.resourceManager.loadResourcesFromQueue(() => {
 | 
				
			||||||
            // When we're done loading, start the loop
 | 
					            // When we're done loading, start the loop
 | 
				
			||||||
            console.log("Finished Preload - loading first scene");
 | 
					            console.log("Finished Preload - loading first scene");
 | 
				
			||||||
            this.sceneManager.addScene(InitialScene, options);
 | 
					            this.sceneManager.changeToScene(InitialScene, options);
 | 
				
			||||||
            this.loop.start();
 | 
					            this.loop.start();
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -155,48 +155,60 @@ export default class Game {
 | 
				
			||||||
     * @param deltaT The time sine the last update
 | 
					     * @param deltaT The time sine the last update
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    update(deltaT: number): void {
 | 
					    update(deltaT: number): void {
 | 
				
			||||||
        // Handle all events that happened since the start of the last loop
 | 
					        try{
 | 
				
			||||||
        this.eventQueue.update(deltaT);
 | 
					            // Handle all events that happened since the start of the last loop
 | 
				
			||||||
 | 
					            this.eventQueue.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Update the input data structures so game objects can see the input
 | 
					            // Update the input data structures so game objects can see the input
 | 
				
			||||||
        Input.update(deltaT);
 | 
					            Input.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Update the recording of the game
 | 
					            // Update the recording of the game
 | 
				
			||||||
        this.recorder.update(deltaT);
 | 
					            this.recorder.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Update all scenes
 | 
					            // Update all scenes
 | 
				
			||||||
        this.sceneManager.update(deltaT);
 | 
					            this.sceneManager.update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Update all sounds
 | 
					            // Update all sounds
 | 
				
			||||||
        this.audioManager.update(deltaT);
 | 
					            this.audioManager.update(deltaT);
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
        // Load or unload any resources if needed
 | 
					            // Load or unload any resources if needed
 | 
				
			||||||
        this.resourceManager.update(deltaT);
 | 
					            this.resourceManager.update(deltaT);
 | 
				
			||||||
 | 
					        } catch(e){
 | 
				
			||||||
 | 
					            this.loop.pause();
 | 
				
			||||||
 | 
					            console.warn("Uncaught Error in Update - Crashing gracefully");
 | 
				
			||||||
 | 
					            console.error(e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Clears the canvas and defers scene rendering to the sceneManager. Renders the debug canvas
 | 
					     * Clears the canvas and defers scene rendering to the sceneManager. Renders the debug canvas
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    render(): void {
 | 
					    render(): void {
 | 
				
			||||||
        // Clear the canvases
 | 
					        try{
 | 
				
			||||||
        Debug.clearCanvas();
 | 
					            // Clear the canvases
 | 
				
			||||||
 | 
					            Debug.clearCanvas();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.renderingManager.clear(this.clearColor);
 | 
					            this.renderingManager.clear(this.clearColor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.sceneManager.render();
 | 
					            this.sceneManager.render();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Hacky debug mode
 | 
					            // Hacky debug mode
 | 
				
			||||||
        if(Input.isKeyJustPressed("g")){
 | 
					            if(Input.isKeyJustPressed("g")){
 | 
				
			||||||
            this.showDebug = !this.showDebug;
 | 
					                this.showDebug = !this.showDebug;
 | 
				
			||||||
        }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Debug render
 | 
					            // Debug render
 | 
				
			||||||
        if(this.showDebug){
 | 
					            if(this.showDebug){
 | 
				
			||||||
            Debug.render();
 | 
					                Debug.render();
 | 
				
			||||||
        }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(this.showStats){
 | 
					            if(this.showStats){
 | 
				
			||||||
            Stats.render();
 | 
					                Stats.render();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch(e){
 | 
				
			||||||
 | 
					            this.loop.pause();
 | 
				
			||||||
 | 
					            console.warn("Uncaught Error in Render - Crashing gracefully");
 | 
				
			||||||
 | 
					            console.error(e);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -32,6 +32,16 @@ export default abstract class GameLoop {
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
	abstract start(): void;
 | 
						abstract start(): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Pauses the game loop, usually for an error condition.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						abstract pause(): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Resumes the game loop.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						abstract resume(): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Runs the first frame of the game. No update occurs here, only a render.
 | 
						 * Runs the first frame of the game. No update occurs here, only a render.
 | 
				
			||||||
	 * This is needed to initialize delta time values
 | 
						 * This is needed to initialize delta time values
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@ export default abstract class CanvasNode extends GameNode implements Region {
 | 
				
			||||||
	private _boundary: AABB;
 | 
						private _boundary: AABB;
 | 
				
			||||||
	private _hasCustomShader: boolean;
 | 
						private _hasCustomShader: boolean;
 | 
				
			||||||
	private _customShaderKey: string;
 | 
						private _customShaderKey: string;
 | 
				
			||||||
 | 
						private _alpha: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** A flag for whether or not the CanvasNode is visible */
 | 
						/** A flag for whether or not the CanvasNode is visible */
 | 
				
			||||||
	visible: boolean = true;
 | 
						visible: boolean = true;
 | 
				
			||||||
| 
						 | 
					@ -30,6 +31,14 @@ export default abstract class CanvasNode extends GameNode implements Region {
 | 
				
			||||||
		this._hasCustomShader = false;
 | 
							this._hasCustomShader = false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						get alpha(): number {
 | 
				
			||||||
 | 
							return this._alpha;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						set alpha(a: number) {
 | 
				
			||||||
 | 
							this._alpha = a;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	get size(): Vec2 {
 | 
						get size(): Vec2 {
 | 
				
			||||||
		return this._size;
 | 
							return this._size;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,10 +12,9 @@ import Updateable from "../DataTypes/Interfaces/Updateable";
 | 
				
			||||||
import DebugRenderable from "../DataTypes/Interfaces/DebugRenderable";
 | 
					import DebugRenderable from "../DataTypes/Interfaces/DebugRenderable";
 | 
				
			||||||
import Actor from "../DataTypes/Interfaces/Actor";
 | 
					import Actor from "../DataTypes/Interfaces/Actor";
 | 
				
			||||||
import Shape from "../DataTypes/Shapes/Shape";
 | 
					import Shape from "../DataTypes/Shapes/Shape";
 | 
				
			||||||
import Map from "../DataTypes/Map";
 | 
					 | 
				
			||||||
import AABB from "../DataTypes/Shapes/AABB";
 | 
					import AABB from "../DataTypes/Shapes/AABB";
 | 
				
			||||||
import NavigationPath from "../Pathfinding/NavigationPath";
 | 
					import NavigationPath from "../Pathfinding/NavigationPath";
 | 
				
			||||||
import TweenManager from "../Rendering/Animations/TweenManager";
 | 
					import TweenController from "../Rendering/Animations/TweenController";
 | 
				
			||||||
import Debug from "../Debug/Debug";
 | 
					import Debug from "../Debug/Debug";
 | 
				
			||||||
import Color from "../Utils/Color";
 | 
					import Color from "../Utils/Color";
 | 
				
			||||||
import Circle from "../DataTypes/Shapes/Circle";
 | 
					import Circle from "../DataTypes/Shapes/Circle";
 | 
				
			||||||
| 
						 | 
					@ -43,19 +42,19 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
 | 
				
			||||||
	isStatic: boolean;
 | 
						isStatic: boolean;
 | 
				
			||||||
	isCollidable: boolean;
 | 
						isCollidable: boolean;
 | 
				
			||||||
	isTrigger: boolean;
 | 
						isTrigger: boolean;
 | 
				
			||||||
	group: string;
 | 
						triggerMask: number;
 | 
				
			||||||
	triggers: Map<string>;
 | 
						triggerEnters: Array<string>;
 | 
				
			||||||
 | 
						triggerExits: Array<string>;
 | 
				
			||||||
	_velocity: Vec2;
 | 
						_velocity: Vec2;
 | 
				
			||||||
	sweptRect: AABB;
 | 
						sweptRect: AABB;
 | 
				
			||||||
	collidedWithTilemap: boolean;
 | 
						collidedWithTilemap: boolean;
 | 
				
			||||||
	physicsLayer: number;
 | 
						group: number;
 | 
				
			||||||
	isPlayer: boolean;
 | 
						isPlayer: boolean;
 | 
				
			||||||
	isColliding: boolean = false;
 | 
						isColliding: boolean = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*---------- ACTOR ----------*/
 | 
						/*---------- ACTOR ----------*/
 | 
				
			||||||
	_ai: AI;
 | 
						_ai: AI;
 | 
				
			||||||
	aiActive: boolean;
 | 
						aiActive: boolean;
 | 
				
			||||||
	actorId: number;
 | 
					 | 
				
			||||||
	path: NavigationPath;
 | 
						path: NavigationPath;
 | 
				
			||||||
	pathfinding: boolean = false;
 | 
						pathfinding: boolean = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,11 +68,13 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
 | 
				
			||||||
	/** The visual layer this GameNode resides in. */
 | 
						/** The visual layer this GameNode resides in. */
 | 
				
			||||||
	protected layer: Layer;
 | 
						protected layer: Layer;
 | 
				
			||||||
	/** A utility that allows the use of tweens on this GameNode */
 | 
						/** A utility that allows the use of tweens on this GameNode */
 | 
				
			||||||
	tweens: TweenManager;
 | 
						tweens: TweenController;
 | 
				
			||||||
	/** A tweenable property for rotation. Does not affect the bounding box of this GameNode - Only rendering. */
 | 
						/** A tweenable property for rotation. Does not affect the bounding box of this GameNode - Only rendering. */
 | 
				
			||||||
	rotation: number;
 | 
						rotation: number;
 | 
				
			||||||
	/** The opacity value of this GameNode */
 | 
						/** The opacity value of this GameNode */
 | 
				
			||||||
	alpha: number;
 | 
						abstract set alpha(a: number);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						abstract get alpha(): number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Constructor docs are ignored, as the user should NOT create new GameNodes with a raw constructor
 | 
						// Constructor docs are ignored, as the user should NOT create new GameNodes with a raw constructor
 | 
				
			||||||
	constructor(){
 | 
						constructor(){
 | 
				
			||||||
| 
						 | 
					@ -81,9 +82,27 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
 | 
				
			||||||
		this._position.setOnChange(() => this.positionChanged());
 | 
							this._position.setOnChange(() => this.positionChanged());
 | 
				
			||||||
		this.receiver = new Receiver();
 | 
							this.receiver = new Receiver();
 | 
				
			||||||
		this.emitter = new Emitter();
 | 
							this.emitter = new Emitter();
 | 
				
			||||||
		this.tweens = new TweenManager(this);
 | 
							this.tweens = new TweenController(this);
 | 
				
			||||||
		this.rotation = 0;
 | 
							this.rotation = 0;
 | 
				
			||||||
		this.alpha = 1;
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						destroy(){
 | 
				
			||||||
 | 
							this.tweens.destroy();
 | 
				
			||||||
 | 
							this.receiver.destroy();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(this.hasPhysics){
 | 
				
			||||||
 | 
								this.removePhysics();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(this._ai){
 | 
				
			||||||
 | 
								this._ai.destroy();
 | 
				
			||||||
 | 
								delete this._ai;
 | 
				
			||||||
 | 
								this.scene.getAIManager().removeActor(this);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.scene.remove(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.layer.removeNode(this);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*---------- POSITIONED ----------*/
 | 
						/*---------- POSITIONED ----------*/
 | 
				
			||||||
| 
						 | 
					@ -176,12 +195,13 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
 | 
				
			||||||
		this.isCollidable = isCollidable;
 | 
							this.isCollidable = isCollidable;
 | 
				
			||||||
		this.isStatic = isStatic;
 | 
							this.isStatic = isStatic;
 | 
				
			||||||
		this.isTrigger = false;
 | 
							this.isTrigger = false;
 | 
				
			||||||
		this.group = "";
 | 
							this.triggerMask = 0;
 | 
				
			||||||
		this.triggers = new Map();
 | 
							this.triggerEnters = new Array(32);
 | 
				
			||||||
 | 
							this.triggerExits = new Array(32);
 | 
				
			||||||
		this._velocity = Vec2.ZERO;
 | 
							this._velocity = Vec2.ZERO;
 | 
				
			||||||
		this.sweptRect = new AABB();
 | 
							this.sweptRect = new AABB();
 | 
				
			||||||
		this.collidedWithTilemap = false;
 | 
							this.collidedWithTilemap = false;
 | 
				
			||||||
		this.physicsLayer = -1;
 | 
							this.group = -1;					// The default group, collides with everything
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Set the collision shape if provided, or simply use the the region if there is one.
 | 
							// Set the collision shape if provided, or simply use the the region if there is one.
 | 
				
			||||||
		if(collisionShape){
 | 
							if(collisionShape){
 | 
				
			||||||
| 
						 | 
					@ -208,6 +228,43 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
 | 
				
			||||||
		this.scene.getPhysicsManager().registerObject(this);
 | 
							this.scene.getPhysicsManager().registerObject(this);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Removes this object from the physics system */
 | 
				
			||||||
 | 
					    removePhysics(): void {
 | 
				
			||||||
 | 
							// Nullify all physics fields
 | 
				
			||||||
 | 
							this.hasPhysics = false;
 | 
				
			||||||
 | 
							this.moving = false;
 | 
				
			||||||
 | 
							this.onGround = false;
 | 
				
			||||||
 | 
							this.onWall = false;
 | 
				
			||||||
 | 
							this.onCeiling = false;
 | 
				
			||||||
 | 
							this.active = false;
 | 
				
			||||||
 | 
							this.isCollidable = false;
 | 
				
			||||||
 | 
							this.isStatic = false;
 | 
				
			||||||
 | 
							this.isTrigger = false;
 | 
				
			||||||
 | 
							this.triggerMask = 0;
 | 
				
			||||||
 | 
							this.triggerEnters = null;
 | 
				
			||||||
 | 
							this.triggerExits = null;
 | 
				
			||||||
 | 
							this._velocity = Vec2.ZERO;
 | 
				
			||||||
 | 
							this.sweptRect = null;
 | 
				
			||||||
 | 
							this.collidedWithTilemap = false;
 | 
				
			||||||
 | 
							this.group = -1;
 | 
				
			||||||
 | 
							this.collisionShape = null;
 | 
				
			||||||
 | 
							this.colliderOffset = Vec2.ZERO;
 | 
				
			||||||
 | 
							this.sweptRect = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Remove this from the physics manager
 | 
				
			||||||
 | 
							this.scene.getPhysicsManager().deregisterObject(this);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Prevents this object from participating in all collisions and triggers. It can still move. */
 | 
				
			||||||
 | 
					    disablePhysics(): void {
 | 
				
			||||||
 | 
							this.active = false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Enables this object to participate in collisions and triggers. This is only necessary if disablePhysics was called */
 | 
				
			||||||
 | 
					    enablePhysics(): void {
 | 
				
			||||||
 | 
							this.active = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Sets the collider for this GameNode
 | 
						 * Sets the collider for this GameNode
 | 
				
			||||||
	 * @param collider The new collider to use
 | 
						 * @param collider The new collider to use
 | 
				
			||||||
| 
						 | 
					@ -219,20 +276,40 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// @implemented
 | 
						// @implemented
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @param group The name of the group that will activate the trigger
 | 
					     * Sets this object to be a trigger for a specific group
 | 
				
			||||||
	 * @param eventType The type of this event to send when this trigger is activated
 | 
					     * @param group The name of the group that activates the trigger
 | 
				
			||||||
	 */
 | 
					     * @param onEnter The name of the event to send when this trigger is activated
 | 
				
			||||||
    addTrigger(group: string, eventType: string): void {
 | 
					     * @param onExit The name of the event to send when this trigger stops being activated
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    setTrigger(group: string, onEnter: string, onExit: string): void {
 | 
				
			||||||
 | 
							// Make this object a trigger
 | 
				
			||||||
		this.isTrigger = true;
 | 
							this.isTrigger = true;
 | 
				
			||||||
		this.triggers.add(group, eventType);
 | 
					
 | 
				
			||||||
 | 
							// Get the number of the physics layer
 | 
				
			||||||
 | 
							let layerNumber = this.scene.getPhysicsManager().getGroupNumber(group);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(layerNumber === 0){
 | 
				
			||||||
 | 
								console.warn(`Trigger for GameNode ${this.id} not set - group "${group}" was not recognized by the physics manager.`);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Add this to the trigger mask
 | 
				
			||||||
 | 
							this.triggerMask |= layerNumber;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Layer numbers are bits, so get which bit it is
 | 
				
			||||||
 | 
							let index = Math.log2(layerNumber);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Set the event names
 | 
				
			||||||
 | 
							this.triggerEnters[index] = onEnter;
 | 
				
			||||||
 | 
							this.triggerExits[index] = onExit;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// @implemented
 | 
						// @implemented
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @param layer The physics layer this node should belong to
 | 
						 * @param group The physics group this node should belong to
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	setPhysicsLayer(layer: string): void {
 | 
						setGroup(group: string): void {
 | 
				
			||||||
		this.scene.getPhysicsManager().setLayer(this, layer);
 | 
							this.scene.getPhysicsManager().setGroup(this, group);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// @implemened
 | 
						// @implemened
 | 
				
			||||||
| 
						 | 
					@ -347,9 +424,6 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
 | 
				
			||||||
		while(this.receiver.hasNextEvent()){
 | 
							while(this.receiver.hasNextEvent()){
 | 
				
			||||||
			this._ai.handleEvent(this.receiver.getNextEvent());
 | 
								this._ai.handleEvent(this.receiver.getNextEvent());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		// Update our tweens
 | 
					 | 
				
			||||||
		this.tweens.update(deltaT);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// @implemented
 | 
						// @implemented
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,14 @@ export default abstract class Graphic extends CanvasNode {
 | 
				
			||||||
        this.color = Color.RED;
 | 
					        this.color = Color.RED;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get alpha(): number {
 | 
				
			||||||
 | 
							return this.color.a;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						set alpha(a: number) {
 | 
				
			||||||
 | 
							this.color.a = a;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // @deprecated
 | 
					    // @deprecated
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Sets the color of the Graphic. DEPRECATED
 | 
					     * Sets the color of the Graphic. DEPRECATED
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@ import Vec2 from "../DataTypes/Vec2";
 | 
				
			||||||
import Tileset from "../DataTypes/Tilesets/Tileset";
 | 
					import Tileset from "../DataTypes/Tilesets/Tileset";
 | 
				
			||||||
import { TiledTilemapData, TiledLayerData } from "../DataTypes/Tilesets/TiledData"
 | 
					import { TiledTilemapData, TiledLayerData } from "../DataTypes/Tilesets/TiledData"
 | 
				
			||||||
import CanvasNode from "./CanvasNode";
 | 
					import CanvasNode from "./CanvasNode";
 | 
				
			||||||
 | 
					import PhysicsManager from "../Physics/PhysicsManager";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * The representation of a tilemap - this can consist of a combination of tilesets in one layer
 | 
					 * The representation of a tilemap - this can consist of a combination of tilesets in one layer
 | 
				
			||||||
| 
						 | 
					@ -74,6 +75,9 @@ export default abstract class Tilemap extends CanvasNode {
 | 
				
			||||||
     * Adds this tilemap to the physics system
 | 
					     * Adds this tilemap to the physics system
 | 
				
			||||||
    */
 | 
					    */
 | 
				
			||||||
    addPhysics(): void {
 | 
					    addPhysics(): void {
 | 
				
			||||||
 | 
					        this.hasPhysics = true;
 | 
				
			||||||
 | 
					        this.active = true;
 | 
				
			||||||
 | 
					        this.group = -1;
 | 
				
			||||||
        this.scene.getPhysicsManager().registerTilemap(this);
 | 
					        this.scene.getPhysicsManager().registerTilemap(this);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -162,16 +162,27 @@ export default class OrthogonalTilemap extends Tilemap {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // @override
 | 
					    // @override
 | 
				
			||||||
    debugRender(){
 | 
					    debugRender(){
 | 
				
			||||||
        let tileSize = this.getTileSizeWithZoom();
 | 
					        // Half of the tile size
 | 
				
			||||||
        let origin = this.relativePosition.sub(this.sizeWithZoom);
 | 
					        let zoomedHalfTileSize = this.getTileSizeWithZoom().scaled(0.5);
 | 
				
			||||||
 | 
					        let halfTileSize = this.getTileSize().scaled(0.5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // The center of the top left tile
 | 
				
			||||||
 | 
					        let topLeft = this.position.clone().sub(this.size.scaled(0.5));
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // A vec to store the center
 | 
				
			||||||
 | 
					        let center = Vec2.ZERO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for(let col = 0; col < this.numCols; col++){
 | 
					        for(let col = 0; col < this.numCols; col++){
 | 
				
			||||||
 | 
					            // Calculate the x-position
 | 
				
			||||||
 | 
					            center.x = topLeft.x + col*2*halfTileSize.x + halfTileSize.x;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for(let row = 0; row < this.numRows; row++){
 | 
					            for(let row = 0; row < this.numRows; row++){
 | 
				
			||||||
                if(this.isCollidable && this.isTileCollidable(col, row)){
 | 
					                if(this.isCollidable && this.isTileCollidable(col, row)){
 | 
				
			||||||
                    // Draw a box for this tile
 | 
					                    // Calculate the y-position
 | 
				
			||||||
                    let center = new Vec2(origin.x + (col + 0.5)*tileSize.x, origin.y + (row + 0.5)*tileSize.y);
 | 
					                    center.y = topLeft.y + row*2*halfTileSize.y + halfTileSize.y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    Debug.drawBox(center, tileSize.scaled(0.5), false, Color.BLUE);
 | 
					                    // Draw a box for this tile
 | 
				
			||||||
 | 
					                    Debug.drawBox(this.inRelativeCoordinates(center), zoomedHalfTileSize, false, Color.BLUE);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,9 +9,9 @@ export default class Label extends UIElement{
 | 
				
			||||||
	/** The value of the text of this UIElement */
 | 
						/** The value of the text of this UIElement */
 | 
				
			||||||
	text: string;
 | 
						text: string;
 | 
				
			||||||
	/** The name of the font */
 | 
						/** The name of the font */
 | 
				
			||||||
	protected font: string;
 | 
						font: string;
 | 
				
			||||||
	/** The size of the font */
 | 
						/** The size of the font */
 | 
				
			||||||
	protected fontSize: number;
 | 
						fontSize: number;
 | 
				
			||||||
	/** The horizontal alignment of the text within the label */
 | 
						/** The horizontal alignment of the text within the label */
 | 
				
			||||||
	protected hAlign: string;
 | 
						protected hAlign: string;
 | 
				
			||||||
	/** The vertical alignment of text within the label */
 | 
						/** The vertical alignment of text within the label */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@ import Vec2 from "../DataTypes/Vec2";
 | 
				
			||||||
import AABB from "../DataTypes/Shapes/AABB";
 | 
					import AABB from "../DataTypes/Shapes/AABB";
 | 
				
			||||||
import OrthogonalTilemap from "../Nodes/Tilemaps/OrthogonalTilemap";
 | 
					import OrthogonalTilemap from "../Nodes/Tilemaps/OrthogonalTilemap";
 | 
				
			||||||
import AreaCollision from "../DataTypes/Physics/AreaCollision";
 | 
					import AreaCollision from "../DataTypes/Physics/AreaCollision";
 | 
				
			||||||
 | 
					import Unique from "../DataTypes/Interfaces/Unique";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * ALGORITHM:
 | 
					 * ALGORITHM:
 | 
				
			||||||
| 
						 | 
					@ -52,15 +53,50 @@ export default class BasicPhysicsManager extends PhysicsManager {
 | 
				
			||||||
	/** The array of tilemaps */
 | 
						/** The array of tilemaps */
 | 
				
			||||||
	protected tilemaps: Array<Tilemap>;
 | 
						protected tilemaps: Array<Tilemap>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** An array of the collision masks for each group */
 | 
				
			||||||
 | 
						protected collisionMasks: Array<number>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	constructor(options: Record<string, any>){
 | 
						constructor(options: Record<string, any>){
 | 
				
			||||||
		super();
 | 
							super();
 | 
				
			||||||
		this.staticNodes = new Array();
 | 
							this.staticNodes = new Array();
 | 
				
			||||||
		this.dynamicNodes = new Array();
 | 
							this.dynamicNodes = new Array();
 | 
				
			||||||
		this.tilemaps = new Array();
 | 
							this.tilemaps = new Array();
 | 
				
			||||||
 | 
							this.collisionMasks = new Array(32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Parse options
 | 
				
			||||||
 | 
							this.parseOptions(options);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Parses the options for constructing the physics manager
 | 
				
			||||||
 | 
						 * @param options A record of options
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						protected parseOptions(options: Record<string, any>): void {
 | 
				
			||||||
 | 
							console.log("Parsing physics options: ", options);
 | 
				
			||||||
 | 
							if(options.groupNames !== undefined && options.collisions !== undefined){
 | 
				
			||||||
 | 
								for(let i = 0; i < options.groupNames.length; i++){
 | 
				
			||||||
 | 
									let group = options.groupNames[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Register the group name and number
 | 
				
			||||||
 | 
									this.groupNames[i] = group;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									this.groupMap.set(group, 1 << i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									let collisionMask = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for(let j = 0; j < options.collisions[i].length; j++){
 | 
				
			||||||
 | 
										if(options.collisions[i][j]){
 | 
				
			||||||
 | 
											collisionMask |= 1 << j;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									this.collisionMasks[i] = collisionMask;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// @override
 | 
						// @override
 | 
				
			||||||
	registerObject(node: GameNode): void {
 | 
						registerObject(node: Physical): void {
 | 
				
			||||||
		if(node.isStatic){
 | 
							if(node.isStatic){
 | 
				
			||||||
			// Static and not collidable
 | 
								// Static and not collidable
 | 
				
			||||||
			this.staticNodes.push(node);
 | 
								this.staticNodes.push(node);
 | 
				
			||||||
| 
						 | 
					@ -70,14 +106,28 @@ export default class BasicPhysicsManager extends PhysicsManager {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// @override
 | 
				
			||||||
 | 
						deregisterObject(node: Physical): void {
 | 
				
			||||||
 | 
							if(node.isStatic){
 | 
				
			||||||
 | 
								// Remove the node from the static list
 | 
				
			||||||
 | 
								const index = this.staticNodes.indexOf(node);
 | 
				
			||||||
 | 
								this.staticNodes.splice(index, 1);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// Remove the node from the dynamic list
 | 
				
			||||||
 | 
								const index = this.dynamicNodes.indexOf(node);
 | 
				
			||||||
 | 
								this.dynamicNodes.splice(index, 1);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// @override
 | 
						// @override
 | 
				
			||||||
	registerTilemap(tilemap: Tilemap): void {
 | 
						registerTilemap(tilemap: Tilemap): void {
 | 
				
			||||||
		this.tilemaps.push(tilemap);
 | 
							this.tilemaps.push(tilemap);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// @override
 | 
						// @override
 | 
				
			||||||
	setLayer(node: GameNode, layer: string): void {
 | 
						deregisterTilemap(tilemap: Tilemap): void {
 | 
				
			||||||
		node.physicsLayer = this.layerMap.get(layer);
 | 
							const index = this.tilemaps.indexOf(tilemap);
 | 
				
			||||||
 | 
							this.tilemaps.splice(index, 1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// @override
 | 
						// @override
 | 
				
			||||||
| 
						 | 
					@ -91,6 +141,11 @@ export default class BasicPhysicsManager extends PhysicsManager {
 | 
				
			||||||
			node.collidedWithTilemap = false;
 | 
								node.collidedWithTilemap = false;
 | 
				
			||||||
			node.isColliding = false;
 | 
								node.isColliding = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// If this node is not active, don't process it
 | 
				
			||||||
 | 
								if(!node.active){
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Update the swept shapes of each node
 | 
								// Update the swept shapes of each node
 | 
				
			||||||
			if(node.moving){
 | 
								if(node.moving){
 | 
				
			||||||
				// If moving, reflect that in the swept shape
 | 
									// If moving, reflect that in the swept shape
 | 
				
			||||||
| 
						 | 
					@ -105,8 +160,13 @@ export default class BasicPhysicsManager extends PhysicsManager {
 | 
				
			||||||
			// Gather a set of overlaps
 | 
								// Gather a set of overlaps
 | 
				
			||||||
			let overlaps = new Array<AreaCollision>();
 | 
								let overlaps = new Array<AreaCollision>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								let groupIndex = Math.log2(node.group);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// First, check this node against every static node (order doesn't actually matter here, since we sort anyways)
 | 
								// First, check this node against every static node (order doesn't actually matter here, since we sort anyways)
 | 
				
			||||||
			for(let other of this.staticNodes){
 | 
								for(let other of this.staticNodes){
 | 
				
			||||||
 | 
									// Ignore inactive nodes
 | 
				
			||||||
 | 
									if(!other.active) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				let collider = other.collisionShape.getBoundingRect();
 | 
									let collider = other.collisionShape.getBoundingRect();
 | 
				
			||||||
				let area = node.sweptRect.overlapArea(collider);
 | 
									let area = node.sweptRect.overlapArea(collider);
 | 
				
			||||||
				if(area > 0){
 | 
									if(area > 0){
 | 
				
			||||||
| 
						 | 
					@ -117,6 +177,12 @@ export default class BasicPhysicsManager extends PhysicsManager {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Then, check it against every dynamic node
 | 
								// Then, check it against every dynamic node
 | 
				
			||||||
			for(let other of this.dynamicNodes){
 | 
								for(let other of this.dynamicNodes){
 | 
				
			||||||
 | 
									// Ignore ourselves
 | 
				
			||||||
 | 
									if(node === other) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Ignore inactive nodes
 | 
				
			||||||
 | 
									if(!other.active) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				let collider = other.collisionShape.getBoundingRect();
 | 
									let collider = other.collisionShape.getBoundingRect();
 | 
				
			||||||
				let area = node.sweptRect.overlapArea(collider);
 | 
									let area = node.sweptRect.overlapArea(collider);
 | 
				
			||||||
				if(area > 0){
 | 
									if(area > 0){
 | 
				
			||||||
| 
						 | 
					@ -128,6 +194,9 @@ export default class BasicPhysicsManager extends PhysicsManager {
 | 
				
			||||||
			// Lastly, gather a set of AABBs from the tilemap.
 | 
								// Lastly, gather a set of AABBs from the tilemap.
 | 
				
			||||||
			// This step involves the most extra work, so it is abstracted into a method
 | 
								// This step involves the most extra work, so it is abstracted into a method
 | 
				
			||||||
			for(let tilemap of this.tilemaps){
 | 
								for(let tilemap of this.tilemaps){
 | 
				
			||||||
 | 
									// Ignore inactive tilemaps
 | 
				
			||||||
 | 
									if(!tilemap.active) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if(tilemap instanceof OrthogonalTilemap){
 | 
									if(tilemap instanceof OrthogonalTilemap){
 | 
				
			||||||
					this.collideWithOrthogonalTilemap(node, tilemap, overlaps);
 | 
										this.collideWithOrthogonalTilemap(node, tilemap, overlaps);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					@ -142,6 +211,9 @@ export default class BasicPhysicsManager extends PhysicsManager {
 | 
				
			||||||
			/*---------- RESOLUTION PHASE ----------*/
 | 
								/*---------- RESOLUTION PHASE ----------*/
 | 
				
			||||||
			// For every overlap, determine if we need to collide with it and when
 | 
								// For every overlap, determine if we need to collide with it and when
 | 
				
			||||||
			for(let overlap of overlaps){
 | 
								for(let overlap of overlaps){
 | 
				
			||||||
 | 
									// Ignore nodes we don't interact with
 | 
				
			||||||
 | 
									if((this.collisionMasks[groupIndex] & overlap.other.group) === 0) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// Do a swept line test on the static AABB with this AABB size as padding (this is basically using a minkowski sum!)
 | 
									// Do a swept line test on the static AABB with this AABB size as padding (this is basically using a minkowski sum!)
 | 
				
			||||||
				// Start the sweep at the position of this node with a delta of _velocity
 | 
									// Start the sweep at the position of this node with a delta of _velocity
 | 
				
			||||||
				const point = node.collisionShape.center;
 | 
									const point = node.collisionShape.center;
 | 
				
			||||||
| 
						 | 
					@ -188,21 +260,46 @@ export default class BasicPhysicsManager extends PhysicsManager {
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
 | 
								/*---------- INFORMATION/TRIGGER PHASE ----------*/
 | 
				
			||||||
			// Check if we ended up on the ground, ceiling or wall
 | 
								// Check if we ended up on the ground, ceiling or wall
 | 
				
			||||||
 | 
								// Also check for triggers
 | 
				
			||||||
			for(let overlap of overlaps){
 | 
								for(let overlap of overlaps){
 | 
				
			||||||
				let collisionSide = overlap.collider.touchesAABBWithoutCorners(node.collisionShape.getBoundingRect());
 | 
									// Check for a trigger. If we care about the trigger, react
 | 
				
			||||||
				if(collisionSide !== null){
 | 
									if(overlap.other.isTrigger && (overlap.other.triggerMask & node.group)){
 | 
				
			||||||
					// If we touch, not including corner cases, check the collision normal
 | 
										// Get the bit that this group is represented by
 | 
				
			||||||
					if(overlap.hit !== null){
 | 
										let index = Math.floor(Math.log2(node.group));
 | 
				
			||||||
						if(collisionSide.y === -1){
 | 
					
 | 
				
			||||||
							// Node is on top of overlap, so onGround
 | 
										// Extract the triggerEnter event name
 | 
				
			||||||
							node.onGround = true;
 | 
										this.emitter.fireEvent(overlap.other.triggerEnters[index], {
 | 
				
			||||||
						} else if(collisionSide.y === 1){
 | 
											node: (<GameNode>node).id,
 | 
				
			||||||
							// Node is on bottom of overlap, so onCeiling
 | 
											other: (<GameNode>overlap.other).id
 | 
				
			||||||
							node.onCeiling = true;
 | 
										});
 | 
				
			||||||
						} else {
 | 
									}
 | 
				
			||||||
							// Node wasn't touching on y, so it is touching on x
 | 
					
 | 
				
			||||||
							node.onWall = true;
 | 
									// Ignore collision sides for nodes we don't interact with
 | 
				
			||||||
 | 
									if((this.collisionMasks[groupIndex] & overlap.other.group) === 0) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Only check for direction if the overlap was collidable
 | 
				
			||||||
 | 
									if(overlap.type === "Tilemap" || overlap.other.isCollidable){
 | 
				
			||||||
 | 
										let collisionSide = overlap.collider.touchesAABBWithoutCorners(node.collisionShape.getBoundingRect());
 | 
				
			||||||
 | 
										if(collisionSide !== null){
 | 
				
			||||||
 | 
											// If we touch, not including corner cases, check the collision normal
 | 
				
			||||||
 | 
											if(overlap.hit !== null){
 | 
				
			||||||
 | 
												// If we hit a tilemap, keep track of it
 | 
				
			||||||
 | 
												if(overlap.type == "Tilemap"){
 | 
				
			||||||
 | 
													node.collidedWithTilemap = true;
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												if(collisionSide.y === -1){
 | 
				
			||||||
 | 
													// Node is on top of overlap, so onGround
 | 
				
			||||||
 | 
													node.onGround = true;
 | 
				
			||||||
 | 
												} else if(collisionSide.y === 1){
 | 
				
			||||||
 | 
													// Node is on bottom of overlap, so onCeiling
 | 
				
			||||||
 | 
													node.onCeiling = true;
 | 
				
			||||||
 | 
												} else {
 | 
				
			||||||
 | 
													// Node wasn't touching on y, so it is touching on x
 | 
				
			||||||
 | 
													node.onWall = true;
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,9 @@
 | 
				
			||||||
import GameNode from "../Nodes/GameNode";
 | 
					 | 
				
			||||||
import Updateable from "../DataTypes/Interfaces/Updateable";
 | 
					import Updateable from "../DataTypes/Interfaces/Updateable";
 | 
				
			||||||
import Tilemap from "../Nodes/Tilemap";
 | 
					import Tilemap from "../Nodes/Tilemap";
 | 
				
			||||||
import Receiver from "../Events/Receiver";
 | 
					import Receiver from "../Events/Receiver";
 | 
				
			||||||
import Emitter from "../Events/Emitter";
 | 
					import Emitter from "../Events/Emitter";
 | 
				
			||||||
import Map from "../DataTypes/Map";
 | 
					import Map from "../DataTypes/Map";
 | 
				
			||||||
 | 
					import Physical from "../DataTypes/Interfaces/Physical";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * An abstract physics manager.
 | 
					 * An abstract physics manager.
 | 
				
			||||||
| 
						 | 
					@ -16,25 +16,35 @@ export default abstract class PhysicsManager implements Updateable {
 | 
				
			||||||
	protected emitter: Emitter;
 | 
						protected emitter: Emitter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Maps layer names to numbers */
 | 
						/** Maps layer names to numbers */
 | 
				
			||||||
	protected layerMap: Map<number>;
 | 
						protected groupMap: Map<number>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Maps layer numbers to names */
 | 
						/** Maps layer numbers to names */
 | 
				
			||||||
	protected layerNames: Array<string>;
 | 
						protected groupNames: Array<string>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** The default group name */
 | 
				
			||||||
 | 
						protected static readonly DEFAULT_GROUP = "Default";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	constructor(){
 | 
						constructor(){
 | 
				
			||||||
		this.receiver = new Receiver();
 | 
							this.receiver = new Receiver();
 | 
				
			||||||
		this.emitter = new Emitter();
 | 
							this.emitter = new Emitter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// The creation and implementation of layers is deferred to the subclass
 | 
							// The creation and implementation of layers is deferred to the subclass
 | 
				
			||||||
		this.layerMap = new Map();
 | 
							this.groupMap = new Map();
 | 
				
			||||||
		this.layerNames = new Array();
 | 
							this.groupNames = new Array();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Registers a gamenode with this physics manager
 | 
						 * Registers a gamenode with this physics manager
 | 
				
			||||||
	 * @param object The object to register
 | 
						 * @param object The object to register
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	abstract registerObject(object: GameNode): void;
 | 
						abstract registerObject(object: Physical): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Removes references to this object from the physics managerr
 | 
				
			||||||
 | 
						 * @param object The object to deregister
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						abstract deregisterObject(object: Physical): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Registers a tilemap with this physics manager
 | 
						 * Registers a tilemap with this physics manager
 | 
				
			||||||
| 
						 | 
					@ -42,14 +52,57 @@ export default abstract class PhysicsManager implements Updateable {
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	abstract registerTilemap(tilemap: Tilemap): void;
 | 
						abstract registerTilemap(tilemap: Tilemap): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Removes references to this tilemap from the physics managerr
 | 
				
			||||||
 | 
						 * @param tilemap The object to deregister
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						abstract deregisterTilemap(tilemap: Tilemap): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	abstract update(deltaT: number): void;
 | 
						abstract update(deltaT: number): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Sets the physics layer of the GameNode
 | 
						 * Sets the physics layer of the GameNode
 | 
				
			||||||
	 * @param node The GameNode
 | 
						 * @param node The GameNode
 | 
				
			||||||
	 * @param layer The layer that the GameNode should be on
 | 
						 * @param group The group that the GameNode should be on
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	setLayer(node: GameNode, layer: string): void {
 | 
						setGroup(node: Physical, group: string): void {
 | 
				
			||||||
		node.physicsLayer = this.layerMap.get(layer);
 | 
							node.group = this.groupMap.get(group);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Retrieves the layer number associated with the provided name
 | 
				
			||||||
 | 
						 * @param layer The name of the layer
 | 
				
			||||||
 | 
						 * @returns The layer number, or 0 if there is not a layer with that name registered
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						getGroupNumber(group: string): number {
 | 
				
			||||||
 | 
							if(this.groupMap.has(group)){
 | 
				
			||||||
 | 
								return this.groupMap.get(group);
 | 
				
			||||||
 | 
							} else{
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Gets all group names associated with the number provided
 | 
				
			||||||
 | 
						 * @param groups A mask of groups
 | 
				
			||||||
 | 
						 * @returns All groups contained in the mask
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						getGroupNames(groups: number): Array<string> {
 | 
				
			||||||
 | 
							if(groups === -1){
 | 
				
			||||||
 | 
								return [PhysicsManager.DEFAULT_GROUP];
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								let g = 1;
 | 
				
			||||||
 | 
								let names = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for(let i = 0; i < 32; i++){
 | 
				
			||||||
 | 
									if(g & groups){
 | 
				
			||||||
 | 
										// This group is in the groups number
 | 
				
			||||||
 | 
										names.push(this.groupNames[i]);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// Shift the bit over
 | 
				
			||||||
 | 
									g = g << 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										0
									
								
								src/Wolfie2D/Registry/Registries/FontRegistry.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/Wolfie2D/Registry/Registries/FontRegistry.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -80,7 +80,7 @@ export default class AnimationManager {
 | 
				
			||||||
            return this.animations.get(this.currentAnimation).frames[this.currentFrame].index;
 | 
					            return this.animations.get(this.currentAnimation).frames[this.currentFrame].index;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            // No current animation, warn the user
 | 
					            // No current animation, warn the user
 | 
				
			||||||
            console.warn("Animation index was requested, but the current animation was invalid");
 | 
					            console.warn(`Animation index was requested, but the current animation: ${this.currentAnimation} was invalid`);
 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -130,7 +130,7 @@ export default class AnimationManager {
 | 
				
			||||||
            return index;
 | 
					            return index;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            // No current animation, can't advance. Warn the user
 | 
					            // No current animation, can't advance. Warn the user
 | 
				
			||||||
            console.warn("Animation index and advance was requested, but the current animation was invalid");
 | 
					            console.warn(`Animation index and advance was requested, but the current animation (${this.currentAnimation}) in node with id: ${this.owner.id} was invalid`);
 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -141,7 +141,7 @@ export default class AnimationManager {
 | 
				
			||||||
        this.animationState = AnimationState.STOPPED;
 | 
					        this.animationState = AnimationState.STOPPED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(this.onEndEvent !== null){
 | 
					        if(this.onEndEvent !== null){
 | 
				
			||||||
            this.emitter.fireEvent(this.onEndEvent, {owner: this.owner, animation: this.currentAnimation});
 | 
					            this.emitter.fireEvent(this.onEndEvent, {owner: this.owner.id, animation: this.currentAnimation});
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // If there is a pending animation, play it
 | 
					        // If there is a pending animation, play it
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,26 @@ export class AnimationData {
 | 
				
			||||||
    repeat: boolean = false;
 | 
					    repeat: boolean = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class TweenEffect {
 | 
				
			||||||
 | 
					    /** The property to tween */
 | 
				
			||||||
 | 
					    property: TweenableProperties;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Whether or not the Tween should reset the property to its original value after playing */
 | 
				
			||||||
 | 
					    resetOnComplete: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** The starting value for the tween */
 | 
				
			||||||
 | 
					    start: any;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** The ending value for the tween */
 | 
				
			||||||
 | 
					    end: any;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** The ease function to use */
 | 
				
			||||||
 | 
					    ease: EaseFunctionType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** DO NOT MODIFY - The original value of the property - set automatically */
 | 
				
			||||||
 | 
					    initialValue: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class TweenData {
 | 
					export class TweenData {
 | 
				
			||||||
    // Members for initialization by the user
 | 
					    // Members for initialization by the user
 | 
				
			||||||
    /** The amount of time in ms to wait before executing the tween */
 | 
					    /** The amount of time in ms to wait before executing the tween */
 | 
				
			||||||
| 
						 | 
					@ -22,18 +42,13 @@ export class TweenData {
 | 
				
			||||||
    /** The duration of time over which the value with change from start to end */
 | 
					    /** The duration of time over which the value with change from start to end */
 | 
				
			||||||
    duration: number;
 | 
					    duration: number;
 | 
				
			||||||
    /** An array of the effects on the properties of the object */
 | 
					    /** An array of the effects on the properties of the object */
 | 
				
			||||||
    effects: [{
 | 
					    effects: Array<TweenEffect>;
 | 
				
			||||||
        property: TweenableProperties;
 | 
					 | 
				
			||||||
        resetOnComplete: boolean;
 | 
					 | 
				
			||||||
        initialValue: number;
 | 
					 | 
				
			||||||
        start: any;
 | 
					 | 
				
			||||||
        end: any;
 | 
					 | 
				
			||||||
        ease: EaseFunctionType;
 | 
					 | 
				
			||||||
    }];
 | 
					 | 
				
			||||||
    /** Whether or not this tween should reverse from end to start for each property when it finishes */
 | 
					    /** Whether or not this tween should reverse from end to start for each property when it finishes */
 | 
				
			||||||
    reverseOnComplete: boolean;
 | 
					    reverseOnComplete: boolean;
 | 
				
			||||||
    /** Whether or not this tween should loop when it completes */
 | 
					    /** Whether or not this tween should loop when it completes */
 | 
				
			||||||
    loop: boolean;
 | 
					    loop: boolean;
 | 
				
			||||||
 | 
					    /** The name of the event to send (if any) when the tween finishes playing */
 | 
				
			||||||
 | 
					    onEnd: string
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // Members for management by the tween manager
 | 
					    // Members for management by the tween manager
 | 
				
			||||||
    /** The progress of this tween through its effects */
 | 
					    /** The progress of this tween through its effects */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										213
									
								
								src/Wolfie2D/Rendering/Animations/TweenController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								src/Wolfie2D/Rendering/Animations/TweenController.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,213 @@
 | 
				
			||||||
 | 
					import Map from "../../DataTypes/Map";
 | 
				
			||||||
 | 
					import GameNode from "../../Nodes/GameNode";
 | 
				
			||||||
 | 
					import { AnimationState, TweenData } from "./AnimationTypes";
 | 
				
			||||||
 | 
					import EaseFunctions from "../../Utils/EaseFunctions";
 | 
				
			||||||
 | 
					import MathUtils from "../../Utils/MathUtils";
 | 
				
			||||||
 | 
					import TweenManager from "./TweenManager";
 | 
				
			||||||
 | 
					import Emitter from "../../Events/Emitter";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A manager for the tweens of a GameNode.
 | 
				
			||||||
 | 
					 * Tweens are short animations played by interpolating between two properties using an easing function.
 | 
				
			||||||
 | 
					 * For a good visual representation of easing functions, check out @link(https://easings.net/)(https://easings.net/).
 | 
				
			||||||
 | 
					 * Multiple tween can be played at the same time, as long as they don't change the same property.
 | 
				
			||||||
 | 
					 * This allows for some interesting polishes or animations that may be very difficult to do with sprite work alone
 | 
				
			||||||
 | 
					 * - especially pixel art (such as rotations or scaling).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export default class TweenController {
 | 
				
			||||||
 | 
					    /** The GameNode this TweenController acts upon */
 | 
				
			||||||
 | 
					    protected owner: GameNode;
 | 
				
			||||||
 | 
					    /** The list of created tweens */
 | 
				
			||||||
 | 
					    protected tweens: Map<TweenData>;
 | 
				
			||||||
 | 
					    /** An event emitter */
 | 
				
			||||||
 | 
					    protected emitter: Emitter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Creates a new TweenController
 | 
				
			||||||
 | 
					     * @param owner The owner of the TweenController
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    constructor(owner: GameNode){
 | 
				
			||||||
 | 
					        this.owner = owner;
 | 
				
			||||||
 | 
					        this.tweens = new Map();
 | 
				
			||||||
 | 
					        this.emitter = new Emitter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Give ourselves to the TweenManager
 | 
				
			||||||
 | 
					        TweenManager.getInstance().registerTweenController(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Destroys this TweenController
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    destroy(){
 | 
				
			||||||
 | 
					        // Only the gamenode and the tween manager should have a reference to this
 | 
				
			||||||
 | 
					        delete this.owner.tweens;
 | 
				
			||||||
 | 
					        TweenManager.getInstance().deregisterTweenController(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Add a tween to this game node
 | 
				
			||||||
 | 
					     * @param key The name of the tween
 | 
				
			||||||
 | 
					     * @param tween The data of the tween
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    add(key: string, tween: Record<string, any> | TweenData): void {
 | 
				
			||||||
 | 
					        let typedTween = <TweenData>tween;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Initialize members that we need (and the user didn't provide)
 | 
				
			||||||
 | 
					        typedTween.progress = 0;
 | 
				
			||||||
 | 
					        typedTween.elapsedTime = 0;
 | 
				
			||||||
 | 
					        typedTween.animationState = AnimationState.STOPPED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.tweens.add(key, typedTween);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Play a tween with a certain name
 | 
				
			||||||
 | 
					     * @param key The name of the tween to play
 | 
				
			||||||
 | 
					     * @param loop Whether or not the tween should loop
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    play(key: string, loop?: boolean): void {
 | 
				
			||||||
 | 
					        if(this.tweens.has(key)){
 | 
				
			||||||
 | 
					            let tween = this.tweens.get(key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Set loop if needed
 | 
				
			||||||
 | 
					            if(loop !== undefined){
 | 
				
			||||||
 | 
					                tween.loop = loop;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Set the initial values
 | 
				
			||||||
 | 
					            for(let effect of tween.effects){
 | 
				
			||||||
 | 
					                if(effect.resetOnComplete){
 | 
				
			||||||
 | 
					                    effect.initialValue = this.owner[effect.property];
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Start the tween running
 | 
				
			||||||
 | 
					            tween.animationState = AnimationState.PLAYING;
 | 
				
			||||||
 | 
					            tween.elapsedTime = 0;
 | 
				
			||||||
 | 
					            tween.progress = 0;
 | 
				
			||||||
 | 
					            tween.reversing = false;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            console.warn(`Tried to play tween "${key}" on node with id ${this.owner.id}, but no such tween exists`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Pauses a playing tween. Does not affect tweens that are stopped.
 | 
				
			||||||
 | 
					     * @param key The name of the tween to pause.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    pause(key: string): void {
 | 
				
			||||||
 | 
					        if(this.tweens.has(key)){
 | 
				
			||||||
 | 
					            this.tweens.get(key).animationState = AnimationState.PAUSED;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Resumes a paused tween.
 | 
				
			||||||
 | 
					     * @param key The name of the tween to resume
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    resume(key: string): void {
 | 
				
			||||||
 | 
					        if(this.tweens.has(key)){
 | 
				
			||||||
 | 
					            let tween = this.tweens.get(key);
 | 
				
			||||||
 | 
					            if(tween.animationState === AnimationState.PAUSED)
 | 
				
			||||||
 | 
					                tween.animationState = AnimationState.PLAYING;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Stops a currently playing tween
 | 
				
			||||||
 | 
					     * @param key The key of the tween
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    stop(key: string): void {
 | 
				
			||||||
 | 
					        if(this.tweens.has(key)){
 | 
				
			||||||
 | 
					            let tween = this.tweens.get(key);
 | 
				
			||||||
 | 
					            tween.animationState = AnimationState.STOPPED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Return to the initial values
 | 
				
			||||||
 | 
					            for(let effect of tween.effects){
 | 
				
			||||||
 | 
					                if(effect.resetOnComplete){
 | 
				
			||||||
 | 
					                    this.owner[effect.property] = effect.initialValue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The natural stop of a currently playing tween
 | 
				
			||||||
 | 
					     * @param key The key of the tween
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected end(key: string): void {
 | 
				
			||||||
 | 
					        this.stop(key);
 | 
				
			||||||
 | 
					        if(this.tweens.has(key)){
 | 
				
			||||||
 | 
					            // Get the tween
 | 
				
			||||||
 | 
					            let tween = this.tweens.get(key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // If it has an onEnd, send an event
 | 
				
			||||||
 | 
					            if(tween.onEnd){
 | 
				
			||||||
 | 
					                this.emitter.fireEvent(tween.onEnd, {key: key, node: this.owner.id}); 
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Stops all currently playing tweens
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    stopAll(): void {
 | 
				
			||||||
 | 
					        this.tweens.forEach(key => this.stop(key));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    update(deltaT: number): void {
 | 
				
			||||||
 | 
					        this.tweens.forEach(key => {
 | 
				
			||||||
 | 
					            let tween = this.tweens.get(key);
 | 
				
			||||||
 | 
					            if(tween.animationState === AnimationState.PLAYING){
 | 
				
			||||||
 | 
					                // Update the progress of the tween
 | 
				
			||||||
 | 
					                tween.elapsedTime += deltaT*1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // If we're past the startDelay, do the tween
 | 
				
			||||||
 | 
					                if(tween.elapsedTime >= tween.startDelay){
 | 
				
			||||||
 | 
					                    if(!tween.reversing && tween.elapsedTime >= tween.startDelay + tween.duration){
 | 
				
			||||||
 | 
					                        // If we're over time, stop the tween, loop, or reverse
 | 
				
			||||||
 | 
					                        if(tween.reverseOnComplete){
 | 
				
			||||||
 | 
					                            // If we're over time and can reverse, do so
 | 
				
			||||||
 | 
					                            tween.reversing = true;
 | 
				
			||||||
 | 
					                        } else if(tween.loop){
 | 
				
			||||||
 | 
					                            // If we can't reverse and can loop, do so
 | 
				
			||||||
 | 
					                            tween.elapsedTime -= tween.duration;
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            // We aren't looping and can't reverse, so stop
 | 
				
			||||||
 | 
					                            this.end(key);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // Check for the end of reversing
 | 
				
			||||||
 | 
					                    if(tween.reversing && tween.elapsedTime >= tween.startDelay + 2*tween.duration){
 | 
				
			||||||
 | 
					                        if(tween.loop){
 | 
				
			||||||
 | 
					                            tween.reversing = false;
 | 
				
			||||||
 | 
					                            tween.elapsedTime -= 2*tween.duration;
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            this.end(key);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // Update the progress, make sure it is between 0 and 1. Errors from this should never be large
 | 
				
			||||||
 | 
					                    if(tween.reversing){
 | 
				
			||||||
 | 
					                        tween.progress = MathUtils.clamp01((2*tween.duration - (tween.elapsedTime- tween.startDelay))/tween.duration);
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        tween.progress = MathUtils.clamp01((tween.elapsedTime - tween.startDelay)/tween.duration);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for(let effect of tween.effects){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        // Get the value from the ease function that corresponds to our progress
 | 
				
			||||||
 | 
					                        let ease = EaseFunctions[effect.ease](tween.progress);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        // Use the value to lerp the property
 | 
				
			||||||
 | 
					                        let value = MathUtils.lerp(effect.start, effect.end, ease);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        // Assign the value of the property
 | 
				
			||||||
 | 
					                        this.owner[effect.property] = value;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,169 +1,40 @@
 | 
				
			||||||
import Map from "../../DataTypes/Map";
 | 
					import Updateable from "../../DataTypes/Interfaces/Updateable";
 | 
				
			||||||
import GameNode from "../../Nodes/GameNode";
 | 
					import TweenController from "./TweenController";
 | 
				
			||||||
import { AnimationState, TweenData } from "./AnimationTypes";
 | 
					 | 
				
			||||||
import EaseFunctions from "../../Utils/EaseFunctions";
 | 
					 | 
				
			||||||
import MathUtils from "../../Utils/MathUtils";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					export default class TweenManager implements Updateable {
 | 
				
			||||||
 * A manager for the tweens of a GameNode.
 | 
					 | 
				
			||||||
 * Tweens are short animations played by interpolating between two properties using an easing function.
 | 
					 | 
				
			||||||
 * For a good visual representation of easing functions, check out @link(https://easings.net/)(https://easings.net/).
 | 
					 | 
				
			||||||
 * Multiple tween can be played at the same time, as long as they don't change the same property.
 | 
					 | 
				
			||||||
 * This allows for some interesting polishes or animations that may be very difficult to do with sprite work alone
 | 
					 | 
				
			||||||
 * - especially pixel art (such as rotations or scaling).
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export default class TweenManager {
 | 
					 | 
				
			||||||
    /** The GameNode this TweenManager acts upon */
 | 
					 | 
				
			||||||
    protected owner: GameNode;
 | 
					 | 
				
			||||||
    /** The list of created tweens */
 | 
					 | 
				
			||||||
    protected tweens: Map<TweenData>;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    private static instance: TweenManager = null;
 | 
				
			||||||
     * Creates a new TweenManager
 | 
					    
 | 
				
			||||||
     * @param owner The owner of the TweenManager
 | 
					    protected tweenControllers: Array<TweenController>;
 | 
				
			||||||
     */
 | 
					
 | 
				
			||||||
    constructor(owner: GameNode){
 | 
					    private constructor(){
 | 
				
			||||||
        this.owner = owner;
 | 
					        this.tweenControllers = new Array();
 | 
				
			||||||
        this.tweens = new Map();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    static getInstance(): TweenManager {
 | 
				
			||||||
     * Add a tween to this game node
 | 
					        if(TweenManager.instance === null){
 | 
				
			||||||
     * @param key The name of the tween
 | 
					            TweenManager.instance = new TweenManager();
 | 
				
			||||||
     * @param tween The data of the tween
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    add(key: string, tween: Record<string, any> | TweenData): void {
 | 
					 | 
				
			||||||
        let typedTween = <TweenData>tween;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Initialize members that we need (and the user didn't provide)
 | 
					 | 
				
			||||||
        typedTween.progress = 0;
 | 
					 | 
				
			||||||
        typedTween.elapsedTime = 0;
 | 
					 | 
				
			||||||
        typedTween.animationState = AnimationState.STOPPED;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.tweens.add(key, typedTween);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Play a tween with a certain name
 | 
					 | 
				
			||||||
     * @param key The name of the tween to play
 | 
					 | 
				
			||||||
     * @param loop Whether or not the tween should loop
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    play(key: string, loop?: boolean): void {
 | 
					 | 
				
			||||||
        if(this.tweens.has(key)){
 | 
					 | 
				
			||||||
            let tween = this.tweens.get(key);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Set loop if needed
 | 
					 | 
				
			||||||
            if(loop !== undefined){
 | 
					 | 
				
			||||||
                tween.loop = loop;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Set the initial values
 | 
					 | 
				
			||||||
            for(let effect of tween.effects){
 | 
					 | 
				
			||||||
                if(effect.resetOnComplete){
 | 
					 | 
				
			||||||
                    effect.initialValue = this.owner[effect.property];
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Start the tween running
 | 
					 | 
				
			||||||
            tween.animationState = AnimationState.PLAYING;
 | 
					 | 
				
			||||||
            tween.elapsedTime = 0;
 | 
					 | 
				
			||||||
            tween.progress = 0;
 | 
					 | 
				
			||||||
            tween.reversing = false;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return TweenManager.instance;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    registerTweenController(controller: TweenController){
 | 
				
			||||||
     * Pauses a playing tween. Does not affect tweens that are stopped.
 | 
					        this.tweenControllers.push(controller);
 | 
				
			||||||
     * @param key The name of the tween to pause.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    pause(key: string): void {
 | 
					 | 
				
			||||||
        if(this.tweens.has(key)){
 | 
					 | 
				
			||||||
            this.tweens.get(key).animationState = AnimationState.PAUSED;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    deregisterTweenController(controller: TweenController){
 | 
				
			||||||
     * Resumes a paused tween.
 | 
					        let index = this.tweenControllers.indexOf(controller);
 | 
				
			||||||
     * @param key The name of the tween to resume
 | 
					        this.tweenControllers.splice(index, 1);
 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    resume(key: string): void {
 | 
					 | 
				
			||||||
        if(this.tweens.has(key)){
 | 
					 | 
				
			||||||
            let tween = this.tweens.get(key);
 | 
					 | 
				
			||||||
            if(tween.animationState === AnimationState.PAUSED)
 | 
					 | 
				
			||||||
                tween.animationState = AnimationState.PLAYING;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    clearTweenControllers(){
 | 
				
			||||||
     * Stops a currently playing tween
 | 
					        this.tweenControllers = new Array();
 | 
				
			||||||
     * @param key The key of the tween
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    stop(key: string): void {
 | 
					 | 
				
			||||||
        if(this.tweens.has(key)){
 | 
					 | 
				
			||||||
            let tween = this.tweens.get(key);
 | 
					 | 
				
			||||||
            tween.animationState = AnimationState.STOPPED;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Return to the initial values
 | 
					 | 
				
			||||||
            for(let effect of tween.effects){
 | 
					 | 
				
			||||||
                if(effect.resetOnComplete){
 | 
					 | 
				
			||||||
                    this.owner[effect.property] = effect.initialValue;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    update(deltaT: number): void {
 | 
					    update(deltaT: number): void {
 | 
				
			||||||
        this.tweens.forEach(key => {
 | 
					        for(let tweenController of this.tweenControllers){
 | 
				
			||||||
            let tween = this.tweens.get(key);
 | 
					            tweenController.update(deltaT);
 | 
				
			||||||
            if(tween.animationState === AnimationState.PLAYING){
 | 
					        }
 | 
				
			||||||
                // Update the progress of the tween
 | 
					 | 
				
			||||||
                tween.elapsedTime += deltaT*1000;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // If we're past the startDelay, do the tween
 | 
					 | 
				
			||||||
                if(tween.elapsedTime >= tween.startDelay){
 | 
					 | 
				
			||||||
                    if(!tween.reversing && tween.elapsedTime >= tween.startDelay + tween.duration){
 | 
					 | 
				
			||||||
                        // If we're over time, stop the tween, loop, or reverse
 | 
					 | 
				
			||||||
                        if(tween.reverseOnComplete){
 | 
					 | 
				
			||||||
                            // If we're over time and can reverse, do so
 | 
					 | 
				
			||||||
                            tween.reversing = true;
 | 
					 | 
				
			||||||
                        } else if(tween.loop){
 | 
					 | 
				
			||||||
                            // If we can't reverse and can loop, do so
 | 
					 | 
				
			||||||
                            tween.elapsedTime -= tween.duration;
 | 
					 | 
				
			||||||
                        } else {
 | 
					 | 
				
			||||||
                            // We aren't looping and can't reverse, so stop
 | 
					 | 
				
			||||||
                            this.stop(key);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // Check for the end of reversing
 | 
					 | 
				
			||||||
                    if(tween.reversing && tween.elapsedTime >= tween.startDelay + 2*tween.duration){
 | 
					 | 
				
			||||||
                        if(tween.loop){
 | 
					 | 
				
			||||||
                            tween.reversing = false;
 | 
					 | 
				
			||||||
                            tween.elapsedTime -= 2*tween.duration;
 | 
					 | 
				
			||||||
                        } else {
 | 
					 | 
				
			||||||
                            this.stop(key);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // Update the progress, make sure it is between 0 and 1. Errors from this should never be large
 | 
					 | 
				
			||||||
                    if(tween.reversing){
 | 
					 | 
				
			||||||
                        tween.progress = MathUtils.clamp01((2*tween.duration - (tween.elapsedTime- tween.startDelay))/tween.duration);
 | 
					 | 
				
			||||||
                    } else {
 | 
					 | 
				
			||||||
                        tween.progress = MathUtils.clamp01((tween.elapsedTime - tween.startDelay)/tween.duration);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    for(let effect of tween.effects){
 | 
					 | 
				
			||||||
                        // Get the value from the ease function that corresponds to our progress
 | 
					 | 
				
			||||||
                        let ease = EaseFunctions[effect.ease](tween.progress);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        // Use the value to lerp the property
 | 
					 | 
				
			||||||
                        let value = MathUtils.lerp(effect.start, effect.end, ease);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        // Assign the value of the property
 | 
					 | 
				
			||||||
                        this.owner[effect.property] = value;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -153,7 +153,10 @@ export default class CanvasRenderer extends RenderingManager {
 | 
				
			||||||
        this.ctx.setTransform(xScale, 0, 0, yScale, (node.position.x - this.origin.x)*this.zoom, (node.position.y - this.origin.y)*this.zoom);
 | 
					        this.ctx.setTransform(xScale, 0, 0, yScale, (node.position.x - this.origin.x)*this.zoom, (node.position.y - this.origin.y)*this.zoom);
 | 
				
			||||||
        this.ctx.rotate(-node.rotation);
 | 
					        this.ctx.rotate(-node.rotation);
 | 
				
			||||||
        let globalAlpha = this.ctx.globalAlpha;
 | 
					        let globalAlpha = this.ctx.globalAlpha;
 | 
				
			||||||
        this.ctx.globalAlpha = ((<any>node).color ? (<any>node).color.a : 1) * node.alpha;
 | 
					        if(node instanceof Rect){
 | 
				
			||||||
 | 
					            Debug.log("node" + node.id, "Node" + node.id + " Alpha: " + node.alpha);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.ctx.globalAlpha = node.alpha;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        if(node instanceof AnimatedSprite){
 | 
					        if(node instanceof AnimatedSprite){
 | 
				
			||||||
            this.renderAnimatedSprite(<AnimatedSprite>node);
 | 
					            this.renderAnimatedSprite(<AnimatedSprite>node);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -110,6 +110,14 @@ export default class TilemapFactory {
 | 
				
			||||||
                // Register tilemap with physics if it's collidable
 | 
					                // Register tilemap with physics if it's collidable
 | 
				
			||||||
                if(tilemap.isCollidable){
 | 
					                if(tilemap.isCollidable){
 | 
				
			||||||
                    tilemap.addPhysics();
 | 
					                    tilemap.addPhysics();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if(layer.properties){
 | 
				
			||||||
 | 
					                        for(let item of layer.properties){
 | 
				
			||||||
 | 
					                            if(item.name === "Group"){
 | 
				
			||||||
 | 
					                                tilemap.setGroup(item.value);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,6 +158,9 @@ export default class TilemapFactory {
 | 
				
			||||||
                    let hasPhysics = false;
 | 
					                    let hasPhysics = false;
 | 
				
			||||||
                    let isCollidable = false;
 | 
					                    let isCollidable = false;
 | 
				
			||||||
                    let isTrigger = false;
 | 
					                    let isTrigger = false;
 | 
				
			||||||
 | 
					                    let onEnter = null;
 | 
				
			||||||
 | 
					                    let onExit = null;
 | 
				
			||||||
 | 
					                    let triggerGroup = null;
 | 
				
			||||||
                    let group = "";
 | 
					                    let group = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if(obj.properties){
 | 
					                    if(obj.properties){
 | 
				
			||||||
| 
						 | 
					@ -158,10 +169,16 @@ export default class TilemapFactory {
 | 
				
			||||||
                                hasPhysics = prop.value;
 | 
					                                hasPhysics = prop.value;
 | 
				
			||||||
                            } else if(prop.name === "Collidable"){
 | 
					                            } else if(prop.name === "Collidable"){
 | 
				
			||||||
                                isCollidable = prop.value;
 | 
					                                isCollidable = prop.value;
 | 
				
			||||||
                            } else if(prop.name === "IsTrigger"){
 | 
					 | 
				
			||||||
                                isTrigger = prop.value;
 | 
					 | 
				
			||||||
                            } else if(prop.name === "Group"){
 | 
					                            } else if(prop.name === "Group"){
 | 
				
			||||||
                                group = prop.value;
 | 
					                                group = prop.value;
 | 
				
			||||||
 | 
					                            } else if(prop.name === "IsTrigger"){
 | 
				
			||||||
 | 
					                                isTrigger = prop.value;
 | 
				
			||||||
 | 
					                            } else if(prop.name === "TriggerGroup"){
 | 
				
			||||||
 | 
					                                triggerGroup = prop.value;
 | 
				
			||||||
 | 
					                            } else if(prop.name === "TriggerOnEnter"){
 | 
				
			||||||
 | 
					                                onEnter = prop.value;
 | 
				
			||||||
 | 
					                            } else if(prop.name === "TriggerOnExit"){
 | 
				
			||||||
 | 
					                                onExit = prop.value;
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
| 
						 | 
					@ -199,8 +216,10 @@ export default class TilemapFactory {
 | 
				
			||||||
                    if(hasPhysics){
 | 
					                    if(hasPhysics){
 | 
				
			||||||
                        // Make the sprite a static physics object
 | 
					                        // Make the sprite a static physics object
 | 
				
			||||||
                        sprite.addPhysics(sprite.boundary.clone(), Vec2.ZERO, isCollidable, true);
 | 
					                        sprite.addPhysics(sprite.boundary.clone(), Vec2.ZERO, isCollidable, true);
 | 
				
			||||||
                        sprite.group = group;
 | 
					                        sprite.setGroup(group);
 | 
				
			||||||
                        sprite.isTrigger = isTrigger;
 | 
					                        if(isTrigger && triggerGroup !== null){
 | 
				
			||||||
 | 
					                            sprite.setTrigger(triggerGroup, onEnter, onExit);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -164,17 +164,14 @@ export default class Layer {
 | 
				
			||||||
     * @param node The node to remove
 | 
					     * @param node The node to remove
 | 
				
			||||||
     * @returns true if the node was removed, false otherwise
 | 
					     * @returns true if the node was removed, false otherwise
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    removeNode(node: GameNode): boolean {
 | 
					    removeNode(node: GameNode): void {
 | 
				
			||||||
        // Find and remove the node
 | 
					        // Find and remove the node
 | 
				
			||||||
        for(let i = 0; i < this.items.length; i++){
 | 
					        let index = this.items.indexOf(node);
 | 
				
			||||||
            if(this.items[i].id === node.id){
 | 
					 | 
				
			||||||
                this.items.splice(i, 1);
 | 
					 | 
				
			||||||
                node.setLayer(null);
 | 
					 | 
				
			||||||
                return true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return false;
 | 
					        if(index !== -1){
 | 
				
			||||||
 | 
					            this.items.splice(index, 1);
 | 
				
			||||||
 | 
					            node.setLayer(undefined);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,7 @@ import SceneOptions from "./SceneOptions";
 | 
				
			||||||
import RenderingManager from "../Rendering/RenderingManager";
 | 
					import RenderingManager from "../Rendering/RenderingManager";
 | 
				
			||||||
import Debug from "../Debug/Debug";
 | 
					import Debug from "../Debug/Debug";
 | 
				
			||||||
import TimerManager from "../Timing/TimerManager";
 | 
					import TimerManager from "../Timing/TimerManager";
 | 
				
			||||||
 | 
					import TweenManager from "../Rendering/Animations/TweenManager";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Scenes are the main container in the game engine.
 | 
					 * Scenes are the main container in the game engine.
 | 
				
			||||||
| 
						 | 
					@ -87,7 +88,7 @@ export default class Scene implements Updateable {
 | 
				
			||||||
    public sceneOptions: SceneOptions;
 | 
					    public sceneOptions: SceneOptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Creates a new Scene. To add a new Scene in your game, use addScene() in @reference[SceneManager]
 | 
					     * Creates a new Scene. To add a new Scene in your game, use changeToScene() in @reference[SceneManager]
 | 
				
			||||||
     * @param viewport The viewport of the game
 | 
					     * @param viewport The viewport of the game
 | 
				
			||||||
     * @param sceneManager The SceneManager that owns this Scene
 | 
					     * @param sceneManager The SceneManager that owns this Scene
 | 
				
			||||||
     * @param renderingManager The RenderingManager that will handle this Scene's rendering
 | 
					     * @param renderingManager The RenderingManager that will handle this Scene's rendering
 | 
				
			||||||
| 
						 | 
					@ -95,7 +96,7 @@ export default class Scene implements Updateable {
 | 
				
			||||||
     * @param options The options for Scene initialization
 | 
					     * @param options The options for Scene initialization
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    constructor(viewport: Viewport, sceneManager: SceneManager, renderingManager: RenderingManager, options: Record<string, any>){
 | 
					    constructor(viewport: Viewport, sceneManager: SceneManager, renderingManager: RenderingManager, options: Record<string, any>){
 | 
				
			||||||
        this.sceneOptions = SceneOptions.parse(options? options : {});
 | 
					        this.sceneOptions = SceneOptions.parse(options === undefined ? {} : options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.worldSize = new Vec2(500, 500);
 | 
					        this.worldSize = new Vec2(500, 500);
 | 
				
			||||||
        this.viewport = viewport;
 | 
					        this.viewport = viewport;
 | 
				
			||||||
| 
						 | 
					@ -165,6 +166,9 @@ export default class Scene implements Updateable {
 | 
				
			||||||
            } 
 | 
					            } 
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					        // Update all tweens
 | 
				
			||||||
 | 
					        TweenManager.getInstance().update(deltaT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Update viewport
 | 
					        // Update viewport
 | 
				
			||||||
        this.viewport.update(deltaT);
 | 
					        this.viewport.update(deltaT);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -210,6 +214,31 @@ export default class Scene implements Updateable {
 | 
				
			||||||
        return this.running;
 | 
					        return this.running;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Removes a node from this Scene
 | 
				
			||||||
 | 
					     * @param node The node to remove
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    remove(node: GameNode): void {
 | 
				
			||||||
 | 
					        // Remove from the scene graph
 | 
				
			||||||
 | 
					        if(node instanceof CanvasNode){
 | 
				
			||||||
 | 
					            this.sceneGraph.removeNode(node);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Destroys this scene and all nodes in it */
 | 
				
			||||||
 | 
					    destroy(): void {
 | 
				
			||||||
 | 
					        for(let node of this.sceneGraph.getAllNodes()){
 | 
				
			||||||
 | 
					            node.destroy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        delete this.sceneGraph;
 | 
				
			||||||
 | 
					        delete this.physicsManager;
 | 
				
			||||||
 | 
					        delete this.navManager;
 | 
				
			||||||
 | 
					        delete this.aiManager;
 | 
				
			||||||
 | 
					        delete this.receiver;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Adds a new layer to the scene and returns it
 | 
					     * Adds a new layer to the scene and returns it
 | 
				
			||||||
     * @param name The name of the new layer
 | 
					     * @param name The name of the new layer
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,9 @@ export default class SceneManager {
 | 
				
			||||||
	/** The RenderingManager of the game */
 | 
						/** The RenderingManager of the game */
 | 
				
			||||||
	protected renderingManager: RenderingManager;
 | 
						protected renderingManager: RenderingManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** For consistency, only change scenes at the beginning of the update cycle */
 | 
				
			||||||
 | 
						protected pendingScene: Scene;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Creates a new SceneManager
 | 
						 * Creates a new SceneManager
 | 
				
			||||||
	 * @param viewport The Viewport of the game
 | 
						 * @param viewport The Viewport of the game
 | 
				
			||||||
| 
						 | 
					@ -42,8 +45,16 @@ export default class SceneManager {
 | 
				
			||||||
	 * @param constr The constructor of the scene to add
 | 
						 * @param constr The constructor of the scene to add
 | 
				
			||||||
	 * @param init An object to pass to the init function of the new scene
 | 
						 * @param init An object to pass to the init function of the new scene
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public addScene<T extends Scene>(constr: new (...args: any) => T, init?: Record<string, any>, options?: Record<string, any>): void {
 | 
						public changeToScene<T extends Scene>(constr: new (...args: any) => T, init?: Record<string, any>, options?: Record<string, any>): void {
 | 
				
			||||||
 | 
							this.viewport.setCenter(this.viewport.getHalfSize().x, this.viewport.getHalfSize().y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		let scene = new constr(this.viewport, this, this.renderingManager, options);
 | 
							let scene = new constr(this.viewport, this, this.renderingManager, options);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(this.currentScene){
 | 
				
			||||||
 | 
								console.log("Destroying Old Scene");
 | 
				
			||||||
 | 
								this.currentScene.destroy();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		this.currentScene = scene;
 | 
							this.currentScene = scene;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		scene.initScene(init);
 | 
							scene.initScene(init);
 | 
				
			||||||
| 
						 | 
					@ -62,18 +73,6 @@ export default class SceneManager {
 | 
				
			||||||
		this.renderingManager.setScene(scene);
 | 
							this.renderingManager.setScene(scene);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Change from the current scene to this new scene.
 | 
					 | 
				
			||||||
	 * Use this method if you've created a subclass of Scene, and you want to add it as the main Scene.
 | 
					 | 
				
			||||||
	 * @param constr The constructor of the scene to change to
 | 
					 | 
				
			||||||
	 * @param init An object to pass to the init function of the new scene
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public changeScene<T extends Scene>(constr: new (...args: any) => T, init?: Record<string, any>, options?: Record<string, any>): void {
 | 
					 | 
				
			||||||
		this.viewport.setCenter(this.viewport.getHalfSize().x, this.viewport.getHalfSize().y);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		this.addScene(constr, init, options);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Generates a unique ID
 | 
						 * Generates a unique ID
 | 
				
			||||||
	 * @returns A new ID
 | 
						 * @returns A new ID
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,24 +7,17 @@ import ArrayUtils from "../Utils/ArrayUtils";
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export default class SceneOptions {
 | 
					export default class SceneOptions {
 | 
				
			||||||
    physics: {
 | 
					    physics: {
 | 
				
			||||||
        numPhysicsLayers: number,
 | 
					        groups: Array<string>,
 | 
				
			||||||
        physicsLayerNames: Array<string>,
 | 
					        collisions: Array<Array<number>>;
 | 
				
			||||||
        physicsLayerCollisions: Array<Array<number>>;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static parse(options: Record<string, any>): SceneOptions{
 | 
					    static parse(options: Record<string, any>): SceneOptions{
 | 
				
			||||||
        let sOpt = new SceneOptions();
 | 
					        let sOpt = new SceneOptions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        sOpt.physics = {
 | 
					        if(options.physics === undefined){
 | 
				
			||||||
            numPhysicsLayers: 10,
 | 
					            sOpt.physics = {groups: undefined, collisions: undefined};
 | 
				
			||||||
            physicsLayerNames: null,
 | 
					        } else {
 | 
				
			||||||
            physicsLayerCollisions: ArrayUtils.ones2d(10, 10)
 | 
					            sOpt.physics = options.physics;
 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(options.physics){
 | 
					 | 
				
			||||||
            if(options.physics.numPhysicsLayers)        sOpt.physics.numPhysicsLayers = options.physics.numPhysicsLayers;
 | 
					 | 
				
			||||||
            if(options.physics.physicsLayerNames)       sOpt.physics.physicsLayerNames = options.physics.physicsLayerNames;
 | 
					 | 
				
			||||||
            if(options.physics.physicsLayerCollisions)  sOpt.physics.physicsLayerCollisions = options.physics.physicsLayerCollisions;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return sOpt;
 | 
					        return sOpt;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,7 @@ export default abstract class SceneGraph {
 | 
				
			||||||
	/**	A reference to the viewport */
 | 
						/**	A reference to the viewport */
 | 
				
			||||||
	protected viewport: Viewport;
 | 
						protected viewport: Viewport;
 | 
				
			||||||
	/**	A map of CanvasNodes in this SceneGraph */
 | 
						/**	A map of CanvasNodes in this SceneGraph */
 | 
				
			||||||
	protected nodeMap: Map<CanvasNode>;
 | 
						protected nodeMap: Array<CanvasNode>;
 | 
				
			||||||
	/** A counter of IDs for nodes in this SceneGraph */
 | 
						/** A counter of IDs for nodes in this SceneGraph */
 | 
				
			||||||
	protected idCounter: number;
 | 
						protected idCounter: number;
 | 
				
			||||||
	/** A reference to the Scene this SceneGraph belongs to */
 | 
						/** A reference to the Scene this SceneGraph belongs to */
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@ export default abstract class SceneGraph {
 | 
				
			||||||
    constructor(viewport: Viewport, scene: Scene){
 | 
					    constructor(viewport: Viewport, scene: Scene){
 | 
				
			||||||
		this.viewport = viewport;
 | 
							this.viewport = viewport;
 | 
				
			||||||
		this.scene = scene;
 | 
							this.scene = scene;
 | 
				
			||||||
		this.nodeMap = new Map<CanvasNode>();
 | 
							this.nodeMap = new Array();
 | 
				
			||||||
		this.idCounter = 0;
 | 
							this.idCounter = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,8 +38,8 @@ export default abstract class SceneGraph {
 | 
				
			||||||
	 * @returns The SceneGraph ID of this newly added CanvasNode
 | 
						 * @returns The SceneGraph ID of this newly added CanvasNode
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
    addNode(node: CanvasNode): number {
 | 
					    addNode(node: CanvasNode): number {
 | 
				
			||||||
		this.nodeMap.add(this.idCounter.toString(), node);
 | 
							this.nodeMap[node.id] = node;
 | 
				
			||||||
		this.addNodeSpecific(node, this.idCounter.toString());
 | 
							this.addNodeSpecific(node, this.idCounter);
 | 
				
			||||||
		this.idCounter += 1;
 | 
							this.idCounter += 1;
 | 
				
			||||||
		return this.idCounter - 1;
 | 
							return this.idCounter - 1;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
| 
						 | 
					@ -49,7 +49,7 @@ export default abstract class SceneGraph {
 | 
				
			||||||
	 * @param node The node to add to the data structure
 | 
						 * @param node The node to add to the data structure
 | 
				
			||||||
	 * @param id The id of the CanvasNode
 | 
						 * @param id The id of the CanvasNode
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	protected abstract addNodeSpecific(node: CanvasNode, id: string): void;
 | 
						protected abstract addNodeSpecific(node: CanvasNode, id: number): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Removes a node from the SceneGraph
 | 
						 * Removes a node from the SceneGraph
 | 
				
			||||||
| 
						 | 
					@ -57,12 +57,8 @@ export default abstract class SceneGraph {
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
    removeNode(node: CanvasNode): void {
 | 
					    removeNode(node: CanvasNode): void {
 | 
				
			||||||
		// Find and remove node in O(n)
 | 
							// Find and remove node in O(n)
 | 
				
			||||||
		// TODO: Can this be better?
 | 
							this.nodeMap[node.id] = undefined;
 | 
				
			||||||
		let id = this.nodeMap.keys().filter((key: string) => this.nodeMap.get(key) === node)[0];
 | 
							this.removeNodeSpecific(node, node.id);
 | 
				
			||||||
		if(id !== undefined){
 | 
					 | 
				
			||||||
			this.nodeMap.set(id, undefined);
 | 
					 | 
				
			||||||
			this.removeNodeSpecific(node, id);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
| 
						 | 
					@ -70,15 +66,15 @@ export default abstract class SceneGraph {
 | 
				
			||||||
	 * @param node The node to remove
 | 
						 * @param node The node to remove
 | 
				
			||||||
	 * @param id The id of the node to remove
 | 
						 * @param id The id of the node to remove
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	protected abstract removeNodeSpecific(node: CanvasNode, id: string): void;
 | 
						protected abstract removeNodeSpecific(node: CanvasNode, id: number): void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Get a specific node using its id
 | 
						 * Get a specific node using its id
 | 
				
			||||||
	 * @param id The id of the CanvasNode to retrieve
 | 
						 * @param id The id of the CanvasNode to retrieve
 | 
				
			||||||
	 * @returns The node with this ID
 | 
						 * @returns The node with this ID
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	getNode(id: string): CanvasNode {
 | 
						getNode(id: number): CanvasNode {
 | 
				
			||||||
		return this.nodeMap.get(id);
 | 
							return this.nodeMap[id];
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
| 
						 | 
					@ -108,7 +104,11 @@ export default abstract class SceneGraph {
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	getAllNodes(): Array<CanvasNode> {
 | 
						getAllNodes(): Array<CanvasNode> {
 | 
				
			||||||
		let arr = new Array<CanvasNode>();
 | 
							let arr = new Array<CanvasNode>();
 | 
				
			||||||
		this.nodeMap.forEach(key => arr.push(this.nodeMap.get(key)));
 | 
							for(let i = 0; i < this.nodeMap.length; i++){
 | 
				
			||||||
 | 
								if(this.nodeMap[i] !== undefined){
 | 
				
			||||||
 | 
									arr.push(this.nodeMap[i]);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return arr;
 | 
							return arr;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,12 +24,12 @@ export default class SceneGraphArray extends SceneGraph {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // @override
 | 
					    // @override
 | 
				
			||||||
    protected addNodeSpecific(node: CanvasNode, id: string): void {
 | 
					    protected addNodeSpecific(node: CanvasNode, id: number): void {
 | 
				
			||||||
        this.nodeList.push(node);
 | 
					        this.nodeList.push(node);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // @override
 | 
					    // @override
 | 
				
			||||||
    protected removeNodeSpecific(node: CanvasNode, id: string): void {
 | 
					    protected removeNodeSpecific(node: CanvasNode, id: number): void {
 | 
				
			||||||
        let index = this.nodeList.indexOf(node);
 | 
					        let index = this.nodeList.indexOf(node);
 | 
				
			||||||
        if(index > -1){
 | 
					        if(index > -1){
 | 
				
			||||||
            this.nodeList.splice(index, 1);
 | 
					            this.nodeList.splice(index, 1);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,12 +31,12 @@ export default class SceneGraphQuadTree extends SceneGraph {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // @override
 | 
					    // @override
 | 
				
			||||||
    protected addNodeSpecific(node: CanvasNode, id: string): void {
 | 
					    protected addNodeSpecific(node: CanvasNode, id: number): void {
 | 
				
			||||||
        this.nodes.push(node);
 | 
					        this.nodes.push(node);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // @override
 | 
					    // @override
 | 
				
			||||||
    protected removeNodeSpecific(node: CanvasNode, id: string): void {
 | 
					    protected removeNodeSpecific(node: CanvasNode, id: number): void {
 | 
				
			||||||
        let index = this.nodes.indexOf(node);
 | 
					        let index = this.nodes.indexOf(node);
 | 
				
			||||||
        if(index >= 0){
 | 
					        if(index >= 0){
 | 
				
			||||||
            this.nodes.splice(index, 1);
 | 
					            this.nodes.splice(index, 1);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,12 +4,24 @@ import TimerManager from "./TimerManager";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class Timer implements Updateable {
 | 
					export default class Timer implements Updateable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** The current state of this timer */
 | 
				
			||||||
    protected state: TimerState;
 | 
					    protected state: TimerState;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /** The function to call when this timer ends */
 | 
				
			||||||
    protected onEnd: Function;
 | 
					    protected onEnd: Function;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Whether or not this timer should loop */
 | 
				
			||||||
    protected loop: boolean;
 | 
					    protected loop: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** The total amount of time this timer runs for */
 | 
				
			||||||
    protected totalTime: number;
 | 
					    protected totalTime: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** The amount of time left on the current run */
 | 
				
			||||||
    protected timeLeft: number;
 | 
					    protected timeLeft: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** The number of times this timer has been run */
 | 
				
			||||||
 | 
					    protected numRuns: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(time: number, onEnd?: Function, loop: boolean = false){
 | 
					    constructor(time: number, onEnd?: Function, loop: boolean = false){
 | 
				
			||||||
        // Register this timer
 | 
					        // Register this timer
 | 
				
			||||||
        TimerManager.getInstance().addTimer(this);
 | 
					        TimerManager.getInstance().addTimer(this);
 | 
				
			||||||
| 
						 | 
					@ -19,6 +31,7 @@ export default class Timer implements Updateable {
 | 
				
			||||||
        this.onEnd = onEnd;
 | 
					        this.onEnd = onEnd;
 | 
				
			||||||
        this.loop = loop;
 | 
					        this.loop = loop;
 | 
				
			||||||
        this.state = TimerState.STOPPED;
 | 
					        this.state = TimerState.STOPPED;
 | 
				
			||||||
 | 
					        this.numRuns = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    isStopped(){
 | 
					    isStopped(){
 | 
				
			||||||
| 
						 | 
					@ -29,6 +42,14 @@ export default class Timer implements Updateable {
 | 
				
			||||||
        return this.state === TimerState.PAUSED;
 | 
					        return this.state === TimerState.PAUSED;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns whether or not this timer has been run before
 | 
				
			||||||
 | 
					     * @returns true if it has been run at least once (after the latest reset), and false otherwise
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    hasRun(): boolean {
 | 
				
			||||||
 | 
					        return this.numRuns > 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    start(time?: number){
 | 
					    start(time?: number){
 | 
				
			||||||
        if(time !== undefined){
 | 
					        if(time !== undefined){
 | 
				
			||||||
            this.totalTime = time;
 | 
					            this.totalTime = time;
 | 
				
			||||||
| 
						 | 
					@ -37,6 +58,12 @@ export default class Timer implements Updateable {
 | 
				
			||||||
        this.timeLeft = this.totalTime;
 | 
					        this.timeLeft = this.totalTime;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Resets this timer. Sets the progress back to zero, and sets the number of runs back to zero */
 | 
				
			||||||
 | 
					    reset(){
 | 
				
			||||||
 | 
					        this.timeLeft = this.totalTime;
 | 
				
			||||||
 | 
					        this.numRuns = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pause(): void {
 | 
					    pause(): void {
 | 
				
			||||||
        this.state = TimerState.PAUSED;
 | 
					        this.state = TimerState.PAUSED;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -55,6 +82,7 @@ export default class Timer implements Updateable {
 | 
				
			||||||
    protected end(){
 | 
					    protected end(){
 | 
				
			||||||
        // Update the state
 | 
					        // Update the state
 | 
				
			||||||
        this.state = TimerState.STOPPED;
 | 
					        this.state = TimerState.STOPPED;
 | 
				
			||||||
 | 
					        this.numRuns += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Call the end function if there is one
 | 
					        // Call the end function if there is one
 | 
				
			||||||
        if(this.onEnd){
 | 
					        if(this.onEnd){
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
 | 
					import ControllerAI from "../Wolfie2D/AI/ControllerAI";
 | 
				
			||||||
import AI from "../Wolfie2D/DataTypes/Interfaces/AI";
 | 
					import AI from "../Wolfie2D/DataTypes/Interfaces/AI";
 | 
				
			||||||
import Emitter from "../Wolfie2D/Events/Emitter";
 | 
					import Emitter from "../Wolfie2D/Events/Emitter";
 | 
				
			||||||
import GameEvent from "../Wolfie2D/Events/GameEvent";
 | 
					import GameEvent from "../Wolfie2D/Events/GameEvent";
 | 
				
			||||||
| 
						 | 
					@ -5,8 +6,8 @@ import { GameEventType } from "../Wolfie2D/Events/GameEventType";
 | 
				
			||||||
import Input from "../Wolfie2D/Input/Input";
 | 
					import Input from "../Wolfie2D/Input/Input";
 | 
				
			||||||
import AnimatedSprite from "../Wolfie2D/Nodes/Sprites/AnimatedSprite";
 | 
					import AnimatedSprite from "../Wolfie2D/Nodes/Sprites/AnimatedSprite";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class PlayerController implements AI {
 | 
					export default class PlayerController extends ControllerAI {
 | 
				
			||||||
    protected owner: AnimatedSprite;
 | 
					    public owner: AnimatedSprite;
 | 
				
			||||||
    protected jumpSoundKey: string;
 | 
					    protected jumpSoundKey: string;
 | 
				
			||||||
    protected emitter: Emitter;
 | 
					    protected emitter: Emitter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,6 +39,11 @@
 | 
				
			||||||
        left: 0px;
 | 
					        left: 0px;
 | 
				
			||||||
        pointer-events: none;
 | 
					        pointer-events: none;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @font-face {
 | 
				
			||||||
 | 
					        font-family: 'NoPixel';
 | 
				
			||||||
 | 
					        src: url('hw4_assets/fonts/NoPixel.ttf');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    </style>
 | 
					    </style>
 | 
				
			||||||
  </head>
 | 
					  </head>
 | 
				
			||||||
  <body>
 | 
					  <body>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								src/main.ts
									
									
									
									
									
								
							| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
import Game from "./Wolfie2D/Loop/Game";
 | 
					import Game from "./Wolfie2D/Loop/Game";
 | 
				
			||||||
import default_scene from "./default_scene";
 | 
					import MainMenu from "./Homework4/Scenes/MainMenu";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The main function is your entrypoint into Wolfie2D. Specify your first scene and any options here.
 | 
					// The main function is your entrypoint into Wolfie2D. Specify your first scene and any options here.
 | 
				
			||||||
(function main(){
 | 
					(function main(){
 | 
				
			||||||
| 
						 | 
					@ -9,8 +9,14 @@ import default_scene from "./default_scene";
 | 
				
			||||||
    // Set up options for our game
 | 
					    // Set up options for our game
 | 
				
			||||||
    let options = {
 | 
					    let options = {
 | 
				
			||||||
        canvasSize: {x: 1200, y: 800},          // The size of the game
 | 
					        canvasSize: {x: 1200, y: 800},          // The size of the game
 | 
				
			||||||
        clearColor: {r: 0.1, g: 0.1, b: 0.1},   // The color the game clears to
 | 
					        clearColor: {r: 34, g: 32, b: 52},   // The color the game clears to
 | 
				
			||||||
        useWebGL: true,                        // Tell the game we want to use webgl
 | 
					        inputs: [
 | 
				
			||||||
 | 
					            {name: "left", keys: ["a"]},
 | 
				
			||||||
 | 
					            {name: "right", keys: ["d"]},
 | 
				
			||||||
 | 
					            {name: "jump", keys: ["w", "space"]},
 | 
				
			||||||
 | 
					            {name: "run", keys: ["shift"]}
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        useWebGL: false,                        // Tell the game we want to use webgl
 | 
				
			||||||
        showDebug: false                       // Whether to show debug messages. You can change this to true if you want
 | 
					        showDebug: false                       // Whether to show debug messages. You can change this to true if you want
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +24,7 @@ import default_scene from "./default_scene";
 | 
				
			||||||
    const game = new Game(options);
 | 
					    const game = new Game(options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Start our game
 | 
					    // Start our game
 | 
				
			||||||
    game.start(default_scene, {});
 | 
					    game.start(MainMenu, {});
 | 
				
			||||||
})();
 | 
					})();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function runTests(){};
 | 
					function runTests(){};
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user