collision detection works and is fast. for now.
This commit is contained in:
parent
903835a10a
commit
83c35f68c4
2
arena.h
2
arena.h
|
@ -5,4 +5,4 @@ void clearArenaRedrawRequests();
|
||||||
void redrawArena();
|
void redrawArena();
|
||||||
void drawOnlyArena(struct SpriteBounds *bounds);
|
void drawOnlyArena(struct SpriteBounds *bounds);
|
||||||
void buildArena();
|
void buildArena();
|
||||||
void setupWallSprites(struct BMPImage *);
|
void setupWallSprites();
|
||||||
|
|
133
combat.c
133
combat.c
|
@ -1,4 +1,5 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
|
||||||
|
@ -12,7 +13,8 @@ void attemptToFireRabbitBullet(
|
||||||
struct BulletPosition rabbitBulletPosition[]
|
struct BulletPosition rabbitBulletPosition[]
|
||||||
) {
|
) {
|
||||||
int okToFire = 0, availableBullet, i;
|
int okToFire = 0, availableBullet, i;
|
||||||
signed char doubleVelocityX, doubleVelocityY;
|
signed int doubleVelocityX, doubleVelocityY;
|
||||||
|
char buffer[20];
|
||||||
|
|
||||||
if (rabbitWeaponry->cooldown > 0) return;
|
if (rabbitWeaponry->cooldown > 0) return;
|
||||||
|
|
||||||
|
@ -34,15 +36,15 @@ void attemptToFireRabbitBullet(
|
||||||
rabbitBulletPosition[availableBullet].isActive = 1;
|
rabbitBulletPosition[availableBullet].isActive = 1;
|
||||||
rabbitBulletPosition[availableBullet].willBeInactive = 0;
|
rabbitBulletPosition[availableBullet].willBeInactive = 0;
|
||||||
rabbitBulletPosition[availableBullet].x = rabbitPosition->rabbitPosition[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].oldX = rabbitBulletPosition[availableBullet].x;
|
||||||
rabbitBulletPosition[availableBullet].oldY = rabbitBulletPosition[availableBullet].y;
|
rabbitBulletPosition[availableBullet].oldY = rabbitBulletPosition[availableBullet].y;
|
||||||
|
|
||||||
rabbitBulletPosition[availableBullet].velocityXSteps[0] = doubleVelocityX / RABBIT_BULLET_VELOCITY;
|
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[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;
|
rabbitBulletPosition[availableBullet].velocityStep = 0;
|
||||||
}
|
}
|
||||||
|
@ -81,22 +83,12 @@ struct CollisionDetection {
|
||||||
struct CollisionDetection collisionDetection;
|
struct CollisionDetection collisionDetection;
|
||||||
|
|
||||||
int isCollision() {
|
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
|
return 1;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void populateSourceCollision(struct CompiledSpriteRender *sprite) {
|
void populateSourceCollision(struct CompiledSpriteRender *sprite) {
|
||||||
|
@ -117,31 +109,108 @@ void populateTargetCollision(struct CompiledSpriteRender *sprite) {
|
||||||
collisionDetection.targetEY = bounds.bottom;
|
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(
|
void handleRabbitBulletToEnemyCollisions(
|
||||||
struct BulletPosition rabbitBulletPosition[],
|
struct BulletPosition rabbitBulletPosition[],
|
||||||
struct EnemyPosition enemyPosition[]
|
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) {
|
for (bulletIdx = 0; bulletIdx < RABBIT_BULLET_LIMIT; ++bulletIdx) {
|
||||||
if (!rabbitBulletPosition[bulletIdx].isActive) continue;
|
if (!rabbitBulletPosition[bulletIdx].isActive) continue;
|
||||||
if (rabbitBulletPosition[bulletIdx].willBeInactive) 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) {
|
rabbitBulletGrid[grid][rabbitGridIndex[grid]++] = bulletIdx;
|
||||||
if (!enemyPosition[enemyIdx].isActive) continue;
|
}
|
||||||
if (enemyPosition[enemyIdx].willBeInactive) continue;
|
|
||||||
|
|
||||||
populateTargetCollision(&enemy);
|
for (grid = 0; grid < 4; ++grid) {
|
||||||
|
enemyGridIndex[grid] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (isCollision()) {
|
for (enemyIdx = 0; enemyIdx < ENEMY_MAX_COUNT; ++enemyIdx) {
|
||||||
enemyPosition[enemyIdx].willBeInactive = 1;
|
if (!enemyPosition[enemyIdx].isActive) continue;
|
||||||
rabbitBulletPosition[bulletIdx].willBeInactive = 1;
|
if (enemyPosition[enemyIdx].willBeInactive) continue;
|
||||||
break;
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
5
combat.h
5
combat.h
|
@ -13,3 +13,8 @@ void handleRabbitBulletToEnemyCollisions(
|
||||||
struct BulletPosition[],
|
struct BulletPosition[],
|
||||||
struct EnemyPosition[]
|
struct EnemyPosition[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void handleRabbitToEnemyCollisions(
|
||||||
|
struct RabbitPosition*,
|
||||||
|
struct EnemyPosition[]
|
||||||
|
);
|
||||||
|
|
4
const.h
4
const.h
|
@ -10,7 +10,7 @@
|
||||||
#define RABBIT_MOTION_VELOCITY_DECAY (5)
|
#define RABBIT_MOTION_VELOCITY_DECAY (5)
|
||||||
|
|
||||||
#define RABBIT_BULLET_LIMIT (12)
|
#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_COOLDOWN (10)
|
||||||
#define RABBIT_BULLET_HEIGHT_START (8)
|
#define RABBIT_BULLET_HEIGHT_START (8)
|
||||||
|
|
||||||
|
@ -22,4 +22,4 @@
|
||||||
#define RAD2DEG (180/3.14159)
|
#define RAD2DEG (180/3.14159)
|
||||||
#define DEG2RAD (3.14159/180)
|
#define DEG2RAD (3.14159/180)
|
||||||
|
|
||||||
#define ENEMY_MAX_COUNT (20)
|
#define ENEMY_MAX_COUNT (50)
|
||||||
|
|
18
game.c
18
game.c
|
@ -1,3 +1,4 @@
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <conio.h>
|
#include <conio.h>
|
||||||
|
@ -42,7 +43,7 @@ struct SpawnPointRange {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SpawnPointRange spawnPointRanges[1] = {
|
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() {
|
void maybeSpawnEnemy() {
|
||||||
char canSpawn;
|
char canSpawn;
|
||||||
int i, availableEnemy;
|
int i, availableEnemy;
|
||||||
|
@ -238,7 +238,7 @@ int setupGame() {
|
||||||
|
|
||||||
spritesheetImage.transparentColor = 0;
|
spritesheetImage.transparentColor = 0;
|
||||||
|
|
||||||
setupWallSprites(&spritesheetImage);
|
setupWallSprites();
|
||||||
setupRabbitSprites();
|
setupRabbitSprites();
|
||||||
setupRabbitBullets();
|
setupRabbitBullets();
|
||||||
setupEnemySprites();
|
setupEnemySprites();
|
||||||
|
@ -286,6 +286,11 @@ void handleCombat() {
|
||||||
&rabbitWeaponry
|
&rabbitWeaponry
|
||||||
);
|
);
|
||||||
|
|
||||||
|
handleRabbitToEnemyCollisions(
|
||||||
|
&rabbitPosition,
|
||||||
|
enemyPosition
|
||||||
|
);
|
||||||
|
|
||||||
handleRabbitBulletToEnemyCollisions(
|
handleRabbitBulletToEnemyCollisions(
|
||||||
rabbitBulletPosition,
|
rabbitBulletPosition,
|
||||||
enemyPosition
|
enemyPosition
|
||||||
|
@ -316,23 +321,26 @@ clock_t startTime;
|
||||||
int main(void) {
|
int main(void) {
|
||||||
byte *drawBuffer;
|
byte *drawBuffer;
|
||||||
int keepRunning = 1;
|
int keepRunning = 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (setupGame()) return 1;
|
if (setupGame()) return 1;
|
||||||
|
|
||||||
drawBuffer = getDrawBuffer();
|
drawBuffer = getDrawBuffer();
|
||||||
|
|
||||||
maybeSpawnEnemy();
|
for (i = 0; i < ENEMY_MAX_COUNT; ++i) {
|
||||||
|
maybeSpawnEnemy();
|
||||||
|
}
|
||||||
|
|
||||||
while (keepRunning) {
|
while (keepRunning) {
|
||||||
readMouse(&mouseStatus);
|
readMouse(&mouseStatus);
|
||||||
populateKeyboardKeydownState();
|
populateKeyboardKeydownState();
|
||||||
|
|
||||||
handleMovement();
|
handleMovement();
|
||||||
handleCombat();
|
|
||||||
handleRedraw();
|
handleRedraw();
|
||||||
|
|
||||||
waitStartVbl();
|
waitStartVbl();
|
||||||
copyDrawBufferToDisplay();
|
copyDrawBufferToDisplay();
|
||||||
|
handleCombat();
|
||||||
waitEndVbl();
|
waitEndVbl();
|
||||||
|
|
||||||
if (keyboardKeydownState.KEY_ESC) { keepRunning = 0; }
|
if (keyboardKeydownState.KEY_ESC) { keepRunning = 0; }
|
||||||
|
|
|
@ -31,7 +31,7 @@ void calculateTargetAngle(
|
||||||
|
|
||||||
// Position the cursor
|
// Position the cursor
|
||||||
distanceX = pos->mouseDotPosition[0] - pos->rabbitPosition[0];
|
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;
|
angle = atan2(distanceY, distanceX) * RAD2DEG + 90;
|
||||||
if (angle < 0) angle += 360;
|
if (angle < 0) angle += 360;
|
||||||
|
|
Loading…
Reference in New Issue