summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Vink <mike1994vink@gmail.com>2021-07-20 00:02:30 +0200
committerMike Vink <mike1994vink@gmail.com>2021-07-20 00:02:30 +0200
commit2384eb32984a17ae00bd894d81e5f7b4eb40bffa (patch)
treef70914732be0185d7da9d149536ae506a098d982
parenta159975d09c9160b89a733f2434b406d8f99dbb4 (diff)
feat(client): grid-based physics local
-rw-r--r--akkamon.tiled-session12
-rw-r--r--client/dist/assets/tilemaps/akkamon-demo-tilemap.json6
-rw-r--r--client/src/Direction.ts7
-rw-r--r--client/src/GridControls.ts24
-rw-r--r--client/src/GridPhysics.ts148
-rw-r--r--client/src/game.ts203
-rw-r--r--client/src/sprite.ts56
7 files changed, 285 insertions, 171 deletions
diff --git a/akkamon.tiled-session b/akkamon.tiled-session
index f36d16d..1430a8a 100644
--- a/akkamon.tiled-session
+++ b/akkamon.tiled-session
@@ -6,11 +6,11 @@
"activeFile": "client/dist/assets/tilemaps/akkamon-demo-tilemap.json",
"expandedProjectPaths": [
"client/dist/assets",
- "client/dist/assets/tilemaps",
- "client/dist",
"client/dist/assets/tilesets",
"client",
- "."
+ ".",
+ "client/dist/assets/tilemaps",
+ "client/dist"
],
"file.lastUsedOpenFilter": "All Files (*)",
"fileStates": {
@@ -19,10 +19,10 @@
"scaleInEditor": 1
},
"client/dist/assets/tilemaps/akkamon-demo-tilemap.json": {
- "scale": 0.5,
- "selectedLayer": 1,
+ "scale": 4,
+ "selectedLayer": 0,
"viewCenter": {
- "x": 604,
+ "x": 603.875,
"y": 829
}
},
diff --git a/client/dist/assets/tilemaps/akkamon-demo-tilemap.json b/client/dist/assets/tilemaps/akkamon-demo-tilemap.json
index 981bdc1..90b3091 100644
--- a/client/dist/assets/tilemaps/akkamon-demo-tilemap.json
+++ b/client/dist/assets/tilemaps/akkamon-demo-tilemap.json
@@ -3,7 +3,7 @@
"infinite":false,
"layers":[
{
- "data":[126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126],
+ "data":[126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 125, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126],
"height":40,
"id":1,
"name":"Below Player",
@@ -52,8 +52,8 @@
"type":"",
"visible":true,
"width":0,
- "x":576,
- "y":852
+ "x":592.25,
+ "y":853
}],
"opacity":1,
"type":"objectgroup",
diff --git a/client/src/Direction.ts b/client/src/Direction.ts
new file mode 100644
index 0000000..87484ad
--- /dev/null
+++ b/client/src/Direction.ts
@@ -0,0 +1,7 @@
+export enum Direction {
+ NONE = "none",
+ LEFT = "left",
+ UP = "up",
+ RIGHT = "right",
+ DOWN = "down",
+}
diff --git a/client/src/GridControls.ts b/client/src/GridControls.ts
new file mode 100644
index 0000000..9986b1f
--- /dev/null
+++ b/client/src/GridControls.ts
@@ -0,0 +1,24 @@
+import { Direction } from './Direction';
+import type { GridPhysics } from './GridPhysics';
+
+export class GridControls {
+ constructor(
+ private input: Phaser.Input.InputPlugin,
+ private gridPhysics: GridPhysics
+ ) { }
+
+ update() {
+ const cursors = this.input.keyboard.createCursorKeys();
+ if (cursors.left.isDown) {
+ this.gridPhysics.movePlayerSprite(Direction.LEFT);
+ } else if (cursors.right.isDown) {
+ this.gridPhysics.movePlayerSprite(Direction.RIGHT);
+ } else if (cursors.up.isDown) {
+ this.gridPhysics.movePlayerSprite(Direction.UP);
+ } else if (cursors.down.isDown) {
+ this.gridPhysics.movePlayerSprite(Direction.DOWN);
+ }
+ }
+
+
+}
diff --git a/client/src/GridPhysics.ts b/client/src/GridPhysics.ts
new file mode 100644
index 0000000..5fca10a
--- /dev/null
+++ b/client/src/GridPhysics.ts
@@ -0,0 +1,148 @@
+import Phaser from 'phaser';
+import type PlayerSprite from './sprite';
+import { Direction } from './Direction';
+import AkkamonStartScene from './game';
+
+export class GridPhysics {
+
+ private movementDirectionVectors: {
+ [key in Direction]?: Phaser.Math.Vector2;
+ } = {
+ [Direction.UP]: Phaser.Math.Vector2.UP,
+ [Direction.DOWN]: Phaser.Math.Vector2.DOWN,
+ [Direction.LEFT]: Phaser.Math.Vector2.LEFT,
+ [Direction.RIGHT]: Phaser.Math.Vector2.RIGHT,
+ }
+
+ private movementDirection: Direction = Direction.NONE;
+ private readonly speedPixelsPerSecond: number = AkkamonStartScene.TILE_SIZE * 4;
+
+ private tileSizePixelsWalked: number = 0;
+
+ private lastMovementIntent = Direction.NONE;
+
+ constructor(
+ private playerSprite: PlayerSprite,
+ private tileMap: Phaser.Tilemaps.Tilemap
+ ) { }
+
+ movePlayerSprite(direction: Direction): void {
+ this.lastMovementIntent = direction;
+
+ if (this.isMoving()) return;
+
+ if (this.isBlockingDirection(direction)) {
+ this.playerSprite.stopAnimation(direction);
+ } else {
+ this.startMoving(direction);
+ }
+ }
+
+ private isMoving(): boolean {
+ return this.movementDirection != Direction.NONE;
+ }
+
+ private startMoving(direction: Direction): void {
+ this.playerSprite.startAnimation(direction);
+ this.movementDirection = direction;
+ this.updatePlayerSpriteTilePosition();
+ }
+
+ update(delta: number): void {
+ if (this.isMoving()) {
+ this.updatePlayerSpritePosition(delta);
+ }
+ this.lastMovementIntent = Direction.NONE;
+ }
+
+ private updatePlayerSpritePosition(delta: number) {
+ const pixelsToWalkThisUpdate = this.getPixelsToWalkThisUpdate(delta);
+
+ if (!this.willCrossTileBorderThisUpdate(pixelsToWalkThisUpdate)) {
+ this.spriteMovement(pixelsToWalkThisUpdate);
+ } else if (this.shouldContinueMoving()) {
+ this.spriteMovement(pixelsToWalkThisUpdate);
+ this.updatePlayerSpriteTilePosition();
+ } else {
+ this.spriteMovement(AkkamonStartScene.TILE_SIZE - this.tileSizePixelsWalked);
+ this.stopMoving();
+ }
+ }
+
+ private updatePlayerSpriteTilePosition() {
+ this.playerSprite.setTilePos(
+ this.playerSprite
+ .getTilePos()
+ .add(this.movementDirectionVectors[this.movementDirection]!)
+ );
+ }
+
+ private shouldContinueMoving(): boolean {
+ return (
+ this.movementDirection == this.lastMovementIntent &&
+ !this.isBlockingDirection(this.lastMovementIntent)
+
+ );
+ }
+
+ private spriteMovement(pixelsToMove: number) {
+
+ this.tileSizePixelsWalked += pixelsToMove;
+ this.tileSizePixelsWalked %= AkkamonStartScene.TILE_SIZE;
+
+
+ const directionVec = this.movementDirectionVectors[
+ this.movementDirection
+ ]!.clone();
+
+ const movementDistance = directionVec.multiply(
+ new Phaser.Math.Vector2(pixelsToMove)
+ );
+
+ const newPlayerPos = this.playerSprite.getPosition().add(movementDistance);
+ this.playerSprite.newPosition(newPlayerPos);
+ }
+
+ private willCrossTileBorderThisUpdate(
+ pixelsToWalkThisUpdate: number
+ ): boolean {
+ return (
+ this.tileSizePixelsWalked + pixelsToWalkThisUpdate >= AkkamonStartScene.TILE_SIZE
+ );
+ }
+
+ private getPixelsToWalkThisUpdate(delta: number): number {
+ const deltaInSeconds = delta / 1000;
+ return this.speedPixelsPerSecond * deltaInSeconds;
+ }
+
+ private stopMoving(): void {
+ this.playerSprite.stopAnimation(this.movementDirection);
+ this.movementDirection = Direction.NONE;
+ }
+
+ private isBlockingDirection(direction: Direction): boolean {
+ return this.hasBlockingTile(this.tilePosInDirection(direction));
+ }
+
+ private tilePosInDirection(direction: Direction): Phaser.Math.Vector2 {
+ return this.playerSprite
+ .getTilePos()
+ .add(this.movementDirectionVectors[direction]!);
+ }
+
+ private hasBlockingTile(pos: Phaser.Math.Vector2): boolean {
+ if (this.hasNoTile(pos)) return true;
+ return this.tileMap.layers.some((layer) => {
+ const tile = this.tileMap.getTileAt(pos.x, pos.y, false, layer.name);
+ return tile && tile.properties.collides;
+ });
+ }
+
+ private hasNoTile(pos: Phaser.Math.Vector2): boolean {
+ return !this.tileMap.layers.some((layer) =>
+ this.tileMap.hasTileAt(pos.x, pos.y, layer.name));
+ }
+
+}
+
diff --git a/client/src/game.ts b/client/src/game.ts
index b9e19a0..6413aa0 100644
--- a/client/src/game.ts
+++ b/client/src/game.ts
@@ -3,6 +3,10 @@ import type Player from './player';
import Client from './client';
import GameState from './GameState';
import PlayerSprite from './sprite';
+import { GridControls } from './GridControls';
+import { GridPhysics } from './GridPhysics';
+import { Direction } from './Direction';
+
type RemotePlayerStates = {
[name: string]: Player
@@ -10,10 +14,26 @@ type RemotePlayerStates = {
export default class AkkamonStartScene extends Phaser.Scene
{
- currentPlayerSprite: PlayerSprite | undefined;
+
+ static readonly TILE_SIZE = 32;
+
+ private gridPhysics?: GridPhysics
+ private gridControls?: GridControls
+
+ directionToAnimation: {
+ [key in Direction]: string
+ } = {
+ [Direction.UP]: "misa-back-walk",
+ [Direction.DOWN]: "misa-front-walk",
+ [Direction.LEFT]: "misa-left-walk",
+ [Direction.RIGHT]: "misa-right-walk",
+ [Direction.NONE]: "misa-front-walk"
+ }
+
remotePlayerSprites: {[name: string]: PlayerSprite} = {};
spawnPoint: Phaser.Types.Tilemaps.TiledObject | undefined;
+
constructor ()
{
super('akkamonStartScene');
@@ -40,190 +60,77 @@ export default class AkkamonStartScene extends Phaser.Scene
create ()
{
const map = this.make.tilemap({ key: "map" });
-
// Parameters are the name you gave the tileset in Tiled and then the key of the tileset image in
// Phaser's cache (i.e. the name you used in preload)
const tileset = map.addTilesetImage("akkamon-demo-extruded", "tiles");
-
// Parameters: layer name (or index) from Tiled, tileset, x, y
const belowLayer = map.createLayer("Below Player", tileset, 0, 0);
const worldLayer = map.createLayer("World", tileset, 0, 0);
const aboveLayer = map.createLayer("Above Player", tileset, 0, 0);
-
- worldLayer.setCollisionByProperty({collides: true});
-
// By default, everything gets depth sorted on the screen in the order we created things. Here, we
// want the "Above Player" layer to sit on top of the player, so we explicitly give it a depth.
// Higher depths will sit on top of lower depth objects.
aboveLayer.setDepth(10);
- const spawnPoint = map.findObject("Objects", obj => obj.name === "Spawn Point");
- this.spawnPoint = spawnPoint;
+ this.spawnPoint = map.findObject("Objects", obj => obj.name === "Spawn Point");
+
+ //this.createPlayerAnimation(Direction.UP);
+
// Create a sprite with physics enabled via the physics system. The image used for the sprite has
// a bit of whitespace, so I'm using setSize & setOffset to control the size of the player's body.
-
let player = new PlayerSprite({
scene: this,
- x: spawnPoint.x!,
- y: spawnPoint.y!,
+ tilePos: new Phaser.Math.Vector2(
+ Math.floor(this.spawnPoint.x! / AkkamonStartScene.TILE_SIZE),
+ Math.floor(this.spawnPoint.y! / AkkamonStartScene.TILE_SIZE),
+ ),
texture: this.textures.get("atlas"),
frame: "misa-front",
player: GameState.getInstance().currentPlayer!,
- moveControls: this.input.keyboard.createCursorKeys()
});
- this.currentPlayerSprite = player;
-
- player
- .setSize(30, 40)
- .setOffset(0, 24);
this.add.existing(player);
- this.physics.add.existing(player);
- // GameState.getInstance().currentPlayer!.setSprite(player);
-
- this.physics.add.collider(player, worldLayer);
- console.log(player);
-
- // Create the player's walking animations from the texture atlas. These are stored in the global
- // animation manager so any sprite can access them.
- const anims = this.anims;
- anims.create({
- key: "misa-left-walk",
- frames: anims.generateFrameNames("atlas", { prefix: "misa-left-walk.", start: 0, end: 3, zeroPad: 3 }),
- frameRate: 10,
- repeat: -1
- });
- anims.create({
- key: "misa-right-walk",
- frames: anims.generateFrameNames("atlas", { prefix: "misa-right-walk.", start: 0, end: 3, zeroPad: 3 }),
- frameRate: 10,
- repeat: -1
- });
- anims.create({
- key: "misa-front-walk",
- frames: anims.generateFrameNames("atlas", { prefix: "misa-front-walk.", start: 0, end: 3, zeroPad: 3 }),
- frameRate: 10,
- repeat: -1
- });
- anims.create({
- key: "misa-back-walk",
- frames: anims.generateFrameNames("atlas", { prefix: "misa-back-walk.", start: 0, end: 3, zeroPad: 3 }),
- frameRate: 10,
- repeat: -1
- });
+ this.gridPhysics = new GridPhysics(player, map);
+ this.gridControls = new GridControls(
+ this.input,
+ this.gridPhysics
+ );
+ this.createPlayerAnimation(Direction.LEFT, 0, 3);
+ this.createPlayerAnimation(Direction.RIGHT, 0, 3);
+ this.createPlayerAnimation(Direction.UP, 0, 3);
+ this.createPlayerAnimation(Direction.DOWN, 0, 3);
// Phaser supports multiple cameras, but you can access the default camera like this:
const camera = this.cameras.main;
camera.startFollow(player);
- camera.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
-
- // Debug graphics
- this.input.keyboard.once("keydown_D", (event: Event) => {
- // Turn on physics debugging to show player's hitbox
- this.physics.world.createDebugGraphic();
-
- // Create worldLayer collision graphic above the player, but below the help text
- const graphics = this.add
- .graphics()
- .setAlpha(0.75)
- .setDepth(20);
-
- worldLayer.renderDebug(graphics, {
- tileColor: null, // Color of non-colliding tiles
- collidingTileColor: new Phaser.Display.Color(243, 134, 48, 255), // Color of colliding tiles
- faceColor: new Phaser.Display.Color(40, 39, 37, 255) // Color of colliding face edges
- });
-
- });
-
- // Constrain the camera so that it isn't allowed to move outside the width/height of tilemap
+ camera.roundPixels = true;
camera.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
}
- update(time: Number, delta: Number) {
- let playerSprite = this.currentPlayerSprite!;
-
- const speed = 175;
- const prevVelocity = playerSprite.body.velocity.clone();
-
- // Stop any previous movement from the last frame
- playerSprite.body.setVelocity(0);
-
- this.moveSprite(playerSprite, speed, prevVelocity)
-
- // update player state
- playerSprite.player.position = {
- x: playerSprite.x,
- y: playerSprite.y
- }
-
- if (GameState.getInstance().remotePlayers !== undefined) {
- this.renderRemotePlayers(GameState.getInstance().remotePlayers!);
- }
+ update(time: number, delta: number) {
+ this.gridControls!.update();
+ this.gridPhysics!.update(delta);
}
- renderRemotePlayers(remotePlayers: RemotePlayerStates) {
- console.log(remotePlayers);
-
- for (let playerName in remotePlayers) {
- if (playerName in this.remotePlayerSprites) {
- this.remotePlayerSprites[playerName].renderUpdate(remotePlayers[playerName].position);
- } else {
- let remotePlayer = remotePlayers[playerName];
- let remotePlayerSprite = new PlayerSprite({
- scene: this,
- x: remotePlayer.position.x,
- y: remotePlayer.position.y,
- texture: this.textures.get("atlas"),
- player: remotePlayer,
- });
- this.add.existing(remotePlayerSprite);
- this.remotePlayerSprites[playerName] = remotePlayerSprite;
- }
- }
- }
+ private createPlayerAnimation(direction: Direction, start: number, end: number) {
+ this.anims.create({
+ key: direction, // "misa-left-walk",
+ frames: this.anims.generateFrameNames("atlas", { prefix: this.directionToAnimation[direction] + ".", start: start, end: end, zeroPad: 3 }),
+ frameRate: 10,
+ repeat: -1
+ });
+
+// anims.create({
+// key: "misa-left-walk",
+// frames: anims.generateFrameNames("atlas", { prefix: "misa-left-walk.", start: 0, end: 3, zeroPad: 3 }),
+// frameRate: 10,
+// repeat: -1
- moveSprite(playerSprite: PlayerSprite, speed: number, prevVelocity: {x: number, y:number}) {
- let moveControls = playerSprite.moveControls!;
- // Horizontal movement
- if (moveControls.left.isDown) {
- playerSprite.body.setVelocityX(-speed);
- } else if (moveControls.right.isDown) {
- playerSprite.body.setVelocityX(speed);
- }
-
- // Vertical movement
- if (moveControls.up.isDown) {
- playerSprite.body.setVelocityY(-speed);
- } else if (moveControls.down.isDown) {
- playerSprite.body.setVelocityY(speed);
- }
-
- // Normalize and scale the velocity so that playerSprite can't move faster along a diagonal
- playerSprite.body.velocity.normalize().scale(speed);
-
- // Update the animation last and give left/right animations precedence over up/down animations
- if (moveControls.left.isDown) {
- playerSprite.anims.play("misa-left-walk", true);
- } else if (moveControls.right.isDown) {
- playerSprite.anims.play("misa-right-walk", true);
- } else if (moveControls.up.isDown) {
- playerSprite.anims.play("misa-back-walk", true);
- } else if (moveControls.down.isDown) {
- playerSprite.anims.play("misa-front-walk", true);
- } else {
- playerSprite.anims.stop();
- // If we were moving, pick and idle frame to use
- if (prevVelocity.x < 0) playerSprite.setTexture("atlas", "misa-left");
- else if (prevVelocity.x > 0) playerSprite.setTexture("atlas", "misa-right");
- else if (prevVelocity.y < 0) playerSprite.setTexture("atlas", "misa-back");
- else if (prevVelocity.y > 0) playerSprite.setTexture("atlas", "misa-front");
- }
}
}
diff --git a/client/src/sprite.ts b/client/src/sprite.ts
index a47d617..cf25ba0 100644
--- a/client/src/sprite.ts
+++ b/client/src/sprite.ts
@@ -1,38 +1,66 @@
import Phaser from 'phaser';
+import AkkamonStartScene from './game';
import type Player from './player';
+import type { Direction } from './Direction';
type PlayerSpriteConfig = {
scene: Phaser.Scene,
- x: number,
- y: number,
+ tilePos: Phaser.Math.Vector2,
texture: Phaser.Textures.Texture | string,
frame?: string,
player: Player,
- moveControls?: Phaser.Types.Input.Keyboard.CursorKeys;
}
-interface AkkamonDynamicSprite extends Phaser.Types.Physics.Arcade.SpriteWithDynamicBody {
+interface AkkamonPlayerSprite extends Phaser.GameObjects.Sprite {
player: Player
- moveControls: Phaser.Types.Input.Keyboard.CursorKeys | undefined
}
-export default class PlayerSprite extends Phaser.Physics.Arcade.Sprite implements AkkamonDynamicSprite {
+export default class PlayerSprite extends Phaser.GameObjects.Sprite implements AkkamonPlayerSprite {
- body: Phaser.Physics.Arcade.Body;
player: Player;
- moveControls: Phaser.Types.Input.Keyboard.CursorKeys | undefined;
+ tilePos: Phaser.Math.Vector2;
constructor(config: PlayerSpriteConfig) {
- super(config.scene, config.x, config.y, config.texture, config.frame!);
+ const offsetX = AkkamonStartScene.TILE_SIZE / 2;
+ const offsetY = AkkamonStartScene.TILE_SIZE;
+
+ super(config.scene,
+ config.tilePos.x * AkkamonStartScene.TILE_SIZE + offsetX,
+ config.tilePos.y * AkkamonStartScene.TILE_SIZE + offsetY,
+ config.texture,
+ config.frame);
- this.body = new Phaser.Physics.Arcade.Body(config.scene.physics.world, this);
this.player = config.player;
+ this.tilePos = new Phaser.Math.Vector2(config.tilePos.x, config.tilePos.y);
+
+ this.setOrigin(0.5, 1);
+ }
+
+ getPosition(): Phaser.Math.Vector2 {
+ return this.getBottomCenter();
+ }
+
+ newPosition(position: Phaser.Math.Vector2): void {
+ super.setPosition(position.x, position.y);
+ }
+
+ stopAnimation(direction: Direction) {
+ const animationManager = this.anims.animationManager;
+ const standingFrame = animationManager.get(direction).frames[1].frame.name;
+
+ this.anims.stop();
+ this.setFrame(standingFrame);
+ }
+
+ startAnimation(direction: Direction) {
+ this.anims.play(direction);
+ }
- if (config.moveControls) this.moveControls = config.moveControls;
+ getTilePos(): Phaser.Math.Vector2 {
+ return this.tilePos.clone();
}
- renderUpdate({x, y}: Player["position"]) {
- this.x = x;
- this.y = y;
+ setTilePos(tilePosition: Phaser.Math.Vector2): void {
+ this.tilePos = tilePosition.clone();
}
}