diff --git a/arena.h b/arena.h index a079a05..8288e40 100644 --- a/arena.h +++ b/arena.h @@ -5,4 +5,4 @@ void clearArenaRedrawRequests(); void redrawArena(); void drawOnlyArena(struct SpriteBounds *bounds); void buildArena(); -void setupWallSprites(struct BMPImage *); +void setupWallSprites(); diff --git a/combat.c b/combat.c index fb0d04e..4ed516e 100644 --- a/combat.c +++ b/combat.c @@ -1,4 +1,5 @@ #include +#include #include "game.h" @@ -12,7 +13,8 @@ void attemptToFireRabbitBullet( struct BulletPosition rabbitBulletPosition[] ) { int okToFire = 0, availableBullet, i; - signed char doubleVelocityX, doubleVelocityY; + signed int doubleVelocityX, doubleVelocityY; + char buffer[20]; if (rabbitWeaponry->cooldown > 0) return; @@ -34,15 +36,15 @@ void attemptToFireRabbitBullet( rabbitBulletPosition[availableBullet].isActive = 1; rabbitBulletPosition[availableBullet].willBeInactive = 0; rabbitBulletPosition[availableBullet].x = rabbitPosition->rabbitPosition[0]; - rabbitBulletPosition[availableBullet].y = rabbitPosition->rabbitPosition[1] - RABBIT_BULLET_HEIGHT_START; + rabbitBulletPosition[availableBullet].y = rabbitPosition->rabbitPosition[1]; rabbitBulletPosition[availableBullet].oldX = rabbitBulletPosition[availableBullet].x; rabbitBulletPosition[availableBullet].oldY = rabbitBulletPosition[availableBullet].y; rabbitBulletPosition[availableBullet].velocityXSteps[0] = doubleVelocityX / RABBIT_BULLET_VELOCITY; - rabbitBulletPosition[availableBullet].velocityXSteps[1] = doubleVelocityX % RABBIT_BULLET_VELOCITY; + rabbitBulletPosition[availableBullet].velocityXSteps[1] = doubleVelocityX - rabbitBulletPosition[availableBullet].velocityXSteps[0]; rabbitBulletPosition[availableBullet].velocityYSteps[0] = doubleVelocityY / RABBIT_BULLET_VELOCITY; - rabbitBulletPosition[availableBullet].velocityYSteps[1] = doubleVelocityY % RABBIT_BULLET_VELOCITY; + rabbitBulletPosition[availableBullet].velocityYSteps[1] = doubleVelocityY - rabbitBulletPosition[availableBullet].velocityYSteps[0]; rabbitBulletPosition[availableBullet].velocityStep = 0; } @@ -81,22 +83,12 @@ struct CollisionDetection { struct CollisionDetection collisionDetection; int isCollision() { - int result; + if (collisionDetection.sourceEY < collisionDetection.targetSY) return 0; + if (collisionDetection.sourceEX < collisionDetection.targetSX) return 0; + if (collisionDetection.targetEY < collisionDetection.sourceSY) return 0; + if (collisionDetection.targetEX < collisionDetection.sourceSX) return 0; - // first pass: are the hitboxes even close - result = !( - collisionDetection.sourceEY < collisionDetection.targetSY || - collisionDetection.sourceEX < collisionDetection.targetSX || - collisionDetection.targetEY < collisionDetection.sourceSY || - collisionDetection.targetEX < collisionDetection.sourceSX - ); - - if (!result) return result; - - // second pass: check against specific character shaped hitboxes - // these will be generated from the spritesheet generator - - return result; + return 1; } void populateSourceCollision(struct CompiledSpriteRender *sprite) { @@ -117,31 +109,108 @@ void populateTargetCollision(struct CompiledSpriteRender *sprite) { collisionDetection.targetEY = bounds.bottom; } +void handleRabbitToEnemyCollisions( + struct RabbitPosition *rabbitPosition, + struct EnemyPosition enemyPosition[] +) { + int enemyIdx; + + // to start: brute force items + // possible performance improvements: + // * grid partitioning + rabbit.x = rabbitPosition->rabbitPosition[0]; + rabbit.y = rabbitPosition->rabbitPosition[1]; + populateSourceCollision(&rabbit); + + for (enemyIdx = 0; enemyIdx < ENEMY_MAX_COUNT; ++enemyIdx) { + if (!enemyPosition[enemyIdx].isActive) continue; + if (enemyPosition[enemyIdx].willBeInactive) continue; + + enemy.x = enemyPosition[enemyIdx].enemyPosition[0]; + enemy.y = enemyPosition[enemyIdx].enemyPosition[1]; + populateTargetCollision(&enemy); + + if (isCollision()) { + enemyPosition[enemyIdx].willBeInactive = 1; + } + } +} + +int rabbitBulletGrid[4][RABBIT_BULLET_LIMIT]; +int enemyGrid[4][ENEMY_MAX_COUNT]; + void handleRabbitBulletToEnemyCollisions( struct BulletPosition rabbitBulletPosition[], struct EnemyPosition enemyPosition[] ) { - int bulletIdx, enemyIdx; + int bulletIdx, enemyIdx, grid; + int resolvedBulletIdx, resolvedEnemyIdx; + int rabbitGridIndex[4], enemyGridIndex[4]; + + char buffer[30]; + + for (grid = 0; grid < 4; ++grid) { + rabbitGridIndex[grid] = 0; + } - // to start: brute force items - // possible performance improvements: - // * horizontal sweep against enemies to rule out enemies to check for (bulletIdx = 0; bulletIdx < RABBIT_BULLET_LIMIT; ++bulletIdx) { if (!rabbitBulletPosition[bulletIdx].isActive) continue; if (rabbitBulletPosition[bulletIdx].willBeInactive) continue; - populateSourceCollision(&bullet); + grid = ( + rabbitBulletPosition[bulletIdx].x / (TILE_SIZE * 5) + ) + ( + (rabbitBulletPosition[bulletIdx].y / (TILE_SIZE * 5)) * 2 + ); - for (enemyIdx = 0; enemyIdx < ENEMY_MAX_COUNT; ++enemyIdx) { - if (!enemyPosition[enemyIdx].isActive) continue; - if (enemyPosition[enemyIdx].willBeInactive) continue; + rabbitBulletGrid[grid][rabbitGridIndex[grid]++] = bulletIdx; + } - populateTargetCollision(&enemy); + for (grid = 0; grid < 4; ++grid) { + enemyGridIndex[grid] = 0; + } - if (isCollision()) { - enemyPosition[enemyIdx].willBeInactive = 1; - rabbitBulletPosition[bulletIdx].willBeInactive = 1; - break; + for (enemyIdx = 0; enemyIdx < ENEMY_MAX_COUNT; ++enemyIdx) { + if (!enemyPosition[enemyIdx].isActive) continue; + if (enemyPosition[enemyIdx].willBeInactive) continue; + + grid = ( + enemyPosition[enemyIdx].enemyPosition[0] / (TILE_SIZE * 5) + ) + ( + (enemyPosition[enemyIdx].enemyPosition[1] / (TILE_SIZE * 5)) * 2 + ); + + enemyGrid[grid][enemyGridIndex[grid]++] = enemyIdx; + } + + for (grid = 0; grid < 4; ++grid) { + if (enemyGridIndex[grid] == 0) continue; + + for (bulletIdx = 0; bulletIdx < rabbitGridIndex[grid]; ++bulletIdx) { + resolvedBulletIdx = rabbitBulletGrid[grid][bulletIdx]; + + if (!rabbitBulletPosition[resolvedBulletIdx].isActive) continue; + if (rabbitBulletPosition[resolvedBulletIdx].willBeInactive) continue; + + bullet.x = rabbitBulletPosition[resolvedBulletIdx].x; + bullet.y = rabbitBulletPosition[resolvedBulletIdx].y; + populateSourceCollision(&bullet); + + for (enemyIdx = 0; enemyIdx < enemyGridIndex[grid]; ++enemyIdx) { + resolvedEnemyIdx = enemyGrid[grid][enemyIdx]; + + if (!enemyPosition[resolvedEnemyIdx].isActive) continue; + if (enemyPosition[resolvedEnemyIdx].willBeInactive) continue; + + enemy.x = enemyPosition[resolvedEnemyIdx].enemyPosition[0]; + enemy.y = enemyPosition[resolvedEnemyIdx].enemyPosition[1]; + populateTargetCollision(&enemy); + + if (isCollision()) { + enemyPosition[resolvedEnemyIdx].willBeInactive = 1; + rabbitBulletPosition[resolvedBulletIdx].willBeInactive = 1; + break; + } } } } diff --git a/combat.h b/combat.h index 6bda5a1..c1131a0 100644 --- a/combat.h +++ b/combat.h @@ -13,3 +13,8 @@ void handleRabbitBulletToEnemyCollisions( struct BulletPosition[], struct EnemyPosition[] ); + +void handleRabbitToEnemyCollisions( + struct RabbitPosition*, + struct EnemyPosition[] +); diff --git a/const.h b/const.h index 14d5ec9..e477c3a 100644 --- a/const.h +++ b/const.h @@ -10,7 +10,7 @@ #define RABBIT_MOTION_VELOCITY_DECAY (5) #define RABBIT_BULLET_LIMIT (12) -#define RABBIT_BULLET_VELOCITY (RABBIT_MOTION_ACCELERATION + 2) +#define RABBIT_BULLET_VELOCITY (RABBIT_MOTION_ACCELERATION + 1) #define RABBIT_BULLET_COOLDOWN (10) #define RABBIT_BULLET_HEIGHT_START (8) @@ -22,4 +22,4 @@ #define RAD2DEG (180/3.14159) #define DEG2RAD (3.14159/180) -#define ENEMY_MAX_COUNT (20) +#define ENEMY_MAX_COUNT (50) diff --git a/game.c b/game.c index 57148d0..144466f 100644 --- a/game.c +++ b/game.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -42,7 +43,7 @@ struct SpawnPointRange { }; struct SpawnPointRange spawnPointRanges[1] = { - { .left = 50, .width = 30, .top = 50, .height = 30 } + { .left = 130, .width = 50, .top = 50, .height = 100 } }; @@ -66,7 +67,6 @@ void setupEnemies() { } } - void maybeSpawnEnemy() { char canSpawn; int i, availableEnemy; @@ -238,7 +238,7 @@ int setupGame() { spritesheetImage.transparentColor = 0; - setupWallSprites(&spritesheetImage); + setupWallSprites(); setupRabbitSprites(); setupRabbitBullets(); setupEnemySprites(); @@ -286,6 +286,11 @@ void handleCombat() { &rabbitWeaponry ); + handleRabbitToEnemyCollisions( + &rabbitPosition, + enemyPosition + ); + handleRabbitBulletToEnemyCollisions( rabbitBulletPosition, enemyPosition @@ -316,23 +321,26 @@ clock_t startTime; int main(void) { byte *drawBuffer; int keepRunning = 1; + int i; if (setupGame()) return 1; drawBuffer = getDrawBuffer(); - maybeSpawnEnemy(); + for (i = 0; i < ENEMY_MAX_COUNT; ++i) { + maybeSpawnEnemy(); + } while (keepRunning) { readMouse(&mouseStatus); populateKeyboardKeydownState(); handleMovement(); - handleCombat(); handleRedraw(); waitStartVbl(); copyDrawBufferToDisplay(); + handleCombat(); waitEndVbl(); if (keyboardKeydownState.KEY_ESC) { keepRunning = 0; } diff --git a/movement.c b/movement.c index 257465c..16be776 100644 --- a/movement.c +++ b/movement.c @@ -31,7 +31,7 @@ void calculateTargetAngle( // Position the cursor distanceX = pos->mouseDotPosition[0] - pos->rabbitPosition[0]; - distanceY = pos->mouseDotPosition[1] - pos->rabbitPosition[1] - RABBIT_BULLET_HEIGHT_START; + distanceY = pos->mouseDotPosition[1] - pos->rabbitPosition[1]; angle = atan2(distanceY, distanceX) * RAD2DEG + 90; if (angle < 0) angle += 360;