rip out player-enemy.sml and let player react to enemy collisions independently of enemy reaction to player
This commit is contained in:
@@ -5,22 +5,9 @@ struct
|
|||||||
val {player, walls, wallTree, platforms, platformTree, enemies, graph} =
|
val {player, walls, wallTree, platforms, platformTree, enemies, graph} =
|
||||||
game
|
game
|
||||||
|
|
||||||
val player = Player.runPhysicsAndInput (game, input)
|
|
||||||
|
|
||||||
val enemyTree = Enemy.generateTree enemies
|
val enemyTree = Enemy.generateTree enemies
|
||||||
|
val player = Player.runPhysicsAndInput (game, input, enemyTree)
|
||||||
|
|
||||||
(* check player-enemy collisions and react *)
|
|
||||||
val (player, enemies) = PlayerEnemy.checkCollisions
|
|
||||||
( player
|
|
||||||
, enemies
|
|
||||||
, enemyTree
|
|
||||||
, #projectiles player
|
|
||||||
, walls
|
|
||||||
, wallTree
|
|
||||||
, platforms
|
|
||||||
, platformTree
|
|
||||||
, graph
|
|
||||||
)
|
|
||||||
in
|
in
|
||||||
{ player = player
|
{ player = player
|
||||||
, walls = walls
|
, walls = walls
|
||||||
|
|||||||
@@ -1,122 +0,0 @@
|
|||||||
structure PlayerEnemy =
|
|
||||||
struct
|
|
||||||
open GameType
|
|
||||||
open PlayerPatch
|
|
||||||
|
|
||||||
fun checkCollisions
|
|
||||||
( player
|
|
||||||
, enemies
|
|
||||||
, enemyTree
|
|
||||||
, projectiles
|
|
||||||
, walls
|
|
||||||
, wallTree
|
|
||||||
, platforms
|
|
||||||
, platformTree
|
|
||||||
, graph
|
|
||||||
) =
|
|
||||||
let
|
|
||||||
val {x, y, mainAttack, attacked, ...} = player
|
|
||||||
val size = Constants.playerSize
|
|
||||||
val projectileTree = Projectile.generateTree projectiles
|
|
||||||
in
|
|
||||||
case mainAttack of
|
|
||||||
MAIN_ATTACKING =>
|
|
||||||
let
|
|
||||||
(* filter enemies based on collisions *)
|
|
||||||
val enemyCollisions =
|
|
||||||
Player.getEnemyCollisionsWhenAttacking (x, y, enemyTree)
|
|
||||||
val enemies = Enemy.filterWhenAttacked
|
|
||||||
( Vector.length enemies - 1
|
|
||||||
, enemyCollisions
|
|
||||||
, enemies
|
|
||||||
, projectileTree
|
|
||||||
, []
|
|
||||||
, walls
|
|
||||||
, wallTree
|
|
||||||
, platforms
|
|
||||||
, platformTree
|
|
||||||
, player
|
|
||||||
, graph
|
|
||||||
)
|
|
||||||
|
|
||||||
(* add collided enemies to player record,
|
|
||||||
* concatenating with the previous enemies defeated *)
|
|
||||||
val player = Player.concatAttackedEnemies (player, enemyCollisions)
|
|
||||||
in
|
|
||||||
(player, enemies)
|
|
||||||
end
|
|
||||||
| _ =>
|
|
||||||
(case attacked of
|
|
||||||
NOT_ATTACKED =>
|
|
||||||
let
|
|
||||||
val enemyCollisions = QuadTree.getCollisions
|
|
||||||
(x, y, size, size, ~1, enemyTree)
|
|
||||||
|
|
||||||
val player =
|
|
||||||
Player.enemyCollisionReaction
|
|
||||||
(player, enemies, enemyCollisions, [])
|
|
||||||
|
|
||||||
val enemies = Enemy.filterProjectileCollisions
|
|
||||||
( Vector.length enemies - 1
|
|
||||||
, enemies
|
|
||||||
, projectileTree
|
|
||||||
, []
|
|
||||||
, walls
|
|
||||||
, wallTree
|
|
||||||
, platforms
|
|
||||||
, platformTree
|
|
||||||
, player
|
|
||||||
, graph
|
|
||||||
)
|
|
||||||
in
|
|
||||||
(player, enemies)
|
|
||||||
end
|
|
||||||
| ATTACKED amt =>
|
|
||||||
if amt = Constants.attackedLimit then
|
|
||||||
(* if reached limit, detect enemies again *)
|
|
||||||
let
|
|
||||||
val enemyCollisions = QuadTree.getCollisions
|
|
||||||
(x, y, size, size, ~1, enemyTree)
|
|
||||||
|
|
||||||
val player =
|
|
||||||
Player.exitAttackedAndCheckEnemies
|
|
||||||
(player, enemies, enemyCollisions)
|
|
||||||
|
|
||||||
val enemies = Enemy.filterProjectileCollisions
|
|
||||||
( Vector.length enemies - 1
|
|
||||||
, enemies
|
|
||||||
, projectileTree
|
|
||||||
, []
|
|
||||||
, walls
|
|
||||||
, wallTree
|
|
||||||
, platforms
|
|
||||||
, platformTree
|
|
||||||
, player
|
|
||||||
, graph
|
|
||||||
)
|
|
||||||
in
|
|
||||||
(player, enemies)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
(* if attacked, don't detect collisions,
|
|
||||||
* allowing a brief invincibility period as is common in many games
|
|
||||||
* *)
|
|
||||||
let
|
|
||||||
val player = Player.incrementAttacked (player, amt)
|
|
||||||
val enemies = Enemy.filterProjectileCollisions
|
|
||||||
( Vector.length enemies - 1
|
|
||||||
, enemies
|
|
||||||
, projectileTree
|
|
||||||
, []
|
|
||||||
, walls
|
|
||||||
, wallTree
|
|
||||||
, platforms
|
|
||||||
, platformTree
|
|
||||||
, player
|
|
||||||
, graph
|
|
||||||
)
|
|
||||||
in
|
|
||||||
(player, enemies)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
174
fcore/player.sml
174
fcore/player.sml
@@ -228,7 +228,7 @@ struct
|
|||||||
acc
|
acc
|
||||||
end
|
end
|
||||||
|
|
||||||
fun getRecoilPatches (player, patches) =
|
fun getRecoilPatches (player: player, patches) =
|
||||||
case #recoil player of
|
case #recoil player of
|
||||||
NO_RECOIL => patches
|
NO_RECOIL => patches
|
||||||
| RECOIL_LEFT recoiled =>
|
| RECOIL_LEFT recoiled =>
|
||||||
@@ -300,7 +300,7 @@ struct
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
fun getProjectilePatches ({projectiles, ...}) =
|
fun getProjectilePatches ({projectiles, ...}: player) =
|
||||||
let
|
let
|
||||||
val newProjectiles = helpMoveProjectiles
|
val newProjectiles = helpMoveProjectiles
|
||||||
(Vector.length projectiles - 1, projectiles, [])
|
(Vector.length projectiles - 1, projectiles, [])
|
||||||
@@ -308,44 +308,6 @@ struct
|
|||||||
[W_PROJECTILES newProjectiles]
|
[W_PROJECTILES newProjectiles]
|
||||||
end
|
end
|
||||||
|
|
||||||
fun runPhysicsAndInput (game: game_type, input) =
|
|
||||||
let
|
|
||||||
val player = #player game
|
|
||||||
|
|
||||||
val patches = getProjectilePatches player
|
|
||||||
val patches = getRecoilPatches (player, patches)
|
|
||||||
val player = PlayerPatch.withPatches (player, patches)
|
|
||||||
|
|
||||||
val patches =
|
|
||||||
(* we only accept and handle input if player is not recoiling.
|
|
||||||
* It's important to apply the recoil patches after handling input
|
|
||||||
* because we want to act on the latest recoil state straight away. *)
|
|
||||||
case #recoil player of
|
|
||||||
NO_RECOIL => getInputPatches (player, input)
|
|
||||||
| _ => []
|
|
||||||
|
|
||||||
(* animate projectiles *)
|
|
||||||
val player =
|
|
||||||
let
|
|
||||||
val e = #enemies player
|
|
||||||
val e =
|
|
||||||
Vector.map
|
|
||||||
(fn {angle} => {angle = if angle < 360 then angle + 5 else 0}) e
|
|
||||||
val patches = W_ENEMIES e :: patches
|
|
||||||
in
|
|
||||||
PlayerPatch.withPatches (player, patches)
|
|
||||||
end
|
|
||||||
|
|
||||||
val patches = PlayerPhysics.getPhysicsPatches player
|
|
||||||
val player = PlayerPatch.withPatches (player, patches)
|
|
||||||
|
|
||||||
val {walls, wallTree, platforms, platformTree, ...} = game
|
|
||||||
val patches = PlayerPhysics.getEnvironmentPatches
|
|
||||||
(player, walls, wallTree, platforms, platformTree)
|
|
||||||
in
|
|
||||||
PlayerPatch.withPatches (player, patches)
|
|
||||||
end
|
|
||||||
|
|
||||||
structure FoldEnemies =
|
structure FoldEnemies =
|
||||||
MakeQuadTreeFold
|
MakeQuadTreeFold
|
||||||
(struct
|
(struct
|
||||||
@@ -390,12 +352,74 @@ struct
|
|||||||
in
|
in
|
||||||
eCentreX < pCentreX
|
eCentreX < pCentreX
|
||||||
end
|
end
|
||||||
val patches = getEnemyRecoilPatches (player, playerOnRight, patches)
|
val patches =
|
||||||
|
getEnemyRecoilPatches (player, playerOnRight, patches)
|
||||||
in
|
in
|
||||||
W_ATTACKED (ATTACKED 0) :: patches
|
W_ATTACKED (ATTACKED 0) :: patches
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
fun runPhysicsAndInput (game: game_type, input, enemyTree) =
|
||||||
|
let
|
||||||
|
val player = #player game
|
||||||
|
|
||||||
|
val patches = getProjectilePatches player
|
||||||
|
val patches = getRecoilPatches (player, patches)
|
||||||
|
val player = PlayerPatch.withPatches (player, patches)
|
||||||
|
|
||||||
|
val patches =
|
||||||
|
(* we only accept and handle input if player is not recoiling.
|
||||||
|
* It's important to apply the recoil patches after handling input
|
||||||
|
* because we want to act on the latest recoil state straight away. *)
|
||||||
|
case #recoil player of
|
||||||
|
NO_RECOIL => getInputPatches (player, input)
|
||||||
|
| _ => []
|
||||||
|
|
||||||
|
val patches =
|
||||||
|
(* control timer for how long player should be immune to damage
|
||||||
|
* after being attacked *)
|
||||||
|
case #attacked player of
|
||||||
|
ATTACKED amt =>
|
||||||
|
if amt >= Constants.attackedLimit then
|
||||||
|
W_ATTACKED NOT_ATTACKED :: patches
|
||||||
|
else
|
||||||
|
W_ATTACKED (ATTACKED (amt + 1)) :: patches
|
||||||
|
| _ => patches
|
||||||
|
|
||||||
|
(* animate projectiles *)
|
||||||
|
val player =
|
||||||
|
let
|
||||||
|
val e = #enemies player
|
||||||
|
val e =
|
||||||
|
Vector.map
|
||||||
|
(fn {angle} => {angle = if angle < 360 then angle + 5 else 0}) e
|
||||||
|
val patches = W_ENEMIES e :: patches
|
||||||
|
in
|
||||||
|
PlayerPatch.withPatches (player, patches)
|
||||||
|
end
|
||||||
|
|
||||||
|
val patches = PlayerPhysics.getPhysicsPatches player
|
||||||
|
val player = PlayerPatch.withPatches (player, patches)
|
||||||
|
|
||||||
|
val {walls, wallTree, platforms, platformTree, ...} = game
|
||||||
|
val patches = PlayerPhysics.getEnvironmentPatches
|
||||||
|
(player, walls, wallTree, platforms, platformTree)
|
||||||
|
val player = PlayerPatch.withPatches (player, patches)
|
||||||
|
|
||||||
|
(* player reaction to collisions with enemies *)
|
||||||
|
val patches =
|
||||||
|
let
|
||||||
|
val {x, y, ...} = player
|
||||||
|
val size = Constants.playerSize
|
||||||
|
val env = (#enemies game, player)
|
||||||
|
val state = []
|
||||||
|
in
|
||||||
|
FoldEnemies.foldRegion (x, y, size, size, env, state, enemyTree)
|
||||||
|
end
|
||||||
|
in
|
||||||
|
PlayerPatch.withPatches (player, patches)
|
||||||
|
end
|
||||||
|
|
||||||
(* todo: add attacked enemies to player's 'enemies' field *)
|
(* todo: add attacked enemies to player's 'enemies' field *)
|
||||||
fun concatAttackedEnemies (player: player, enemyCollisions) =
|
fun concatAttackedEnemies (player: player, enemyCollisions) =
|
||||||
let
|
let
|
||||||
@@ -406,74 +430,6 @@ struct
|
|||||||
PlayerPatch.withPatch (player, W_ENEMIES allDefeated)
|
PlayerPatch.withPatch (player, W_ENEMIES allDefeated)
|
||||||
end
|
end
|
||||||
|
|
||||||
fun getEnemyRecoilPatches (player, playerOnRight, acc) =
|
|
||||||
if playerOnRight then
|
|
||||||
let
|
|
||||||
val newRecoil = RECOIL_RIGHT 0
|
|
||||||
val newAttacked = ATTACKED 0
|
|
||||||
in
|
|
||||||
W_RECOIL newRecoil :: W_ATTACKED newAttacked :: W_FACING FACING_LEFT
|
|
||||||
:: W_Y_AXIS FALLING :: W_X_AXIS STAY_STILL :: acc
|
|
||||||
end
|
|
||||||
else
|
|
||||||
let
|
|
||||||
val newRecoil = RECOIL_LEFT 0
|
|
||||||
val newAttacked = ATTACKED 0
|
|
||||||
in
|
|
||||||
W_RECOIL newRecoil :: W_ATTACKED newAttacked :: W_FACING FACING_RIGHT
|
|
||||||
:: W_Y_AXIS FALLING :: W_X_AXIS STAY_STILL :: acc
|
|
||||||
end
|
|
||||||
|
|
||||||
fun enemyCollisionReaction (player: player, enemies: enemy vector, lst, acc) =
|
|
||||||
case lst of
|
|
||||||
id :: tl =>
|
|
||||||
let
|
|
||||||
val playerOnRight =
|
|
||||||
(* check if collision is closer to left side of enemy or right
|
|
||||||
* and then chose appropriate direction to recoil in *)
|
|
||||||
let
|
|
||||||
val {x, ...} = player
|
|
||||||
val pFinishX = x + Constants.playerSize
|
|
||||||
val pHalfW = Constants.playerSize div 2
|
|
||||||
val pCentreX = x + pHalfW
|
|
||||||
|
|
||||||
val {x = ex, y = ey, ...} = Enemy.find (id, enemies)
|
|
||||||
val eFinishX = ex + Constants.enemySize
|
|
||||||
val eHalfW = Constants.enemySize div 2
|
|
||||||
val eCentreX = ex + eHalfW
|
|
||||||
in
|
|
||||||
eCentreX < pCentreX
|
|
||||||
end
|
|
||||||
|
|
||||||
val acc = getEnemyRecoilPatches (player, playerOnRight, acc)
|
|
||||||
in
|
|
||||||
enemyCollisionReaction (player, enemies, tl, acc)
|
|
||||||
end
|
|
||||||
| [] => PlayerPatch.withPatches (player, acc)
|
|
||||||
|
|
||||||
fun incrementAttacked (player, amt) =
|
|
||||||
let val patch = ATTACKED (amt + 1)
|
|
||||||
in PlayerPatch.withPatch (player, W_ATTACKED patch)
|
|
||||||
end
|
|
||||||
|
|
||||||
fun exitAttackedAndCheckEnemies (player, enemies, enemyCollisions) =
|
|
||||||
enemyCollisionReaction
|
|
||||||
(player, enemies, enemyCollisions, [W_ATTACKED NOT_ATTACKED])
|
|
||||||
|
|
||||||
fun getEnemyCollisionsWhenAttacking (x, y, enemyTree) =
|
|
||||||
let
|
|
||||||
val x = x - Constants.halfPlayerSize
|
|
||||||
val y = y - Constants.halfPlayerSize
|
|
||||||
val size = Constants.playerSize * 2
|
|
||||||
|
|
||||||
val ww = Constants.worldWidth
|
|
||||||
val wh = Constants.worldHeight
|
|
||||||
val enemyCollisions = QuadTree.getCollisions
|
|
||||||
(x, y, size, size, ~1, enemyTree)
|
|
||||||
in
|
|
||||||
Vector.fromList enemyCollisions
|
|
||||||
end
|
|
||||||
|
|
||||||
(*** DRAWING FUNCTIONS ***)
|
(*** DRAWING FUNCTIONS ***)
|
||||||
|
|
||||||
(* block is placeholder asset *)
|
(* block is placeholder asset *)
|
||||||
|
|||||||
Reference in New Issue
Block a user