implement left jump/left drop tracing in trace-jump.sml, and verified that it works

This commit is contained in:
2025-01-29 23:04:28 +00:00
parent 89abab31ab
commit d55126b52a
3 changed files with 139 additions and 147 deletions

View File

@@ -249,9 +249,8 @@ struct
* So, if we check for jump first, we would always jump before dropping * So, if we check for jump first, we would always jump before dropping
* even if jumping is not necessary. *) * even if jumping is not necessary. *)
if TraceJump.traceRightDrop (enemy, #id nextPlatform, platformTree) then if TraceJump.traceRightDrop (enemy, #id nextPlatform, platformTree) then
EnemyPatch.W_Y_AXIS DROP_BELOW_PLATFORM :: EnemyPatch.W_Y_AXIS DROP_BELOW_PLATFORM :: EnemyPatch.W_X_AXIS MOVE_RIGHT
EnemyPatch.W_X_AXIS MOVE_RIGHT :: :: acc
acc
else if TraceJump.traceRightJump (enemy, #id nextPlatform, platformTree) then else if TraceJump.traceRightJump (enemy, #id nextPlatform, platformTree) then
if standingOnArea (enemy, platformTree) then if standingOnArea (enemy, platformTree) then
EnemyPatch.W_Y_AXIS (JUMPING 0) :: EnemyPatch.W_X_AXIS MOVE_RIGHT :: acc EnemyPatch.W_Y_AXIS (JUMPING 0) :: EnemyPatch.W_X_AXIS MOVE_RIGHT :: acc
@@ -261,79 +260,16 @@ struct
EnemyPatch.W_X_AXIS MOVE_RIGHT :: acc EnemyPatch.W_X_AXIS MOVE_RIGHT :: acc
fun getMoveLeftPatches (nextPlatform, enemy, platformTree, acc) = fun getMoveLeftPatches (nextPlatform, enemy, platformTree, acc) =
let if TraceJump.traceLeftDrop (enemy, #id nextPlatform, platformTree) then
val {x = platX, y = platY, width = platWidth, ...} = nextPlatform EnemyPatch.W_Y_AXIS DROP_BELOW_PLATFORM :: EnemyPatch.W_X_AXIS MOVE_LEFT
val platFinishX = platX + platWidth :: acc
else if TraceJump.traceLeftJump (enemy, #id nextPlatform, platformTree) then
val {x = ex, y = ey, yAxis = eyAxis, ...} = enemy
val xDiff = ex - platX
in
if ey > platY then
(* enemy is lower than next platform so needs to jump *)
let
val jumpAmt =
case eyAxis of
JUMPING amt => amt
| _ => 0
val apexY = ey - (Constants.jumpLimit - jumpAmt)
val yDiff = platY - apexY
in
if yDiff <= xDiff then
(* enemy can reach platform by jumping *)
let
val acc =
if standingOnArea (enemy, platformTree) then if standingOnArea (enemy, platformTree) then
EnemyPatch.W_Y_AXIS (JUMPING 0) :: acc EnemyPatch.W_Y_AXIS (JUMPING 0) :: EnemyPatch.W_X_AXIS MOVE_LEFT :: acc
else
acc
in
EnemyPatch.W_X_AXIS MOVE_LEFT :: acc
end
else else
EnemyPatch.W_X_AXIS MOVE_LEFT :: acc EnemyPatch.W_X_AXIS MOVE_LEFT :: acc
end
else else
(* platform is below or at same y coordinat as enemy
* so might possibly require dropping below rather than jumping. *)
let
(* check if we can get to next platform without jumping.
* If we can, then simply move rightwards
* and possibly drop below platform.
* Else, jump and move rightwards *)
val yDiff = platY - ey
in
if yDiff >= xDiff then
(* can reach next platform by simply dropping and moving left *)
EnemyPatch.W_Y_AXIS DROP_BELOW_PLATFORM
:: EnemyPatch.W_X_AXIS MOVE_LEFT :: acc
else
let
val jumpAmt =
case eyAxis of
JUMPING amt => amt
| _ => 0
val apexY = ey - (Constants.jumpLimit - jumpAmt)
val yDiff = platY - apexY
in
if yDiff <= xDiff then
(* can reach if we jump and move left *)
let
val acc =
if standingOnArea (enemy, platformTree) then
EnemyPatch.W_Y_AXIS (JUMPING 0) :: acc
else
acc
in
EnemyPatch.W_X_AXIS MOVE_LEFT :: acc EnemyPatch.W_X_AXIS MOVE_LEFT :: acc
end
else
(* cannot reach yet so move left until we can *)
EnemyPatch.W_X_AXIS MOVE_LEFT :: acc
end
end
end
(* get patches to help enemy move to nextPlatformID *) (* get patches to help enemy move to nextPlatformID *)
fun getPathToNextPlatform fun getPathToNextPlatform
@@ -368,8 +304,7 @@ struct
* then move enemy left/right to make them fully overlap with platform *) * then move enemy left/right to make them fully overlap with platform *)
fun getHorizontalLandingPatches (enemy, nextPlatform, acc) = fun getHorizontalLandingPatches (enemy, nextPlatform, acc) =
case #xAxis enemy of case #xAxis enemy of
STAY_STILL => STAY_STILL => acc
acc
| _ => | _ =>
let let
val {x = px, width = pw, ...} = nextPlatform val {x = px, width = pw, ...} = nextPlatform
@@ -427,15 +362,12 @@ struct
STAY_STILL => STAY_STILL =>
let let
val acc = val acc =
if #x player <= #x enemy then if #x player <= #x enemy then EnemyPatch.W_X_AXIS MOVE_RIGHT :: acc
EnemyPatch.W_X_AXIS MOVE_RIGHT :: acc else EnemyPatch.W_X_AXIS MOVE_LEFT :: acc
else
EnemyPatch.W_X_AXIS MOVE_LEFT :: acc
in in
acc acc
end end
| _ => | _ => getPatrollPatches (enemy, wallTree, platformTree, acc)
getPatrollPatches (enemy, wallTree, platformTree, acc)
fun getFollowPatches fun getFollowPatches
(player: player, enemy, wallTree, platformTree, platforms, acc) = (player: player, enemy, wallTree, platformTree, platforms, acc) =
@@ -466,8 +398,7 @@ struct
nextPlatformID :: _ => nextPlatformID :: _ =>
let let
val acc = EnemyPatch.W_NEXT_PLAT_ID nextPlatformID :: acc val acc = EnemyPatch.W_NEXT_PLAT_ID nextPlatformID :: acc
val acc = val acc = getPathToNextPlatform
getPathToNextPlatform
( nextPlatformID ( nextPlatformID
, platforms , platforms
, platformTree , platformTree
@@ -479,7 +410,8 @@ struct
in in
EnemyPatch.W_X_AXIS STAY_STILL :: acc EnemyPatch.W_X_AXIS STAY_STILL :: acc
end end
| [] => startPatrolPatches (player, enemy, wallTree, platformTree, acc) | [] =>
startPatrolPatches (player, enemy, wallTree, platformTree, acc)
end end
end end

View File

@@ -168,13 +168,13 @@ struct
val walls = Vector.fromList [wall1, wall2, wall3] val walls = Vector.fromList [wall1, wall2, wall3]
val wallTree = Wall.generateTree walls val wallTree = Wall.generateTree walls
val plat1 = {id = 1, x = 155, y = 911, width = 199} val plat1 = {id = 1, x = 111, y = 711, width = 199}
val plat2 = {id = 2, x = 355, y = 759, width = 555} val plat2 = {id = 2, x = 355, y = 759, width = 555}
val plat3 = {id = 3, x = 355, y = 659, width = 111} val plat3 = {id = 3, x = 955, y = 659, width = 111}
val plat4 = {id = 4, x = 155, y = 855, width = 99} val plat4 = {id = 4, x = 455, y = 855, width = 99}
val plat5 = {id = 5, x = 155, y = 811, width = 199} val plat5 = {id = 5, x = 555, y = 811, width = 199}
val plat6 = {id = 6, x = 155, y = 710, width = 199} val plat6 = {id = 6, x = 655, y = 710, width = 199}
val plat7 = {id = 7, x = 301, y = 855, width = 99} val plat7 = {id = 7, x = 701, y = 855, width = 99}
val plat8 = {id = 8, x = 970, y = 815, width = 303} val plat8 = {id = 8, x = 970, y = 815, width = 303}
val plat9 = {id = 9, x = 959, y = 705, width = 303} val plat9 = {id = 9, x = 959, y = 705, width = 303}
val plat10 = {id = 10, x = 970, y = 759, width = 303} val plat10 = {id = 10, x = 970, y = 759, width = 303}
@@ -184,9 +184,9 @@ struct
val plat14 = {id = 14, x = 1000, y = 415, width = 303} val plat14 = {id = 14, x = 1000, y = 415, width = 303}
val plat15 = {id = 15, x = 1000, y = 335, width = 303} val plat15 = {id = 15, x = 1000, y = 335, width = 303}
val plat16 = {id = 16, x = 1000, y = 295, width = 303} val plat16 = {id = 16, x = 1000, y = 295, width = 303}
val plat17 = {id = 17, x = 155, y = 599, width = 199} val plat17 = {id = 17, x = 855, y = 599, width = 199}
val plat18 = {id = 18, x = 155, y = 499, width = 199} val plat18 = {id = 18, x = 755, y = 499, width = 199}
val plat19 = {id = 19, x = 155, y = 399, width = 199} val plat19 = {id = 19, x = 655, y = 399, width = 199}
val platforms = Vector.fromList val platforms = Vector.fromList
[ plat1 [ plat1
, plat2 , plat2
@@ -212,8 +212,8 @@ struct
val enemy1 = val enemy1 =
{ id = 1 { id = 1
, x = 251 , x = 751
, y = 855 , y = 555
, health = 1 , health = 1
, xAxis = STAY_STILL , xAxis = STAY_STILL
, yAxis = FALLING , yAxis = FALLING

View File

@@ -1,6 +1,8 @@
structure TraceJump = structure TraceJump =
struct struct
structure Trace = MakeQuadTreeFold (struct structure Trace =
MakeQuadTreeFold
(struct
type env = int type env = int
type state = bool type state = bool
@@ -8,7 +10,7 @@ struct
hasFoundNextPlatID orelse foldPlatID = nextPlatID hasFoundNextPlatID orelse foldPlatID = nextPlatID
end) end)
fun traceRightJumpDescent (x, y, nextPlatID, platTree) = fun traceRightDescent (x, y, nextPlatID, platTree) =
if x >= Constants.worldWidth orelse y >= Constants.worldHeight then if x >= Constants.worldWidth orelse y >= Constants.worldHeight then
(* we hit bounds of screen and saw that there was (* we hit bounds of screen and saw that there was
* no way to jump to next nextPlatID *) * no way to jump to next nextPlatID *)
@@ -17,62 +19,120 @@ struct
let let
val width = Constants.moveEnemyBy val width = Constants.moveEnemyBy
val height = Constants.worldHeight - y val height = Constants.worldHeight - y
val shouldJumpRight = val shouldJumpRight = Trace.foldRegion
Trace.foldRegion (x, y, width, height, nextPlatID, false, platTree) (x, y, width, height, nextPlatID, false, platTree)
val nextX = x + Constants.moveEnemyBy val nextX = x + Constants.moveEnemyBy
val nextY = y + Constants.moveEnemyBy val nextY = y + Constants.moveEnemyBy
in in
shouldJumpRight orelse shouldJumpRight
traceRightJumpDescent (nextX, nextY, nextPlatID, platTree) orelse traceRightDescent (nextX, nextY, nextPlatID, platTree)
end end
fun traceRightDrop (enemy, nextPlatID, platTree) = fun traceRightDrop (enemy: GameType.enemy, nextPlatID, platTree) =
let let
open GameType val {x, y, ...} = enemy
val {x, y, ...}: enemy = enemy
val x = x - Constants.enemySize val x = x - Constants.enemySize
in in
traceRightJumpDescent (x, y, nextPlatID, platTree) traceRightDescent (x, y, nextPlatID, platTree)
end end
fun traceRightJumpAscent (x, y, remainingJump, nextPlatID, platTree) = fun traceRightJumpAscent (x, y, remainingJump, nextPlatID, platTree) =
if remainingJump >= Constants.jumpLimit then if remainingJump >= Constants.jumpLimit then
traceRightJumpDescent (x, y, nextPlatID, platTree) traceRightDescent (x, y, nextPlatID, platTree)
else else
let let
val width = Constants.moveEnemyBy val width = Constants.moveEnemyBy
val height = Constants.worldHeight - y val height = Constants.worldHeight - y
val shouldJumpRight = val shouldJumpRight = Trace.foldRegion
Trace.foldRegion (x, y, width, height, nextPlatID, false, platTree) (x, y, width, height, nextPlatID, false, platTree)
val nextX = x + Constants.moveEnemyBy val nextX = x + Constants.moveEnemyBy
val nextY = y - Constants.moveEnemyBy val nextY = y - Constants.moveEnemyBy
val nextJump = remainingJump + Constants.moveEnemyBy val nextJump = remainingJump + Constants.moveEnemyBy
in in
shouldJumpRight orelse shouldJumpRight
orelse
traceRightJumpAscent (nextX, nextY, nextJump, nextPlatID, platTree) traceRightJumpAscent (nextX, nextY, nextJump, nextPlatID, platTree)
end end
fun traceRightJump (enemy, nextPlatID, platTree) = fun traceRightJump (enemy: GameType.enemy, nextPlatID, platTree) =
let let
open GameType val {x, y, ...} = enemy
val {x, y, ...}: enemy = enemy
val x = x - Constants.enemySize val x = x - Constants.enemySize
open GameType
in in
if EnemyPhysics.standingOnArea (x, y, platTree) then if EnemyPhysics.standingOnArea (x, y, platTree) then
traceRightJumpAscent (x, y, 0, nextPlatID, platTree) traceRightJumpAscent (x, y, 0, nextPlatID, platTree)
else else
case #yAxis enemy of case #yAxis enemy of
JUMPING amt => JUMPING amt => traceRightJumpAscent (x, y, amt, nextPlatID, platTree)
traceRightJumpAscent (x, y, amt, nextPlatID, platTree) | ON_GROUND => traceRightJumpAscent (x, y, 0, nextPlatID, platTree)
| ON_GROUND => | FALLING => traceRightDescent (x, y, nextPlatID, platTree)
traceRightJumpAscent (x, y, 0, nextPlatID, platTree) | DROP_BELOW_PLATFORM => traceRightDescent (x, y, nextPlatID, platTree)
| FALLING => | FLOATING _ => traceRightDescent (x, y, nextPlatID, platTree)
traceRightJumpDescent (x, y, nextPlatID, platTree) end
| DROP_BELOW_PLATFORM =>
traceRightJumpDescent (x, y, nextPlatID, platTree) fun traceLeftDescent (x, y, nextPlatID, platTree) =
| FLOATING _ => if x <= 0 orelse y >= Constants.worldHeight then
traceRightJumpDescent (x, y, nextPlatID, platTree) false
else
let
val width = Constants.moveEnemyBy
val height = Constants.worldHeight - y
val shouldJumpLeft = Trace.foldRegion
(x, y, width, height, nextPlatID, false, platTree)
val nextX = x - Constants.moveEnemyBy
val nextY = y + Constants.moveEnemyBy
in
shouldJumpLeft
orelse traceRightDescent (nextX, nextY, nextPlatID, platTree)
end
fun traceLeftDrop (enemy: GameType.enemy, nextPlatID, platTree) =
let
val {x, y, ...} = enemy
val x = x + Constants.enemySize
in
traceLeftDescent (x, y, nextPlatID, platTree)
end
fun traceLeftJumpAscent (x, y, remainingJump, nextPlatID, platTree) =
if remainingJump >= Constants.jumpLimit then
traceLeftDescent (x, y, nextPlatID, platTree)
else
let
val width = Constants.moveEnemyBy
val height = Constants.worldHeight - y
val shouldJumpLeft = Trace.foldRegion
(x, y, width, height, nextPlatID, false, platTree)
val nextX = x - Constants.moveEnemyBy
val nextY = y - Constants.moveEnemyBy
val nextJump = remainingJump + Constants.moveEnemyBy
in
shouldJumpLeft
orelse
traceLeftJumpAscent (nextX, nextY, nextJump, nextPlatID, platTree)
end
fun traceLeftJump (enemy: GameType.enemy, nextPlatID, platTree) =
let
val {x, y, ...} = enemy
val x = x + Constants.enemySize
open GameType
in
if EnemyPhysics.standingOnArea (x, y, platTree) then
traceLeftJumpAscent (x, y, 0, nextPlatID, platTree)
else
case #yAxis enemy of
JUMPING amt => traceLeftJumpAscent (x, y, amt, nextPlatID, platTree)
| ON_GROUND => traceLeftJumpAscent (x, y, 0, nextPlatID, platTree)
| FALLING => traceLeftDescent (x, y, nextPlatID, platTree)
| DROP_BELOW_PLATFORM => traceLeftDescent (x, y, nextPlatID, platTree)
| FLOATING _ => traceLeftDescent (x, y, nextPlatID, platTree)
end end
end end