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} =
|
||||
game
|
||||
|
||||
val player = Player.runPhysicsAndInput (game, input)
|
||||
|
||||
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
|
||||
{ player = player
|
||||
, 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
|
||||
end
|
||||
|
||||
fun getRecoilPatches (player, patches) =
|
||||
fun getRecoilPatches (player: player, patches) =
|
||||
case #recoil player of
|
||||
NO_RECOIL => patches
|
||||
| RECOIL_LEFT recoiled =>
|
||||
@@ -300,7 +300,7 @@ struct
|
||||
end
|
||||
end
|
||||
|
||||
fun getProjectilePatches ({projectiles, ...}) =
|
||||
fun getProjectilePatches ({projectiles, ...}: player) =
|
||||
let
|
||||
val newProjectiles = helpMoveProjectiles
|
||||
(Vector.length projectiles - 1, projectiles, [])
|
||||
@@ -308,44 +308,6 @@ struct
|
||||
[W_PROJECTILES newProjectiles]
|
||||
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 =
|
||||
MakeQuadTreeFold
|
||||
(struct
|
||||
@@ -390,12 +352,74 @@ struct
|
||||
in
|
||||
eCentreX < pCentreX
|
||||
end
|
||||
val patches = getEnemyRecoilPatches (player, playerOnRight, patches)
|
||||
val patches =
|
||||
getEnemyRecoilPatches (player, playerOnRight, patches)
|
||||
in
|
||||
W_ATTACKED (ATTACKED 0) :: patches
|
||||
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 *)
|
||||
fun concatAttackedEnemies (player: player, enemyCollisions) =
|
||||
let
|
||||
@@ -406,74 +430,6 @@ struct
|
||||
PlayerPatch.withPatch (player, W_ENEMIES allDefeated)
|
||||
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 ***)
|
||||
|
||||
(* block is placeholder asset *)
|
||||
|
||||
Reference in New Issue
Block a user