starting on shotgun

This commit is contained in:
John Bintz 2024-02-26 18:12:39 -05:00
parent 36cb73a9b9
commit 71a6c65f3b
6 changed files with 180 additions and 54 deletions

View File

@ -15,6 +15,7 @@ void setupBullet(struct BulletPosition *bullet, int x, int y, signed int doubleV
bullet->y = y; bullet->y = y;
bullet->oldX = x; bullet->oldX = x;
bullet->oldY = y; bullet->oldY = y;
bullet->wallCooldown = 1;
bullet->velocityXSteps[0] = doubleVelocityX / velocity; bullet->velocityXSteps[0] = doubleVelocityX / velocity;
bullet->velocityXSteps[1] = doubleVelocityX - bullet->velocityXSteps[0]; bullet->velocityXSteps[1] = doubleVelocityX - bullet->velocityXSteps[0];
@ -35,6 +36,9 @@ void attemptToFireRabbitBullet(
if (rabbitWeaponry->cooldown > 0) return; if (rabbitWeaponry->cooldown > 0) return;
rabbitWeaponry->cooldown = RABBIT_BULLET_COOLDOWN;
if (rabbitWeaponry->currentWeapon == SINGLE_SHOT_GUN) {
for (i = 0; i < RABBIT_BULLET_LIMIT; ++i) { for (i = 0; i < RABBIT_BULLET_LIMIT; ++i) {
if (rabbitBulletPosition[i].isActive == 0) { if (rabbitBulletPosition[i].isActive == 0) {
okToFire = 1; okToFire = 1;
@ -45,8 +49,6 @@ void attemptToFireRabbitBullet(
if (!okToFire) return; if (!okToFire) return;
rabbitWeaponry->cooldown = RABBIT_BULLET_COOLDOWN;
doubleVelocityX = sin(rabbitPosition->mouseAngle * DEG2RAD) * (RABBIT_BULLET_VELOCITY * 2); doubleVelocityX = sin(rabbitPosition->mouseAngle * DEG2RAD) * (RABBIT_BULLET_VELOCITY * 2);
doubleVelocityY = -cos(rabbitPosition->mouseAngle * DEG2RAD) * (RABBIT_BULLET_VELOCITY * 2); doubleVelocityY = -cos(rabbitPosition->mouseAngle * DEG2RAD) * (RABBIT_BULLET_VELOCITY * 2);
@ -58,6 +60,23 @@ void attemptToFireRabbitBullet(
doubleVelocityY, doubleVelocityY,
RABBIT_BULLET_VELOCITY RABBIT_BULLET_VELOCITY
); );
} else if (rabbitWeaponry->currentWeapon == SPREAD_SHOT_GUN) {
// make sure three bullets are available
// if so, fire away
for (i = -1; i <= 1; ++i) {
doubleVelocityX = sin(rabbitPosition->mouseAngle * DEG2RAD) * (RABBIT_BULLET_VELOCITY * 2);
doubleVelocityY = -cos(rabbitPosition->mouseAngle * DEG2RAD) * (RABBIT_BULLET_VELOCITY * 2);
setupBullet(
&rabbitBulletPosition[availableBullet],
rabbitPosition->rabbitPosition[0],
rabbitPosition->rabbitPosition[1],
doubleVelocityX,
doubleVelocityY,
RABBIT_BULLET_VELOCITY
);
}
}
} }
void advanceRabbitBullets( void advanceRabbitBullets(
@ -75,10 +94,15 @@ void advanceRabbitBullets(
rabbitBulletPosition[i].x += rabbitBulletPosition[i].velocityXSteps[rabbitBulletPosition[i].velocityStep]; rabbitBulletPosition[i].x += rabbitBulletPosition[i].velocityXSteps[rabbitBulletPosition[i].velocityStep];
rabbitBulletPosition[i].y += rabbitBulletPosition[i].velocityYSteps[rabbitBulletPosition[i].velocityStep]; rabbitBulletPosition[i].y += rabbitBulletPosition[i].velocityYSteps[rabbitBulletPosition[i].velocityStep];
if (rabbitBulletPosition[i].wallCooldown == 0) {
if (rabbitBulletPosition[i].x < MOUSE_LIMIT_LEFT) rabbitBulletPosition[i].willBeInactive = 1; 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].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_TOP) rabbitBulletPosition[i].willBeInactive = 1;
if (rabbitBulletPosition[i].y >= MOUSE_LIMIT_BOTTOM) rabbitBulletPosition[i].willBeInactive = 1; if (rabbitBulletPosition[i].y >= MOUSE_LIMIT_BOTTOM) rabbitBulletPosition[i].willBeInactive = 1;
} else {
rabbitBulletPosition[i].wallCooldown--;
}
rabbitBulletPosition[i].velocityStep = 1 - rabbitBulletPosition[i].velocityStep; rabbitBulletPosition[i].velocityStep = 1 - rabbitBulletPosition[i].velocityStep;
} }
@ -348,8 +372,11 @@ void handleRabbitBulletToEnemyCollisions(
populateTargetCollision(&enemy); populateTargetCollision(&enemy);
if (isCollision()) { if (isCollision()) {
enemyPosition[resolvedEnemyIdx].hitPoints--;
if (enemyPosition[resolvedEnemyIdx].hitPoints < 1) {
enemyPosition[resolvedEnemyIdx].willBeInactive = 1; enemyPosition[resolvedEnemyIdx].willBeInactive = 1;
enemyPosition[resolvedBulletIdx].wasKilled = 1; enemyPosition[resolvedBulletIdx].wasKilled = 1;
}
rabbitBulletPosition[resolvedBulletIdx].willBeInactive = 1; rabbitBulletPosition[resolvedBulletIdx].willBeInactive = 1;
break; break;
} }

View File

@ -26,18 +26,19 @@
#define DEG2RAD (3.14159/180) #define DEG2RAD (3.14159/180)
#define ENEMY_MAX_COUNT (50) #define ENEMY_MAX_COUNT (50)
#define ENEMY_BULLET_LIMIT (ENEMY_MAX_COUNT / 2) #define ENEMY_BULLET_LIMIT (ENEMY_MAX_COUNT / 4)
#define ENEMY_MOVE_SPEED (1) #define ENEMY_MOVE_SPEED (1)
#define ENEMY_MOVE_DELAY (3) #define ENEMY_MOVE_DELAY (3)
#define ENEMY_BULLET_VELOCITY (RABBIT_BULLET_VELOCITY - 2) #define ENEMY_BULLET_VELOCITY (RABBIT_BULLET_VELOCITY - 2)
#define ENEMY_FIRE_MIN_DELAY (35) #define ENEMY_FIRE_MIN_DELAY (45)
#define ENEMY_FIRE_VARIABLE_DELAY (60) #define ENEMY_FIRE_VARIABLE_DELAY (60)
#define ENEMY_BULLET_DAMAGE (4) #define ENEMY_BULLET_DAMAGE (3)
#define ENEMY_COLLISION_DAMAGE (8) #define ENEMY_COLLISION_DAMAGE (6)
#define ENEMY_KILL_HEALTH_GAIN (1) #define ENEMY_KILL_HEALTH_GAIN (1)
#define ENEMY_HIT_POINT_DIFFICULTY_INCREASE_EVERY (4)
#define BASE_ENEMY_SPAWN_COOLDOWN (30) #define BASE_ENEMY_SPAWN_COOLDOWN (30)
#define DIFFICULTY_SPAWN_COOLDOWN_REDUCTION (2) #define DIFFICULTY_SPAWN_COOLDOWN_REDUCTION (2)

51
game.c
View File

@ -16,7 +16,7 @@
#include "arena.h" #include "arena.h"
#include "movement.h" #include "movement.h"
#include "combat.h" #include "combat.h"
#include "game.h"
// TODO: centralize these outside of game.c // TODO: centralize these outside of game.c
struct CompiledSpriteRender rabbit, mouse, bullet, enemy, enemyBullet; struct CompiledSpriteRender rabbit, mouse, bullet, enemy, enemyBullet;
@ -29,7 +29,10 @@ struct MouseStatus mouseStatus;
struct RabbitPosition rabbitPosition = { struct RabbitPosition rabbitPosition = {
.rabbitPosition = { 60, 60 }, .rabbitPosition = { 60, 60 },
.rabbitLimits = { { 20, 20 }, { 180, 180 } }, .rabbitLimits = {
{ 20, 20 },
{ (ARENA_WIDTH_TILES - 1) * TILE_SIZE - 2, (ARENA_HEIGHT_TILES - 1) * TILE_SIZE - 2 }
},
.mousePosition = { 0, 0 }, .mousePosition = { 0, 0 },
.rabbitVelocity = { 0, 0 }, .rabbitVelocity = { 0, 0 },
.mouseDotPosition = { 0, 0 } .mouseDotPosition = { 0, 0 }
@ -39,19 +42,17 @@ struct BulletPosition rabbitBulletPosition[RABBIT_BULLET_LIMIT];
struct BulletPosition enemyBulletPosition[ENEMY_BULLET_LIMIT]; struct BulletPosition enemyBulletPosition[ENEMY_BULLET_LIMIT];
struct RabbitWeaponry rabbitWeaponry; struct RabbitWeaponry rabbitWeaponry;
struct SpawnPointRange {
int left, width;
int top, height;
};
struct SpawnPointRange spawnPointRanges[4] = { struct SpawnPointRange spawnPointRanges[4] = {
{ .left = TILE_SIZE * 4, .width = TILE_SIZE * 2, .top = TILE_SIZE, .height = TILE_SIZE }, // top
{ .left = TILE_SIZE * 4, .width = TILE_SIZE * 2, .top = (ARENA_HEIGHT_TILES - 2) * TILE_SIZE, .height = TILE_SIZE }, { .left = TILE_SIZE * 4, .width = TILE_SIZE * 2, .top = TILE_SIZE - 8, .height = TILE_SIZE },
{ .left = TILE_SIZE, .width = TILE_SIZE, .top = TILE_SIZE * 4, .height = TILE_SIZE * 2 }, // right
{ .left = (ARENA_WIDTH_TILES - 2) * TILE_SIZE, .width = TILE_SIZE, .top = TILE_SIZE * 4, .height = TILE_SIZE * 2 }, { .left = (ARENA_WIDTH_TILES - 1) * TILE_SIZE - 8, .width = TILE_SIZE, .top = TILE_SIZE * 4, .height = TILE_SIZE * 2 },
// bottom
{ .left = TILE_SIZE * 4, .width = TILE_SIZE * 2, .top = (ARENA_HEIGHT_TILES - 1) * TILE_SIZE - 8, .height = TILE_SIZE },
// left
{ .left = TILE_SIZE - 8, .width = TILE_SIZE, .top = TILE_SIZE * 4, .height = TILE_SIZE * 2 },
}; };
void setupRabbitBullets() { void setupRabbitBullets() {
int i; int i;
@ -61,6 +62,7 @@ void setupRabbitBullets() {
} }
rabbitWeaponry.cooldown = 0; rabbitWeaponry.cooldown = 0;
rabbitWeaponry.currentWeapon = SPREAD_SHOT_GUN;
} }
void setupEnemyBullets() { void setupEnemyBullets() {
@ -113,8 +115,10 @@ void handleEnemyKills() {
void maybeSpawnEnemy() { void maybeSpawnEnemy() {
char canSpawn; char canSpawn;
int i, availableEnemy; int i, gate, availableEnemy, gatePlayerIsFacing;
int spawnX, spawnY; int spawnX, spawnY, spawnTry;
char buffer[20];
if (spawnCooldown-- > 0) return; if (spawnCooldown-- > 0) return;
@ -128,14 +132,27 @@ void maybeSpawnEnemy() {
if (!canSpawn) return; if (!canSpawn) return;
i = rand() % 4; // determine which gate the player is at and reduce the likelihood of
// spawning from that gate
// * 8 chances to spawn [0, 1] for each gate
// * if the gate the player is looking at gets [0], reroll
// * try three times max to limit cost of calculating
for (spawnTry = 0; spawnTry < 3; ++spawnTry) {
i = rand() % 12;
gate = i / 3;
spawnX = spawnPointRanges[i].left + rand() % spawnPointRanges[i].width; if (gatePlayerIsFacing == gate && i % 3 != 0) continue;
spawnY = spawnPointRanges[i].top + rand() % spawnPointRanges[i].height; }
spawnX = spawnPointRanges[gate].left + rand() % spawnPointRanges[gate].width;
spawnY = spawnPointRanges[gate].top + rand() % spawnPointRanges[gate].height;
enemyPosition[availableEnemy].isActive = 1; enemyPosition[availableEnemy].isActive = 1;
enemyPosition[availableEnemy].willBeInactive = 0; enemyPosition[availableEnemy].willBeInactive = 0;
enemyPosition[availableEnemy].wasKilled = 0; enemyPosition[availableEnemy].wasKilled = 0;
enemyPosition[availableEnemy].hitPoints = 1 + difficulty / ENEMY_HIT_POINT_DIFFICULTY_INCREASE_EVERY;
enemyPosition[availableEnemy].hasLeftGate = 0;
enemyPosition[availableEnemy].gateExitedFrom = gate;
enemyPosition[availableEnemy].enemyMoveDelayStep = 0; enemyPosition[availableEnemy].enemyMoveDelayStep = 0;
enemyPosition[availableEnemy].enemyFireDelayStep = ENEMY_FIRE_MIN_DELAY + rand() % ENEMY_FIRE_VARIABLE_DELAY; enemyPosition[availableEnemy].enemyFireDelayStep = ENEMY_FIRE_MIN_DELAY + rand() % ENEMY_FIRE_VARIABLE_DELAY;
enemyPosition[availableEnemy].enemyPosition[0] = spawnX; enemyPosition[availableEnemy].enemyPosition[0] = spawnX;

11
game.h
View File

@ -1,4 +1,15 @@
#ifndef __GAME_H__
#define __GAME_H__
#include "system/vga.h" #include "system/vga.h"
struct SpawnPointRange {
int left, width;
int top, height;
};
extern struct CompiledSpriteRender rabbit, mouse, bullet, enemy, enemyBullet; extern struct CompiledSpriteRender rabbit, mouse, bullet, enemy, enemyBullet;
extern struct SpriteBounds bounds; extern struct SpriteBounds bounds;
extern struct SpawnPointRange spawnPointRanges[];
#endif

View File

@ -1,6 +1,7 @@
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include "game.h"
#include "const.h" #include "const.h"
#include "movement.h" #include "movement.h"
#include "system/mouse_io.h" #include "system/mouse_io.h"
@ -55,6 +56,7 @@ void handleEnemyMovement(
struct EnemyPosition enemyPosition[], struct EnemyPosition enemyPosition[],
struct RabbitPosition *pos struct RabbitPosition *pos
) { ) {
char hasExitedGate;
int i, xDistance, yDistance; int i, xDistance, yDistance;
for (i = 0; i < ENEMY_MAX_COUNT; ++i) { for (i = 0; i < ENEMY_MAX_COUNT; ++i) {
@ -64,18 +66,71 @@ void handleEnemyMovement(
if (enemyPosition[i].enemyMoveDelayStep < ENEMY_MOVE_DELAY) continue; if (enemyPosition[i].enemyMoveDelayStep < ENEMY_MOVE_DELAY) continue;
enemyPosition[i].enemyMoveDelayStep = 0; enemyPosition[i].enemyMoveDelayStep = 0;
enemyPosition[i].oldEnemyPosition[0] = enemyPosition[i].enemyPosition[0];
enemyPosition[i].oldEnemyPosition[1] = enemyPosition[i].enemyPosition[1];
if (enemyPosition[i].hasLeftGate) {
// which straight directon is the player closest to // which straight directon is the player closest to
xDistance = pos->rabbitPosition[0] - enemyPosition[i].enemyPosition[0]; xDistance = pos->rabbitPosition[0] - enemyPosition[i].enemyPosition[0];
yDistance = pos->rabbitPosition[1] - enemyPosition[i].enemyPosition[1]; yDistance = pos->rabbitPosition[1] - enemyPosition[i].enemyPosition[1];
enemyPosition[i].oldEnemyPosition[0] = enemyPosition[i].enemyPosition[0];
enemyPosition[i].oldEnemyPosition[1] = enemyPosition[i].enemyPosition[1];
if (abs(xDistance) > abs(yDistance)) { if (abs(xDistance) > abs(yDistance)) {
enemyPosition[i].enemyPosition[0] += SIGN(xDistance) * ENEMY_MOVE_SPEED; enemyPosition[i].enemyPosition[0] += SIGN(xDistance) * ENEMY_MOVE_SPEED;
} else { } else {
enemyPosition[i].enemyPosition[1] += SIGN(yDistance) * ENEMY_MOVE_SPEED; enemyPosition[i].enemyPosition[1] += SIGN(yDistance) * ENEMY_MOVE_SPEED;
} }
} else {
switch (enemyPosition[i].gateExitedFrom) {
// top
case 0:
xDistance = 0;
yDistance = ENEMY_MOVE_SPEED;
break;
// right
case 1:
xDistance = -ENEMY_MOVE_SPEED;
yDistance = 0;
break;
// bottom
case 2:
xDistance = 0;
yDistance = -ENEMY_MOVE_SPEED;
break;
// left
case 3:
xDistance = ENEMY_MOVE_SPEED;
yDistance = 0;
break;
}
enemyPosition[i].enemyPosition[0] += xDistance;
enemyPosition[i].enemyPosition[1] += yDistance;
switch (enemyPosition[i].gateExitedFrom) {
case 0:
hasExitedGate = (
enemyPosition[i].enemyPosition[1] > spawnPointRanges[0].top + spawnPointRanges[0].height
);
break;
case 1:
hasExitedGate = (
enemyPosition[i].enemyPosition[0] < spawnPointRanges[1].left
);
break;
case 2:
hasExitedGate = (
enemyPosition[i].enemyPosition[1] < spawnPointRanges[2].top
);
break;
case 3:
hasExitedGate = (
enemyPosition[i].enemyPosition[0] > spawnPointRanges[3].left + spawnPointRanges[3].width
);
break;
}
enemyPosition[i].hasLeftGate = hasExitedGate;
}
} }
} }

View File

@ -1,3 +1,6 @@
#ifndef __MOVEMENT_H__
#define __MOVEMENT_H__
#include "system/keyboard.h" #include "system/keyboard.h"
struct RabbitPosition { struct RabbitPosition {
@ -15,8 +18,12 @@ struct RabbitPosition {
int mouseAngle; int mouseAngle;
}; };
#define SINGLE_SHOT_GUN (0)
#define SPREAD_SHOT_GUN (1)
struct RabbitWeaponry { struct RabbitWeaponry {
char cooldown; char cooldown;
char currentWeapon;
}; };
struct BulletPosition { struct BulletPosition {
@ -27,6 +34,8 @@ struct BulletPosition {
int x, y; int x, y;
int oldX, oldY; int oldX, oldY;
int wallCooldown;
signed int velocityXSteps[2], velocityYSteps[2]; signed int velocityXSteps[2], velocityYSteps[2];
int velocityStep; int velocityStep;
}; };
@ -37,6 +46,10 @@ struct EnemyPosition {
char willBeInactive; char willBeInactive;
char wasKilled; char wasKilled;
char hitPoints;
char hasLeftGate;
char gateExitedFrom;
int enemyPosition[2]; int enemyPosition[2];
int oldEnemyPosition[2]; int oldEnemyPosition[2];
@ -48,3 +61,5 @@ void calculateTargetAngle(struct RabbitPosition*, struct MouseStatus*);
void captureAndLimitMousePosition(struct RabbitPosition*, struct MouseStatus*); void captureAndLimitMousePosition(struct RabbitPosition*, struct MouseStatus*);
void handleRabbitMovement(struct RabbitPosition*, struct KeyboardKeydownState*); void handleRabbitMovement(struct RabbitPosition*, struct KeyboardKeydownState*);
void handleEnemyMovement(struct EnemyPosition[], struct RabbitPosition*); void handleEnemyMovement(struct EnemyPosition[], struct RabbitPosition*);
#endif