From 75e28b892e33f5587d0d1f6591fbc115afd33d6b Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Sat, 11 Jan 2025 21:35:55 +0000 Subject: [PATCH] done getting player's projectiles to collide with enemies successfully, and tested (although the code of the enemy reacting to the player is not the best) --- fcore/game-type.sml | 6 +- fcore/game-update.sml | 10 +- fcore/player-enemy.sml | 77 ++++++++++-- fcore/projectile-enemy.sml | 61 --------- fcore/projectile.sml | 18 +++ fcore/quad-tree.sml | 246 ++++++++++++++++++++++++++++++++----- oms.mlb | 2 +- 7 files changed, 306 insertions(+), 114 deletions(-) delete mode 100644 fcore/projectile-enemy.sml create mode 100644 fcore/projectile.sml diff --git a/fcore/game-type.sml b/fcore/game-type.sml index 76612a9..190aac8 100644 --- a/fcore/game-type.sml +++ b/fcore/game-type.sml @@ -181,9 +181,9 @@ struct val platforms = Vector.fromList [plat1] val platformTree = Platform.generateTree platforms - val enemy1 = {id = 1, x = 300, y = 945, health = 2} - val enemy2 = {id = 2, x = 555, y = 945, health = 2} - val enemy3 = {id = 3, x = 979, y = 945, health = 2} + val enemy1 = {id = 1, x = 300, y = 945, health = 5} + val enemy2 = {id = 2, x = 555, y = 945, health = 5} + val enemy3 = {id = 3, x = 979, y = 945, health = 5} val enemies = Vector.fromList [enemy1, enemy2, enemy3] val enemyTree = Enemy.generateTree enemies in diff --git a/fcore/game-update.sml b/fcore/game-update.sml index 815cbcc..ae28597 100644 --- a/fcore/game-update.sml +++ b/fcore/game-update.sml @@ -7,15 +7,11 @@ struct val player = Player.runPhysicsAndInput (game, input) - (* check and react to enemy collisions with player projectile *) - val enemies = - ProjectileEnemy.checkCollisions - (#projectiles player, enemies, enemyTree) - val enemyTree = Enemy.generateTree enemies - (* check player-enemy collisions and react *) val (player, enemies, enemyTree) = - PlayerEnemy.checkCollisions (player, enemies, enemyTree) + PlayerEnemy.checkCollisions + (player, enemies, enemyTree, #projectiles player) + in { player = player , walls = walls diff --git a/fcore/player-enemy.sml b/fcore/player-enemy.sml index c0d0552..617b5dc 100644 --- a/fcore/player-enemy.sml +++ b/fcore/player-enemy.sml @@ -57,24 +57,71 @@ struct fun exists (id, collisions) = helpExists (0, id, collisions) - (* removes enemies from `enemies` vector when that enemy is in collisions *) - fun filterEnemyCollisions (pos, collisions, enemies: enemy vector, acc) = + (* 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 (* don't filter out *) enemy :: acc + if exists (#id enemy, collisions) then + (* filter out *) + acc + else + let + val {x, y, health, id} = enemy + val eSize = Enemy.size + val hasCollision = QuadTree.hasCollisionAt + (x, y, eSize, eSize, 0, 0, 1920, 1080, ~1, projectileTree) + in + if hasCollision then + if health = 1 then + (* filter out if decrementing health by one = 0 *) + acc + else + {health = health - 1, x = x, y = y, id = id} :: acc + else + enemy :: acc + end in - filterEnemyCollisions (pos - 1, collisions, enemies, acc) + filterEnemyAttacked + (pos - 1, collisions, enemies, projectileTree, acc) end - fun checkCollisions (player, enemies, enemyTree) = + (* 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 {x, y, health, id} = enemy + val eSize = Enemy.size + val hasCollision = QuadTree.hasCollisionAt + (x, y, eSize, eSize, 0, 0, 1920, 1080, ~1, projectileTree) + + val acc = + if hasCollision then + if health = 1 then + (* filter out if decrementing health by one = 0 *) + acc + else + {health = health - 1, x = x, y = y, id = id} :: acc + else + enemy :: acc + in + filterEnemyProjectiles (pos - 1, enemies, projectileTree, acc) + end + + fun checkCollisions (player, enemies, enemyTree, projectiles) = let val {x, y, mainAttack, attacked, ...} = player val size = Player.size + val projectileTree = Projectile.generateTree projectiles in case mainAttack of MAIN_ATTACKING => @@ -90,8 +137,13 @@ struct (* filter enemies based on collisions *) val enemyCollisions = Vector.fromList enemyCollisions - val enemies = filterEnemyCollisions - (Vector.length enemies - 1, enemyCollisions, enemies, []) + val enemies = filterEnemyAttacked + ( Vector.length enemies - 1 + , enemyCollisions + , enemies + , projectileTree + , [] + ) val enemyTree = Enemy.generateTree enemies (* add collided enemies to player record, @@ -114,6 +166,9 @@ struct val patches = checkEnemies (player, enemies, enemyCollisions, []) val player = Player.withPatches (player, patches) + + val enemies = filterEnemyProjectiles + (Vector.length enemies - 1, enemies, projectileTree, []) in (player, enemies, enemyTree) end @@ -127,6 +182,9 @@ struct val patches = checkEnemies (player, enemies, enemyCollisions, lst) val player = Player.withPatches (player, patches) + + val enemies = filterEnemyProjectiles + (Vector.length enemies - 1, enemies, projectileTree, []) in (player, enemies, enemyTree) end @@ -139,6 +197,9 @@ struct val attacked = ATTACKED amt val player = Player.withPatches (player, [W_ATTACKED attacked]) + + val enemies = filterEnemyProjectiles + (Vector.length enemies - 1, enemies, projectileTree, []) in (player, enemies, enemyTree) end) diff --git a/fcore/projectile-enemy.sml b/fcore/projectile-enemy.sml deleted file mode 100644 index c2efae6..0000000 --- a/fcore/projectile-enemy.sml +++ /dev/null @@ -1,61 +0,0 @@ -structure ProjectileEnemy = -struct - open GameType - - fun helpCheckColisions (pos, projectileTree, enemies, acc) = - if pos < 0 then - Vector.fromList acc - else - let - val enemy = Vector.sub (enemies, pos) - - val {id, health, x, y} = enemy - val size = Enemy.size - - val collisions = QuadTree.helpGetCollisions - (x, y, size, size, 0, 0, 1920, 1080, 0, [], projectileTree) - - (* react to collisions here, possibly removing enemy from acc *) - val acc = - case collisions of - _ :: _ => - if health = 1 then - (* filter enemy out if decrementing their health by 1 - * leads to a health of 0 *) - acc - else - let - (* decrement health by 1 and add to acc *) - val enemy = {id = id, health = health - 1, x = x, y = y} - in - enemy :: acc - end - | [] => enemy :: acc - in - helpCheckColisions (pos - 1, projectileTree, enemies, acc) - end - - fun helpGenerateTree (pos, projectiles, acc) = - if pos = Vector.length projectiles then - acc - else - let - val size = Player.defeatedSizeInt - - val {x, y, facing = _} = Vector.sub (projectiles, pos) - val acc = QuadTree.insert (x, y, size, size, 0, 0, 1920, 1080, pos, acc) - in - helpGenerateTree (pos + 1, projectiles, acc) - end - - fun generateTree projectiles = - helpGenerateTree (0, projectiles, QuadTree.empty) - - fun checkCollisions (projectiles, enemies, enemyTree) = - let - val projectileTree = generateTree projectiles - in - helpCheckColisions - (Vector.length enemies - 1, projectileTree, enemies, []) - end -end diff --git a/fcore/projectile.sml b/fcore/projectile.sml new file mode 100644 index 0000000..bdae901 --- /dev/null +++ b/fcore/projectile.sml @@ -0,0 +1,18 @@ +structure Projectile = +struct + fun helpGenerateTree (pos, projectiles, acc) = + if pos = Vector.length projectiles then + acc + else + let + val size = Player.defeatedSizeInt + + val {x, y, facing = _} = Vector.sub (projectiles, pos) + val acc = QuadTree.insert (x, y, size, size, 0, 0, 1920, 1080, pos, acc) + in + helpGenerateTree (pos + 1, projectiles, acc) + end + + fun generateTree projectiles = + helpGenerateTree (0, projectiles, QuadTree.empty) +end diff --git a/fcore/quad-tree.sml b/fcore/quad-tree.sml index 7495453..05c133c 100644 --- a/fcore/quad-tree.sml +++ b/fcore/quad-tree.sml @@ -30,6 +30,10 @@ sig val getCollisionsBelow: int * int * int * int * int * int * int * int * int * t -> int list + + val hasCollisionAt: int * int * int * int * + int * int * int * int * + int * t -> bool end structure QuadTree: QUAD_TREE = @@ -180,9 +184,16 @@ struct end fun insert - ( itemX, itemY, itemWidth, itemHeight - , quadX, quadY, quadWidth, quadHeight - , itemID, tree: t + ( itemX + , itemY + , itemWidth + , itemHeight + , quadX + , quadY + , quadWidth + , quadHeight + , itemID + , tree: t ) = case tree of NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => @@ -627,14 +638,29 @@ struct (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc) fun getCollisions - ( itemX, itemY, itemWidth, itemHeight - , quadX, quadY, quadWidth, quadHeight - , itemID, tree + ( itemX + , itemY + , itemWidth + , itemHeight + , quadX + , quadY + , quadWidth + , quadHeight + , itemID + , tree ) = helpGetCollisions - ( itemX, itemY, itemWidth, itemHeight - , quadX, quadY, quadWidth, quadHeight - , itemID, [], tree + ( itemX + , itemY + , itemWidth + , itemHeight + , quadX + , quadY + , quadWidth + , quadHeight + , itemID + , [] + , tree ) (* no variant to represent 'no collision' case @@ -881,14 +907,29 @@ struct (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc) fun getCollisionSides - ( itemX, itemY, itemWidth, itemHeight - , quadX, quadY, quadWidth, quadHeight - , itemID, tree + ( itemX + , itemY + , itemWidth + , itemHeight + , quadX + , quadY + , quadWidth + , quadHeight + , itemID + , tree ) = helpGetCollisionSides - ( itemX, itemY, itemWidth, itemHeight - , quadX, quadY, quadWidth, quadHeight - , itemID, [], tree + ( itemX + , itemY + , itemWidth + , itemHeight + , quadX + , quadY + , quadWidth + , quadHeight + , itemID + , [] + , tree ) fun getCollisionsBelowVec (iX, iY, iW, iH, itemID, pos, elements, acc) = @@ -903,19 +944,12 @@ struct case getCollisionSide (iX, iY, iW, iH, item) of QUERY_ON_BOTTOM_SIDE => getCollisionsBelowVec - ( iX, iY, iW, iH, itemID - , pos + 1, elements, curID :: acc - ) + (iX, iY, iW, iH, itemID, pos + 1, elements, curID :: acc) | _ => getCollisionsBelowVec - ( iX, iY, iW, iH, itemID - , pos + 1, elements, acc - ) + (iX, iY, iW, iH, itemID, pos + 1, elements, acc) else - getCollisionsBelowVec - ( iX, iY, iW, iH, itemID - , pos + 1, elements, acc - ) + getCollisionsBelowVec (iX, iY, iW, iH, itemID, pos + 1, elements, acc) end fun getCollisionsBelowAll (iX, iY, iW, iH, qW, qH, itemID, acc, tree) = @@ -943,9 +977,17 @@ struct getCollisionsBelowVec (iX, iY, iW, iH, itemID, 0, elements, acc) fun helpGetCollisionsBelow - ( itemX, itemY, itemWidth, itemHeight - , quadX, quadY, quadWidth, quadHeight - , itemID, acc, tree: t + ( itemX + , itemY + , itemWidth + , itemHeight + , quadX + , quadY + , quadWidth + , quadHeight + , itemID + , acc + , tree: t ) = case tree of NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => @@ -1086,13 +1128,149 @@ struct (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc) fun getCollisionsBelow - ( itemX, itemY, itemWidth, itemHeight - , quadX, quadY, quadWidth, quadHeight - , itemID, tree + ( itemX + , itemY + , itemWidth + , itemHeight + , quadX + , quadY + , quadWidth + , quadHeight + , itemID + , tree ) = helpGetCollisionsBelow - ( itemX, itemY, itemWidth, itemHeight - , quadX, quadY, quadWidth, quadHeight - , itemID, [], tree + ( itemX + , itemY + , itemWidth + , itemHeight + , quadX + , quadY + , quadWidth + , quadHeight + , itemID + , [] + , tree ) + + fun hasCollisionAtVec (iX, iY, iW, iH, itemID, pos, elements) = + if pos = Vector.length elements then + false + else + let + val item = Vector.sub (elements, pos) + in + isColliding (iX, iY, iW, iH, itemID, item) + orelse hasCollisionAtVec (iX, iY, iW, iH, itemID, pos + 1, elements) + end + + fun hasCollisionAt + ( itemX + , itemY + , itemWidth + , itemHeight + , quadX + , quadY + , quadWidth + , quadHeight + , itemID + , tree + ) = + case tree of + NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => + hasCollisionAtVec + (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements) + orelse + (case + whichQuadrant + ( itemX + , itemY + , itemWidth + , itemHeight + , quadX + , quadY + , quadWidth + , quadHeight + ) + of + TOP_LEFT => + let + val halfWidth = quadWidth div 2 + val halfHeight = quadHeight div 2 + in + hasCollisionAt + ( itemX + , itemY + , itemWidth + , itemHeight + , quadX + , quadY + , halfWidth + , halfHeight + , itemID + , topLeft + ) + end + | TOP_RIGHT => + let + val halfWidth = quadWidth div 2 + val halfHeight = quadHeight div 2 + val middleX = quadX + halfWidth + in + hasCollisionAt + ( itemX + , itemY + , itemWidth + , itemHeight + , middleX + , quadY + , halfWidth + , halfHeight + , itemID + , topRight + ) + end + | BOTTOM_LEFT => + let + val halfWidth = quadWidth div 2 + val halfHeight = quadHeight div 2 + val middleY = quadY + halfHeight + in + hasCollisionAt + ( itemX + , itemY + , itemWidth + , itemHeight + , quadX + , middleY + , halfWidth + , halfHeight + , itemID + , bottomLeft + ) + end + | BOTTOM_RIGHT => + let + val halfWidth = quadWidth div 2 + val halfHeight = quadHeight div 2 + val middleX = quadX + halfWidth + val middleY = quadY + halfHeight + in + hasCollisionAt + ( itemX + , itemY + , itemWidth + , itemHeight + , middleX + , middleY + , halfWidth + , halfHeight + , itemID + , bottomRight + ) + end + | PARENT_QUADRANT => false) + | LEAF elements => + hasCollisionAtVec + (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements) end diff --git a/oms.mlb b/oms.mlb index c138858..ef2e24e 100644 --- a/oms.mlb +++ b/oms.mlb @@ -17,8 +17,8 @@ fcore/enemy.sml fcore/game-type.sml fcore/player.sml +fcore/projectile.sml -fcore/projectile-enemy.sml fcore/player-enemy.sml fcore/game-update.sml