diff --git a/fcore/enemy/falling-enemies.sml b/fcore/enemy/falling-enemies.sml index b672234..5b424af 100644 --- a/fcore/enemy/falling-enemies.sml +++ b/fcore/enemy/falling-enemies.sml @@ -3,104 +3,52 @@ struct open EnemyType open EntityType - fun helpGenerateTree (pos, fallingVec: falling_enemy vector, acc) = - if pos = Vector.length fallingVec then - acc - else - let - val {x, y, ...} = Vector.sub (fallingVec, pos) + structure FallingDrawVec = + MakeGapMapFolder + (struct + structure Pair = FallingEnemyPair - val size = Constants.enemySize + type env = + { width: Real32.real + , height: Real32.real + , ratio: Real32.real + , xOffset: Real32.real + , yOffset: Real32.real + } - val acc = QuadTree.insert (x, y, size, size, pos + 1, acc) - in - helpGenerateTree (pos + 1, fallingVec, acc) - end + type state = Real32.real vector list - fun generateTree fallingVec = - helpGenerateTree - ( 0 - , fallingVec - , QuadTree.create (Constants.worldWidth, Constants.worldHeight) - ) + fun helpGetDrawVec + (fallingEnemy, width, height, ratio, xOffset, yOffset, acc) = + let + val {x, y, variant = _} = fallingEnemy - fun isCollidingWithPlayerAttack (player: PlayerType.player, fx, fy) = - let - val {x = px, y = py, mainAttack, facing, ...} = player - in - case mainAttack of - PlayerType.MAIN_ATTACKING {length, ...} => - let - val px = - (case facing of - FACING_RIGHT => px + Constants.playerSize - | FACING_LEFT => px - length) + val x = Real32.fromInt x * ratio + xOffset + val y = Real32.fromInt y * ratio + yOffset + val size = Real32.fromInt Constants.enemySize * ratio - val pSize = Constants.playerSize - val fSize = Constants.enemySize - in - Collision.isCollidingPlus - (px, py, length, pSize, fx, fy, fSize, fSize) - end - | _ => false - end + val vec = Block.lerp + (x, y, size, size, width, height, 0.3, 0.3, 0.3) + in + vec :: acc + end - fun updateList (pos, vec, player: PlayerType.player, acc) = - if pos < 0 then - acc - else - let - val {x, y, variant} = Vector.sub (vec, pos) - - val size = Constants.enemySize - val ww = Constants.worldWidth - val wh = Constants.worldHeight - in - if isCollidingWithPlayerAttack (player, x, y) then - (* filter out if player is attacking falling enemy *) - updateList (pos - 1, vec, player, acc) - else if Collision.isCollidingPlus (x, y, size, size, 0, 0, ww, wh) then - (* move falling enemy upwards *) - let - val updated = - {x = x, y = y - Constants.moveEnemyBy, variant = variant} - in - updateList (pos - 1, vec, player, updated :: acc) - end - else - (* if current is not colliding with world's bounds, then filter out - * as it is off screen *) - updateList (pos - 1, vec, player, acc) - end - - fun helpGetDrawVec - (pos, fallingVec, width, height, ratio, xOffset, yOffset, acc) = - if pos = Vector.length fallingVec then - Vector.concat acc - else - let - val {x, y, variant = _} = Vector.sub (fallingVec, pos) - - val x = Real32.fromInt x * ratio + xOffset - val y = Real32.fromInt y * ratio + yOffset - val size = Real32.fromInt Constants.enemySize * ratio - - val vec = Block.lerp (x, y, size, size, width, height, 0.3, 0.3, 0.3) - val acc = vec :: acc - in - helpGetDrawVec - (pos + 1, fallingVec, width, height, ratio, xOffset, yOffset, acc) - end + fun fold (_, fallingEnemy, env, acc) = + let + val {width, height, ratio, xOffset, yOffset} = env + in + helpGetDrawVec + (fallingEnemy, width, height, ratio, xOffset, yOffset, acc) + end + end) fun getDrawVec (game: GameType.game_type, width, height) = - if Vector.length (#fallingEnemies game) = 0 then - Vector.fromList [] - else - let - val fallingEnemies = #fallingEnemies game - val wratio = width / Constants.worldWidthReal - val hratio = height / Constants.worldHeightReal - in + let + val fallingEnemies = #fallingEnemies game + val wratio = width / Constants.worldWidthReal + val hratio = height / Constants.worldHeightReal + + val env = if wratio < hratio then let val scale = Constants.worldHeightReal * wratio @@ -109,8 +57,12 @@ struct else if height < scale then (scale - height) / 2.0 else 0.0 in - helpGetDrawVec - (0, fallingEnemies, width, height, wratio, 0.0, yOffset, []) + { width = width + , height = height + , ratio = wratio + , xOffset = 0.0 + , yOffset = yOffset + } end else let @@ -120,8 +72,16 @@ struct else if width < scale then (scale - width) / 2.0 else 0.0 in - helpGetDrawVec - (0, fallingEnemies, width, height, hratio, xOffset, 0.0, []) + { width = width + , height = height + , ratio = hratio + , xOffset = xOffset + , yOffset = 0.0 + } end - end + + val lst = FallingDrawVec.foldUnordered (fallingEnemies, env, []) + in + Vector.concat lst + end end diff --git a/fcore/enemy/falling-enemy-map.sml b/fcore/enemy/falling-enemy-map.sml new file mode 100644 index 0000000..e8147eb --- /dev/null +++ b/fcore/enemy/falling-enemy-map.sml @@ -0,0 +1 @@ +structure FallingEnemyMap = MakeGapMap(FallingEnemyPair) diff --git a/fcore/enemy/falling-enemy-pair.sml b/fcore/enemy/falling-enemy-pair.sml new file mode 100644 index 0000000..c25ef96 --- /dev/null +++ b/fcore/enemy/falling-enemy-pair.sml @@ -0,0 +1,11 @@ +structure FallingEnemyPair = +struct + type key = int + type value = EnemyType.falling_enemy + + fun l (a: int, b: int) = a < b + fun eq (a: int, b: int) = a = b + fun g (a: int, b: int) = a > b + + val maxNodeSize = 8 +end diff --git a/fcore/game-type.sml b/fcore/game-type.sml index dc353e9..822e7f3 100644 --- a/fcore/game-type.sml +++ b/fcore/game-type.sml @@ -8,7 +8,7 @@ sig , platformTree: QuadTree.t , enemies: EnemyMap.t , graph: PlatSet.elem vector vector - , fallingEnemies: EnemyType.falling_enemy vector + , fallingEnemies: FallingEnemyMap.t } val initial: game_type @@ -24,7 +24,7 @@ struct , platformTree: QuadTree.t , enemies: EnemyMap.t , graph: PlatSet.elem vector vector - , fallingEnemies: EnemyType.falling_enemy vector + , fallingEnemies: FallingEnemyMap.t } fun enemyMapFromList (hd :: tl, map) = @@ -135,7 +135,7 @@ struct , platformTree = platformTree , enemies = enemies , graph = graph - , fallingEnemies = Vector.fromList [] + , fallingEnemies = FallingEnemyMap.empty } end end diff --git a/fcore/player/player-attack.sml b/fcore/player/player-attack.sml index 3252c87..d9091e5 100644 --- a/fcore/player/player-attack.sml +++ b/fcore/player/player-attack.sml @@ -1,5 +1,6 @@ structure PlayerAttack = struct + (* - Handle collisions where player hits enemy directly - *) structure AttackEnemies = MakeQuadTreeFold (struct @@ -58,59 +59,54 @@ struct | _ => (player, enemyMap) end + (* - Handle collisions when player's projectile hits enemy - *) structure ProjectileHitEnemy = MakeQuadTreeFold (struct type env = unit - type state = EnemyType.falling_enemy list * EnemyMap.t + type state = FallingEnemyMap.t * EnemyMap.t open EnemyType - fun onDefeated (enemyID, enemy, enemyMap, fallingList) = + fun onDefeated (enemyID, enemy, enemyMap, fallingMap) = let val {x, y, variant, ...} = enemy - val fallingList = {x = x, y = y, variant = variant} :: fallingList + val fallingItem = {x = x, y = y, variant = variant} + val fallingMap = + FallingEnemyMap.add (enemyID, fallingItem, fallingMap) val enemyMap = EnemyMap.remove (enemyID, enemyMap) in - (fallingList, enemyMap) + (fallingMap, enemyMap) end - fun onProjectileAttack (enemyID, enemy, enemyMap, fallingList) = + fun onProjectileAttack (enemyID, enemy, enemyMap, fallingMap) = case #variant enemy of - PATROL_SLIME => onDefeated (enemyID, enemy, enemyMap, fallingList) - | FOLLOW_SLIME => onDefeated (enemyID, enemy, enemyMap, fallingList) - | STRAIGHT_BAT => onDefeated (enemyID, enemy, enemyMap, fallingList) + PATROL_SLIME => onDefeated (enemyID, enemy, enemyMap, fallingMap) + | FOLLOW_SLIME => onDefeated (enemyID, enemy, enemyMap, fallingMap) + | STRAIGHT_BAT => onDefeated (enemyID, enemy, enemyMap, fallingMap) - fun fold (enemyID, (), (fallingList, enemyMap)) = + fun fold (enemyID, (), (fallingMap, enemyMap)) = case EnemyMap.get (enemyID, enemyMap) of SOME enemy => - onProjectileAttack (enemyID, enemy, enemyMap, fallingList) - | NONE => (fallingList, enemyMap) + onProjectileAttack (enemyID, enemy, enemyMap, fallingMap) + | NONE => (fallingMap, enemyMap) end) - fun helpProjectileHitEnemy (pos, projectiles, enemyTree, enemyMap, newFalling) = + fun helpProjectileHitEnemy (pos, projectiles, enemyTree, enemyMap, fallingMap) = if pos = Vector.length projectiles then - (newFalling, enemyMap) + (fallingMap, enemyMap) else let val {x, y, ...}: PlayerType.player_projectile = Vector.sub (projectiles, pos) val size = Constants.projectileSizeInt - val (newFalling, enemyMap) = ProjectileHitEnemy.foldRegion - (x, y, size, size, (), (newFalling, enemyMap), enemyTree) + val (fallingMap, enemyMap) = ProjectileHitEnemy.foldRegion + (x, y, size, size, (), (fallingMap, enemyMap), enemyTree) in helpProjectileHitEnemy - (pos + 1, projectiles, enemyTree, enemyMap, newFalling) + (pos + 1, projectiles, enemyTree, enemyMap, fallingMap) end - fun projectileHitEnemy (projectiles, enemyMap, enemyTree, oldFalling) = - let - val (newFalling, enemyMap) = helpProjectileHitEnemy - (0, projectiles, enemyTree, enemyMap, []) - - val newFalling = Vector.fromList newFalling - val allFalling = Vector.concat [newFalling, oldFalling] - in - (allFalling, enemyMap) - end + fun projectileHitEnemy (projectiles, enemyMap, enemyTree, fallingMap) = + helpProjectileHitEnemy (0, projectiles, enemyTree, enemyMap, fallingMap) end diff --git a/oms.mlb b/oms.mlb index c078cff..22a4857 100644 --- a/oms.mlb +++ b/oms.mlb @@ -31,6 +31,8 @@ fcore/entity-type.sml fcore/enemy/enemy-type.sml fcore/enemy/enemy-pair.sml fcore/enemy/enemy-map.sml +fcore/enemy/falling-enemy-pair.sml +fcore/enemy/falling-enemy-map.sml fcore/player/player-type.sml fcore/game-type.sml