diff --git a/fcore/enemy.sml b/fcore/enemy.sml index 6e31223..f902f7b 100644 --- a/fcore/enemy.sml +++ b/fcore/enemy.sml @@ -1,5 +1,15 @@ structure Enemy = struct + fun helpExists (pos, id, collisions) = + if pos = Vector.length collisions then + false + else + let val current = Vector.sub (collisions, pos) + in current = id orelse helpExists (pos + 1, id, collisions) + end + + fun exists (id, collisions) = helpExists (0, id, collisions) + (* called when filtering enemies, * to adjust enemy data on collision with projectile *) fun onCollisionWithProjectile (enemy, projectileTree, acc) = @@ -29,6 +39,34 @@ struct enemy :: acc end + (* filter enemy projectiles when player is not attacking *) + fun filterProjectileCollisions (pos, enemies, projectileTree, acc) = + if pos < 0 then + Vector.fromList acc + else + let + val enemy = Vector.sub (enemies, pos) + val acc = onCollisionWithProjectile (enemy, projectileTree, acc) + in + filterProjectileCollisions (pos - 1, enemies, projectileTree, acc) + end + + (* removes enemies from `enemies` vector when player is attacking that enemy + * and also filter enemy (or change enemyh health) + * if enemy has collided with projectile *) + fun filterWhenAttacked (pos, collisions, enemies, projectileTree, acc) = + if pos < 0 then + Vector.fromList acc + else + let + val enemy = Vector.sub (enemies, pos) + val acc = + if exists (#id enemy, collisions) then (* filter out *) acc + else onCollisionWithProjectile (enemy, projectileTree, acc) + in + filterWhenAttacked (pos - 1, collisions, enemies, projectileTree, acc) + end + fun helpGenerateTree (pos, enemyVec, acc) = if pos = Vector.length enemyVec then acc diff --git a/fcore/player-enemy.sml b/fcore/player-enemy.sml index 7aaf5ed..ffae80b 100644 --- a/fcore/player-enemy.sml +++ b/fcore/player-enemy.sml @@ -3,90 +3,6 @@ struct open GameType open PlayerPatch - 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 checkEnemies (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 - checkEnemies (player, enemies, tl, acc) - end - | [] => acc - - fun helpExists (pos, id, collisions) = - if pos = Vector.length collisions then - false - else - let val current = Vector.sub (collisions, pos) - in current = id orelse helpExists (pos + 1, id, collisions) - end - - fun exists (id, collisions) = helpExists (0, id, collisions) - - (* removes enemies from `enemies` vector when player is attacking that enemy - * and also filter enemy (or change enemyh health) - * if enemy has collided with projectile *) - fun filterEnemyAttacked - (pos, collisions, enemies: enemy vector, projectileTree, acc) = - if pos < 0 then - Vector.fromList acc - else - let - val enemy = Vector.sub (enemies, pos) - val acc = - if exists (#id enemy, collisions) then (* filter out *) acc - else Enemy.onCollisionWithProjectile (enemy, projectileTree, acc) - in - filterEnemyAttacked (pos - 1, collisions, enemies, projectileTree, acc) - end - - (* filter enemy projectiles when player is not attacking *) - fun filterEnemyProjectiles (pos, enemies, projectileTree, acc) = - if pos < 0 then - Vector.fromList acc - else - let - val enemy = Vector.sub (enemies, pos) - val acc = Enemy.onCollisionWithProjectile (enemy, projectileTree, acc) - in - filterEnemyProjectiles (pos - 1, enemies, projectileTree, acc) - end - fun checkCollisions (player, enemies, enemyTree, projectiles) = let val {x, y, mainAttack, attacked, ...} = player @@ -107,7 +23,7 @@ struct (* filter enemies based on collisions *) val enemyCollisions = Vector.fromList enemyCollisions - val enemies = filterEnemyAttacked + val enemies = Enemy.filterWhenAttacked ( Vector.length enemies - 1 , enemyCollisions , enemies @@ -117,11 +33,7 @@ struct (* add collided enemies to player record, * concatenating with the previous enemies defeated *) - val newDefeated = - Vector.map (fn id => {angle = 360}) enemyCollisions - val oldDefeated = #enemies player - val allDefeated = Vector.concat [oldDefeated, newDefeated] - val player = Player.withPatches (player, [W_ENEMIES allDefeated]) + val player = Player.concatAttackedEnemies (player, enemyCollisions) in (player, enemies) end @@ -132,11 +44,11 @@ struct val enemyCollisions = QuadTree.getCollisions (x, y, size, size, 0, 0, 1920, 1080, 0, enemyTree) - val patches = - checkEnemies (player, enemies, enemyCollisions, []) - val player = Player.withPatches (player, patches) + val player = + Player.enemyCollisionReaction + (player, enemies, enemyCollisions, []) - val enemies = filterEnemyProjectiles + val enemies = Enemy.filterProjectileCollisions (Vector.length enemies - 1, enemies, projectileTree, []) in (player, enemies) @@ -148,11 +60,11 @@ struct val enemyCollisions = QuadTree.getCollisions (x, y, size, size, 0, 0, 1920, 1080, 0, enemyTree) val lst = [W_ATTACKED NOT_ATTACKED] - val patches = - checkEnemies (player, enemies, enemyCollisions, lst) - val player = Player.withPatches (player, patches) + val player = + Player.enemyCollisionReaction + (player, enemies, enemyCollisions, lst) - val enemies = filterEnemyProjectiles + val enemies = Enemy.filterProjectileCollisions (Vector.length enemies - 1, enemies, projectileTree, []) in (player, enemies) @@ -164,10 +76,9 @@ struct let val amt = amt + 1 val attacked = ATTACKED amt - val player = Player.withPatches - (player, [W_ATTACKED attacked]) + val player = Player.withPatch (player, W_ATTACKED attacked) - val enemies = filterEnemyProjectiles + val enemies = Enemy.filterProjectileCollisions (Vector.length enemies - 1, enemies, projectileTree, []) in (player, enemies) diff --git a/fcore/player-patch.sml b/fcore/player-patch.sml index 5287538..c1c4415 100644 --- a/fcore/player-patch.sml +++ b/fcore/player-patch.sml @@ -15,6 +15,7 @@ sig | W_CHARGE of int | W_PROJECTILES of GameType.player_projectile vector + val withPatch: GameType.player * player_patch -> GameType.player val withPatches: GameType.player * player_patch list -> GameType.player end diff --git a/fcore/player.sml b/fcore/player.sml index 5356bd9..0ea1595 100644 --- a/fcore/player.sml +++ b/fcore/player.sml @@ -440,6 +440,60 @@ struct PlayerPatch.withPatches (player, patches) end + fun concatAttackedEnemies (player: player, enemyCollisions) = + let + val newDefeated = Vector.map (fn id => {angle = 360}) enemyCollisions + val oldDefeated = #enemies player + val allDefeated = Vector.concat [oldDefeated, newDefeated] + in + 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) + (* block is placeholder asset *) fun helpGetDrawVec (x, y, size, width, height, attacked, mainAttack) = case mainAttack of