dos-vga-arena-shooter-game/game.c

335 lines
7.5 KiB
C
Raw Normal View History

2024-02-15 13:34:50 +00:00
#include <stdio.h>
2024-02-20 11:48:12 +00:00
#include <math.h>
#include <conio.h>
2024-02-15 13:34:50 +00:00
2024-02-20 13:00:13 +00:00
#include "system/vga.h"
#include "system/keyboard.h"
#include "system/mouse_io.h"
#include "system/pc_stuff.h"
2024-02-15 13:34:50 +00:00
#include "bmpload.h"
2024-02-15 01:15:55 +00:00
2024-02-15 13:34:50 +00:00
struct BMPImage spritesheetImage;
struct VGAColor vgaColors[256];
struct SpriteRender arenaWallTop, arenaWallSide, arenaFloor;
2024-02-20 11:48:12 +00:00
struct SpriteRender rabbit, mouse;
2024-02-16 02:18:15 +00:00
void setupWallSprites() {
buildSpriteFromSpritesheet(
&spritesheetImage,
&arenaWallTop,
0, 0, 20, 20
);
buildSpriteFromSpritesheet(
&spritesheetImage,
&arenaWallSide,
20, 0, 20, 20
);
buildSpriteFromSpritesheet(
&spritesheetImage,
&arenaFloor,
40, 0, 20, 20
);
}
void setupRabbitSprites() {
buildSpriteFromSpritesheet(
&spritesheetImage,
&rabbit,
0, 20, 16, 16
);
2024-02-20 11:48:12 +00:00
rabbit.offsetX = 8;
rabbit.offsetY = 15;
buildSpriteFromSpritesheet(
&spritesheetImage,
&mouse,
16, 20, 8, 8
);
mouse.offsetX = 4;
mouse.offsetY = 4;
2024-02-16 02:18:15 +00:00
}
char arenaLayout[10][10] = {
{ 1, 1, 1, 1, 0, 0, 1, 1, 1, 1 },
{ 1, 2, 2, 2, 0, 0, 2, 2, 2, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 2, 0, 0, 0, 0, 0, 0, 0, 0, 2 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 1, 1, 1, 0, 0, 1, 1, 1, 1 }
};
void renderArenaTile(int x, int y) {
char tile;
struct SpriteRender *target;
tile = arenaLayout[y][x];
switch (tile) {
case 0:
target = &arenaFloor;
break;
case 1:
target = &arenaWallTop;
break;
case 2:
target = &arenaWallSide;
break;
}
target->x = x * 20;
target->y = y * 20;
drawSprite(target);
}
void buildArena() {
int x, y;
for (y = 0; y < 10; ++y) {
for (x = 0; x < 10; ++x) {
renderArenaTile(x, y);
}
}
}
2024-02-20 17:39:28 +00:00
#define RABBIT_MOTION_DRAG (2)
#define RABBIT_MOTION_ACCELERATION (5)
#define RABBIT_MOTION_MAX_SPEED (12)
2024-02-16 02:18:15 +00:00
int rabbitPosition[2] = { 60, 60 };
2024-02-20 13:20:35 +00:00
int oldRabbitPosition[2] = { 60, 60 };
2024-02-16 02:18:15 +00:00
int rabbitLimits[2][2] = {
{ 20, 20 },
{ 180, 180 }
};
signed char rabbitVelocity[2] = { 0, 0 };
2024-02-20 11:48:12 +00:00
struct MouseStatus mouseStatus;
char mousePosition[2] = { 0, 0 };
2024-02-20 13:20:35 +00:00
char oldMousePosition[2] = { 0, 0 };
2024-02-20 11:48:12 +00:00
2024-02-20 17:39:28 +00:00
char mouseDotPosition[2] = { 0, 0 };
char oldMouseDotPosition[2] = { 0, 0 };
2024-02-16 02:18:15 +00:00
2024-02-20 17:39:28 +00:00
void renderMouse() {
2024-02-20 11:48:12 +00:00
mouse.x = mousePosition[0];
mouse.y = mousePosition[1];
drawSprite(&mouse);
2024-02-20 17:39:28 +00:00
drawPixel(mouseDotPosition[0], mouseDotPosition[1], 2);
2024-02-20 11:48:12 +00:00
}
void renderRabbit() {
2024-02-20 17:39:28 +00:00
rabbit.x = rabbitPosition[0];
rabbit.y = rabbitPosition[1];
2024-02-16 02:18:15 +00:00
drawSprite(&rabbit);
}
void handleRabbitMovement() {
int i;
if (keyboardKeydownState.KEY_W) {
rabbitVelocity[1] -= RABBIT_MOTION_ACCELERATION;
if (rabbitVelocity[1] < -RABBIT_MOTION_MAX_SPEED) {
rabbitVelocity[1] = -RABBIT_MOTION_MAX_SPEED;
}
}
if (keyboardKeydownState.KEY_S) {
rabbitVelocity[1] += RABBIT_MOTION_ACCELERATION;
if (rabbitVelocity[1] > RABBIT_MOTION_MAX_SPEED) {
rabbitVelocity[1] = RABBIT_MOTION_MAX_SPEED;
}
}
if (keyboardKeydownState.KEY_A) {
rabbitVelocity[0] -= RABBIT_MOTION_ACCELERATION;
if (rabbitVelocity[0] < -RABBIT_MOTION_MAX_SPEED) {
rabbitVelocity[0] = -RABBIT_MOTION_MAX_SPEED;
}
}
if (keyboardKeydownState.KEY_D) {
rabbitVelocity[0] += RABBIT_MOTION_ACCELERATION;
if (rabbitVelocity[0] > RABBIT_MOTION_MAX_SPEED) {
rabbitVelocity[0] = RABBIT_MOTION_MAX_SPEED;
}
}
for (i = 0; i < 2; ++i) {
2024-02-20 13:20:35 +00:00
oldRabbitPosition[i] = rabbitPosition[i];
2024-02-16 02:18:15 +00:00
rabbitPosition[i] += (rabbitVelocity[i] / 5);
if (rabbitPosition[i] < rabbitLimits[0][i]) {
rabbitPosition[i] = rabbitLimits[0][i];
}
if (rabbitPosition[i] >= rabbitLimits[1][i]) {
rabbitPosition[i] = rabbitLimits[1][i];
}
if (rabbitVelocity[i] < 0) {
rabbitVelocity[i] += RABBIT_MOTION_DRAG;
if (rabbitVelocity[i] > 0) rabbitVelocity[i] = 0;
}
if (rabbitVelocity[i] > 0) {
rabbitVelocity[i] -= RABBIT_MOTION_DRAG;
if (rabbitVelocity[i] < 0) rabbitVelocity[i] = 0;
}
}
}
2024-02-20 13:00:13 +00:00
#define TILE_SIZE (20)
struct SpriteBounds bounds;
2024-02-20 13:20:35 +00:00
char tileRenderQueue[400];
2024-02-20 11:48:12 +00:00
void drawOnlyArena() {
int leftTileX, rightTileX,
topTileY, bottomTileY;
2024-02-20 13:00:13 +00:00
leftTileX = bounds.left / TILE_SIZE;
rightTileX = bounds.right / TILE_SIZE;
topTileY = bounds.top / TILE_SIZE;
bottomTileY = bounds.bottom / TILE_SIZE;
2024-02-20 11:48:12 +00:00
renderArenaTile(leftTileX, topTileY);
2024-02-20 13:20:35 +00:00
renderArenaTile(rightTileX, topTileY);
renderArenaTile(rightTileX, bottomTileY);
renderArenaTile(leftTileX, bottomTileY);
2024-02-16 02:18:15 +00:00
}
2024-02-15 01:15:55 +00:00
2024-02-20 11:48:12 +00:00
void drawOnlyMouseArena() {
2024-02-20 13:20:35 +00:00
mouse.x = oldMousePosition[0];
mouse.y = oldMousePosition[1];
2024-02-20 11:48:12 +00:00
getSpriteBounds(&mouse, &bounds);
drawOnlyArena();
2024-02-20 17:39:28 +00:00
bounds.top = oldMouseDotPosition[1];
bounds.bottom = oldMouseDotPosition[1];
bounds.left = oldMouseDotPosition[0];
bounds.right = oldMouseDotPosition[0];
drawOnlyArena();
2024-02-20 11:48:12 +00:00
}
void drawOnlyRabbitArena() {
2024-02-20 13:20:35 +00:00
rabbit.x = oldRabbitPosition[0];
rabbit.y = oldRabbitPosition[1];
2024-02-20 11:48:12 +00:00
getSpriteBounds(&rabbit, &bounds);
drawOnlyArena();
}
#define RAD2DEG (180/3.14159)
#define DEG2RAD (3.14159/180)
#define MOUSE_DISTANCE (32)
2024-02-20 13:00:13 +00:00
void calculateTargetAngle() {
2024-02-20 11:48:12 +00:00
float distanceX, distanceY;
float angle;
2024-02-20 17:39:28 +00:00
oldMouseDotPosition[0] = mouseDotPosition[0];
oldMouseDotPosition[1] = mouseDotPosition[1];
mouseDotPosition[0] = mouseStatus.xPosition;
mouseDotPosition[1] = mouseStatus.yPosition;
2024-02-20 11:48:12 +00:00
distanceX = mouseStatus.xPosition - rabbitPosition[0];
distanceY = mouseStatus.yPosition - rabbitPosition[1];
2024-02-20 13:00:13 +00:00
angle = atan2(distanceY, distanceX) * 180 / 3.14159 + 90;
if (angle < 0) angle += 360;
2024-02-20 11:48:12 +00:00
2024-02-20 13:00:13 +00:00
distanceX = sin(angle * DEG2RAD) * MOUSE_DISTANCE;
distanceY = -cos(angle * DEG2RAD) * MOUSE_DISTANCE;
2024-02-20 11:48:12 +00:00
2024-02-20 13:20:35 +00:00
oldMousePosition[0] = mousePosition[0];
oldMousePosition[1] = mousePosition[1];
2024-02-20 11:48:12 +00:00
mousePosition[0] = rabbitPosition[0] + distanceX;
mousePosition[1] = rabbitPosition[1] + distanceY;
}
2024-02-15 01:15:55 +00:00
int main(void) {
2024-02-15 13:34:50 +00:00
FILE *fh;
2024-02-15 01:15:55 +00:00
int keepRunning = 1;
installKeyboardHandler();
2024-02-15 13:34:50 +00:00
initializeDrawBuffer();
fh = fopen("sprtsht.bmp", "rb");
if (readBMPIntoNewMemory(fh, &spritesheetImage)) return 1;
fclose(fh);
spritesheetImage.transparentColor = 0;
2024-02-16 02:18:15 +00:00
setupWallSprites();
setupRabbitSprites();
2024-02-15 13:34:50 +00:00
setVideoMode(VIDEO_MODE_VGA_256);
bmp256ColorPaletteToVGAColorPalette(&spritesheetImage, vgaColors);
setVGAColors(vgaColors, 256);
2024-02-15 01:15:55 +00:00
2024-02-20 11:48:12 +00:00
activateMouse(&mouseStatus);
2024-02-20 17:39:28 +00:00
limitMouseArea(0, 0, 199, 199);
2024-02-20 11:48:12 +00:00
2024-02-16 02:18:15 +00:00
buildArena();
2024-02-15 13:34:50 +00:00
2024-02-16 02:18:15 +00:00
while (keepRunning) {
readMouse(&mouseStatus);
populateKeyboardKeydownState();
handleRabbitMovement();
2024-02-20 13:00:13 +00:00
calculateTargetAngle();
2024-02-15 13:34:50 +00:00
2024-02-16 02:18:15 +00:00
drawOnlyRabbitArena();
2024-02-20 11:48:12 +00:00
drawOnlyMouseArena();
2024-02-16 02:18:15 +00:00
renderRabbit();
2024-02-20 11:48:12 +00:00
renderMouse();
2024-02-20 13:20:35 +00:00
waitStartVbl();
2024-02-15 13:34:50 +00:00
copyDrawBufferToDisplay();
2024-02-15 01:15:55 +00:00
2024-02-15 13:34:50 +00:00
waitEndVbl();
2024-02-16 02:18:15 +00:00
2024-02-20 17:39:28 +00:00
if (keyboardKeydownState.KEY_ESC) { keepRunning = 0; }
2024-02-15 01:15:55 +00:00
}
2024-02-16 02:18:15 +00:00
2024-02-15 01:15:55 +00:00
// states:
// * main menu
// * play
// * quit
// * play
// * draw base map
// * draw sidebar
// * Game loop
// * get mouse
// * get keyboard
// * set character position
// * check for enemy spawn and spawn enemy if needed
// * check for character firing and able to fire, spawn bullet if allowed
// * check for each enemy firing and able to fire, spawn enemy bullet if allowed
// * check for bullet collisions
// * enemies are destroyed
// * character is damaged
// * check for bullets hitting the edges of the screen and remove
// *
2024-02-15 13:34:50 +00:00
//
2024-02-16 02:18:15 +00:00
freeBMP(&spritesheetImage);
setVideoMode(VIDEO_MODE_80x25_TEXT);
uninstallKeyboardHandler();
fprintf(stderr, "meow\n");
2024-02-15 13:34:50 +00:00
return 0;
2024-02-15 01:15:55 +00:00
}