150 lines
5.0 KiB
C
150 lines
5.0 KiB
C
|
#include <math.h>
|
||
|
|
||
|
#include "game.h"
|
||
|
|
||
|
#include "movement.h"
|
||
|
#include "const.h"
|
||
|
#include "system/vga.h"
|
||
|
|
||
|
void attemptToFireRabbitBullet(
|
||
|
struct RabbitPosition *rabbitPosition,
|
||
|
struct RabbitWeaponry *rabbitWeaponry,
|
||
|
struct BulletPosition rabbitBulletPosition[]
|
||
|
) {
|
||
|
int okToFire = 0, availableBullet, i;
|
||
|
signed char doubleVelocityX, doubleVelocityY;
|
||
|
|
||
|
if (rabbitWeaponry->cooldown > 0) return;
|
||
|
|
||
|
for (i = 0; i < RABBIT_BULLET_LIMIT; ++i) {
|
||
|
if (rabbitBulletPosition[i].isActive == 0) {
|
||
|
okToFire = 1;
|
||
|
availableBullet = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!okToFire) return;
|
||
|
|
||
|
rabbitWeaponry->cooldown = RABBIT_BULLET_COOLDOWN;
|
||
|
|
||
|
doubleVelocityX = sin(rabbitPosition->mouseAngle * DEG2RAD) * (RABBIT_BULLET_VELOCITY * 2);
|
||
|
doubleVelocityY = -cos(rabbitPosition->mouseAngle * DEG2RAD) * (RABBIT_BULLET_VELOCITY * 2);
|
||
|
|
||
|
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].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].velocityYSteps[0] = doubleVelocityY / RABBIT_BULLET_VELOCITY;
|
||
|
rabbitBulletPosition[availableBullet].velocityYSteps[1] = doubleVelocityY % RABBIT_BULLET_VELOCITY;
|
||
|
|
||
|
rabbitBulletPosition[availableBullet].velocityStep = 0;
|
||
|
}
|
||
|
|
||
|
void advanceRabbitBullets(
|
||
|
struct BulletPosition rabbitBulletPosition[],
|
||
|
struct RabbitWeaponry *rabbitWeaponry
|
||
|
) {
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < RABBIT_BULLET_LIMIT; ++i) {
|
||
|
if (!rabbitBulletPosition[i].isActive) continue;
|
||
|
|
||
|
rabbitBulletPosition[i].oldX = rabbitBulletPosition[i].x;
|
||
|
rabbitBulletPosition[i].oldY = rabbitBulletPosition[i].y;
|
||
|
|
||
|
rabbitBulletPosition[i].x += rabbitBulletPosition[i].velocityXSteps[rabbitBulletPosition[i].velocityStep];
|
||
|
rabbitBulletPosition[i].y += rabbitBulletPosition[i].velocityYSteps[rabbitBulletPosition[i].velocityStep];
|
||
|
|
||
|
if (rabbitBulletPosition[i].x < MOUSE_LIMIT_LEFT) rabbitBulletPosition[i].willBeInactive = 1;
|
||
|
if (rabbitBulletPosition[i].x >= MOUSE_LIMIT_RIGHT) rabbitBulletPosition[i].willBeInactive = 1;
|
||
|
if (rabbitBulletPosition[i].y < MOUSE_LIMIT_TOP) rabbitBulletPosition[i].willBeInactive = 1;
|
||
|
if (rabbitBulletPosition[i].y >= MOUSE_LIMIT_BOTTOM) rabbitBulletPosition[i].willBeInactive = 1;
|
||
|
|
||
|
rabbitBulletPosition[i].velocityStep = 1 - rabbitBulletPosition[i].velocityStep;
|
||
|
}
|
||
|
|
||
|
if (rabbitWeaponry->cooldown > 0) rabbitWeaponry->cooldown--;
|
||
|
}
|
||
|
|
||
|
struct CollisionDetection {
|
||
|
short int sourceSX, sourceSY, sourceEX, sourceEY;
|
||
|
short int targetSX, targetSY, targetEX, targetEY;
|
||
|
};
|
||
|
|
||
|
struct CollisionDetection collisionDetection;
|
||
|
|
||
|
int isCollision() {
|
||
|
int result;
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
|
||
|
void populateSourceCollision(struct CompiledSpriteRender *sprite) {
|
||
|
getSpriteBounds(sprite, &bounds);
|
||
|
|
||
|
collisionDetection.sourceSX = bounds.left;
|
||
|
collisionDetection.sourceSY = bounds.top;
|
||
|
collisionDetection.sourceEX = bounds.right;
|
||
|
collisionDetection.sourceEY = bounds.bottom;
|
||
|
}
|
||
|
|
||
|
void populateTargetCollision(struct CompiledSpriteRender *sprite) {
|
||
|
getSpriteBounds(sprite, &bounds);
|
||
|
|
||
|
collisionDetection.targetSX = bounds.left;
|
||
|
collisionDetection.targetSY = bounds.top;
|
||
|
collisionDetection.targetEX = bounds.right;
|
||
|
collisionDetection.targetEY = bounds.bottom;
|
||
|
}
|
||
|
|
||
|
void handleRabbitBulletToEnemyCollisions(
|
||
|
struct BulletPosition rabbitBulletPosition[],
|
||
|
struct EnemyPosition enemyPosition[]
|
||
|
) {
|
||
|
int bulletIdx, enemyIdx;
|
||
|
|
||
|
// 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);
|
||
|
|
||
|
for (enemyIdx = 0; enemyIdx < ENEMY_MAX_COUNT; ++enemyIdx) {
|
||
|
if (!enemyPosition[enemyIdx].isActive) continue;
|
||
|
if (enemyPosition[enemyIdx].willBeInactive) continue;
|
||
|
|
||
|
populateTargetCollision(&enemy);
|
||
|
|
||
|
if (isCollision()) {
|
||
|
enemyPosition[enemyIdx].willBeInactive = 1;
|
||
|
rabbitBulletPosition[bulletIdx].willBeInactive = 1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|