diff --git a/fcore/game-update.sml b/fcore/game-update.sml index 6df3604..fc24ce5 100644 --- a/fcore/game-update.sml +++ b/fcore/game-update.sml @@ -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 diff --git a/fcore/player-enemy.sml b/fcore/player-enemy.sml deleted file mode 100644 index 8735789..0000000 --- a/fcore/player-enemy.sml +++ /dev/null @@ -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 diff --git a/fcore/player.sml b/fcore/player.sml index 6dfd9a7..6af92f9 100644 --- a/fcore/player.sml +++ b/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 *) diff --git a/oms.mlb b/oms.mlb index f24790d..21526f3 100644 --- a/oms.mlb +++ b/oms.mlb @@ -36,7 +36,6 @@ fcore/enemy.sml fcore/player.sml fcore/projectile.sml -fcore/player-enemy.sml fcore/game-update.sml (* shell *)