Skip to content

Commit

Permalink
Added stuff!
Browse files Browse the repository at this point in the history
Shell physics, 11 levels, UI bits.
  • Loading branch information
commandblockguy committed Jun 27, 2018
1 parent e668ee9 commit 656da29
Show file tree
Hide file tree
Showing 27 changed files with 866 additions and 254 deletions.
2 changes: 2 additions & 0 deletions conversion.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
EMPTY, BLOCK, DESTRUCTIBLE, HOLE, DESTROYED
48, 32, 17, 2
Binary file added screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
87 changes: 63 additions & 24 deletions src/collision.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,38 +13,22 @@
#include "collision.h"
#include "level.h"

AABB getShellAABB(Shell* shell) {
AABB result;
result.x1 = shell->pos_x;
result.y1 = shell->pos_y;
result.x2 = result.x1 + SHELL_SIZE;
result.y2 = result.y1 + SHELL_SIZE;
return result;
}
#include <graphx.h>

AABB getMineAABB(Mine* mine) {
AABB getAABB(PhysicsBody* phys) {
AABB result;
result.x1 = mine->pos_x;
result.y1 = mine->pos_y;
result.x2 = result.x1 + MINE_SIZE;
result.y2 = result.y1 + MINE_SIZE;
return result;
}

AABB getTankAABB(Tank* tank) {
AABB result;
result.x1 = tank->pos_x;
result.y1 = tank->pos_y;
result.x2 = tank->pos_x + TANK_SIZE;
result.y2 = tank->pos_y + TANK_SIZE;
result.x1 = phys->position_x >> SHIFT_AMOUNT;
result.y1 = phys->position_y >> SHIFT_AMOUNT;
result.x2 = (phys->position_x >> SHIFT_AMOUNT) + phys->width;
result.y2 = (phys->position_y >> SHIFT_AMOUNT) + phys->height;
return result;
}

AABB getDetectionAABB(Mine* mine) {
AABB result;

uint24_t center_x = mine->pos_x + MINE_SIZE / 2;
uint24_t center_y = mine->pos_y + MINE_SIZE / 2;
uint24_t center_x = (mine->phys.position_x >> SHIFT_AMOUNT) + MINE_SIZE / 2;
uint24_t center_y = (mine->phys.position_y >> SHIFT_AMOUNT) + MINE_SIZE / 2;

result.x1 = center_x - MINE_DETECT_RANGE;
result.y1 = center_y - MINE_DETECT_RANGE;
Expand All @@ -63,6 +47,14 @@ AABB getBlockAABB(uint8_t x, uint8_t y) {
return result;
}

uint24_t center_x(AABB bb) {
return (bb.x1 + bb.x2) / 2;
}

uint8_t center_y(AABB bb) {
return (bb.y1 + bb.y2) / 2;
}

bool detectCollision(AABB bb1, AABB bb2) {
return
bb1.x1 < bb2.x2 &&
Expand All @@ -76,3 +68,50 @@ struct reflection getReflection(AABB bb1, AABB bb2) {
struct reflection value = {0};
return value;
}

bool center_distance(AABB bb1, AABB bb2) {
int24_t delta_x = center_x(bb1) - center_x(bb2);
int24_t delta_y = center_y(bb1) - center_y(bb2);
return sqrt(delta_x * delta_x + delta_y * delta_y);
}

struct reflection getTileReflect(PhysicsBody* state1, PhysicsBody* state2, bool respectHoles, uint8_t* tiles) {
struct reflection result = {false};
uint8_t initial_corners[] = {0,0,0,0};
uint8_t final_corners[] = {0,0,0,0};
AABB bb1 = getAABB(state1);
AABB bb2 = getAABB(state2);

int x, y;

//Loop through the 4 corners
for(x = 0; x < 2; x++) {
for(y = 0; y < 2; y++) {
uint24_t final_corner_x = (&bb2.x1)[x]; //I'm pretty sure this is poor practice.
uint8_t final_corner_y = (&bb2.y1)[y];
//The ID of the tile that the corner is occupying
uint8_t final_tile = tiles[pixelToXTile(final_corner_x) + LEVEL_SIZE_X * pixelToYTile(final_corner_y)];
//Check if we need to collide here
if(final_tile == BLOCK || final_tile == DESTRUCTIBLE || (respectHoles && final_tile == HOLE)) {
//We have collided
result.colliding = true;
//Determine direction by seeing which axis has changed tiles
//This means if it hits a corner it will always prefer to reflect on the X axis
//(don't tell anyone though)
if(pixelToXTile(final_corner_x) > pixelToXTile((&bb1.x1)[x])) {
result.dir = RIGHT;
} else if(pixelToXTile(final_corner_x) < pixelToXTile((&bb1.x1)[x])) {
result.dir = LEFT;
} else if(pixelToYTile(final_corner_y) > pixelToYTile((&bb1.y1)[y])) {
result.dir = DOWN;
} else if(pixelToYTile(final_corner_y) < pixelToYTile((&bb1.y1)[y])) {
result.dir = UP;
} else {
//This should be unreachable.
result.dir = 0;
}
}
}
}
return result;
}
48 changes: 37 additions & 11 deletions src/collision.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,23 @@
#include <stdlib.h>
#include <string.h>

#include "constants.h"

typedef enum {
UP,
DOWN,
LEFT,
RIGHT
UP = 1,
DOWN = 2,
LEFT = 4,
RIGHT = 8
} Direction;

enum {
TankPhysics,
ShellPhysics,
MinePhysics
};

typedef uint8_t PhysicsType;

struct reflection {
bool colliding;
uint8_t distance;
Expand All @@ -26,23 +36,39 @@ struct reflection {

typedef struct {
//Axis-aligned bounding box
uint16_t x1;
uint16_t x2;
uint24_t x1;
uint24_t x2;
uint8_t y1;
uint8_t y2;
} AABB;

AABB getTankAABB(Tank* tank); //Get the AABB of a tank
AABB getShellAABB(Shell* shell); //Get the AABB of a shell
AABB getMineAABB(Mine* mine); //Get the AABB of a mine
AABB getDetectionAABB(Mine* mine); //Get the AABB that a mine uses to detect enemy tanks. A seperate circular deterction radius will be used if the AABB detects a tank.
typedef struct {
PhysicsType type;
uint8_t rotation;
uint16_t position_x; //this is ufix, but gives compiler errors for some reason
uint16_t position_y;
float velocity_x;
float velocity_y;
uint8_t width;
uint8_t height;
uint32_t updateTime;
} PhysicsBody;

AABB getAABB(PhysicsBody* phys);
AABB getBlockAABB(uint8_t x, uint8_t y); //Get the AABB of a tile

uint24_t center_x(AABB bb); //Get the center coords of a AABB
uint8_t center_y(AABB bb);

//Determine if two bounding boxes are intersecting
bool detectCollision(AABB bb1, AABB bb2);

//Distance "into" one BB the other is.
//Determine if a collision occurs with the tilemap
struct reflection getTileReflect(PhysicsBody* state1, PhysicsBody* state2, bool respectHoles, uint8_t* tiles);

//This shouldn't need to handle cases where one bounding box is fully inside the other because of the low speed of bullets and tanks.
struct reflection getReflection(AABB bb1, AABB bb2);

bool center_distance(AABB bb1, AABB bb2);

#endif /* H_COLLISION */
48 changes: 48 additions & 0 deletions src/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <stdlib.h>
#include <string.h>

#include "level.h"

//Comment this out to stop the levels from being bundled with the program
#define CREATE_LEVEL_APPVAR

Expand All @@ -20,12 +22,22 @@
//Offset from sides of screen
#define MAP_OFFSET_X 16

//Size of the gameplay area in tiles
#define LEVEL_SIZE_X 22
#define LEVEL_SIZE_Y 17

//Pixel size of each square object
#define TILE_SIZE 13
#define TANK_SIZE 13
#define SHELL_SIZE 3
#define MINE_SIZE 13

//Shifted by 6 bits
typedef uint16_t ufix;
typedef int16_t fix;
#define SHIFT_AMOUNT 6
#define SHIFT_MASK ((1 << SHIFT_AMOUNT) - 1)

//Distance from center of tank new bullets appear
#define BARREL_LENGTH 5

Expand All @@ -41,13 +53,49 @@
#define MINE_COUNTDOWN 100
#define MINE_TRIGGERED 10

//Player action cooldown
#define SHOT_COOLDOWN 5
#define MINE_COOLDOWN 10

//TODO: Radius in pixels that enemy tanks will cause mines to explode
#define MINE_DETECT_RANGE 20
//TODO: Radius in pixels that the centers of objects must be inside to be blown up by mines
//I know this is inaccurate but mines are so rarely used it really doesn't matter
#define MINE_EXPLOSION_RADIUS 20

//TODO: rate at which things turn
#define PLAYER_BARREL_ROTATION 4
#define PLAYER_TREAD_ROTATION 0

//TODO: amount of time in milliseconds the mission start screen displays
#define MISSION_START_TIME 2000
//Font size
#define MISSION_NUMBER_TEXT 3
#define ENEMY_TANK_TEXT 2

#define BLACK 7
#define WHITE gfx_black

//Number and pixel size of subregions to be used in collision detection
#define COLLISION_SUBREGIONS_X 4
#define COLLISION_SUBREGIONS_Y 4
#define SUBREGION_SIZE_X (TILE_SIZE << SHIFT_AMOUNT) * LEVEL_SIZE_X / COLLISION_SUBREGIONS_X
#define SUBREGION_SIZE_Y (TILE_SIZE << SHIFT_AMOUNT) * LEVEL_SIZE_Y / COLLISION_SUBREGIONS_Y

#define ROT_UNITS_TO_RADIANS M_PI / 128

typedef struct {
Level level; //level currently being played
uint8_t mission; //The mission number, always displayed 1 higher than stored. Also used as an index for levels.
uint8_t lives; //Number of remaining tanks. This includes the tank that is currently in use, so a value of 1 means that the game will end the next time the tank is hit.
uint8_t kills; //Number of enemy tanks destroyed.
uint24_t timer; //Game time, probably used for physics stuff.
uint16_t cursor_x; //If I decide to implement a cursor mode, this will represent the position of the crosshairs on the screen.
uint8_t cursor_y; //Otherwise, this will be removed
uint24_t lastCycle; //Time the last physics cycle started
bool inProgress; //Whether a mission is in progress
uint8_t shotCooldown; //How many more ticks before we can fire another shot
uint8_t mineCooldown;
} Game;

#endif /* H_CONSTANTS */
123 changes: 123 additions & 0 deletions src/graphics.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <tice.h>

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <graphx.h>

#include "constants.h"
#include "objects.h"
//Hopefully we can remove this when we remove AABB rendering
//Hopefully we can now stop referring to myself in the plural
#include "collision.h"
#include "level.h"
#include "graphics.h"
#include "gfx/tiles_gfx.h"


void displayScores(void) {

}

void missionStart(uint8_t mission, uint8_t lives, uint8_t num_tanks) {
gfx_FillScreen(gfx_white);

gfx_SetColor(gfx_red);
//TODO: get proper values for this
gfx_FillRectangle_NoClip(0, 60, LCD_WIDTH, 80);

//Print mission number
gfx_SetTextScale(MISSION_NUMBER_TEXT, MISSION_NUMBER_TEXT);
gfx_SetTextFGColor(WHITE);
gfx_SetTextXY((LCD_WIDTH - 60 * MISSION_NUMBER_TEXT) / 2, 70);
gfx_PrintString("Mission ");
gfx_PrintUInt(mission + 1, 1 + (mission >= 9) + (mission >= 99));
gfx_SetTextScale(ENEMY_TANK_TEXT, ENEMY_TANK_TEXT);
gfx_SetTextXY((LCD_WIDTH - 97 * ENEMY_TANK_TEXT) / 2, 110);
gfx_PrintString("Enemy Tanks: ");
gfx_PrintUInt(num_tanks, 1);
gfx_SetTextXY((LCD_WIDTH - 8 * MISSION_NUMBER_TEXT) / 2, 150);
gfx_SetTextFGColor(BLACK); // Will be blue once I get pallettes working
gfx_PrintString("x ");
gfx_PrintUInt(lives, 1);
gfx_SetTextFGColor(BLACK);
gfx_SetTextScale(1, 1);
//Print number of tanks
//Print number of lives

gfx_BlitBuffer();

delay(MISSION_START_TIME);
}

void render(uint8_t* tiles, Level* level, Tank* tanks) {
int i = 0;
gfx_tilemap_t tilemap; //Tilemap config struct

tilemap.map = tiles;
tilemap.tiles = tileset_tiles;
tilemap.type_width = gfx_tile_no_pow2;
tilemap.type_height = gfx_tile_no_pow2;
tilemap.tile_height = TILE_SIZE;
tilemap.tile_width = TILE_SIZE;
tilemap.draw_height = LEVEL_SIZE_Y;
tilemap.draw_width = LEVEL_SIZE_X;
tilemap.height = LEVEL_SIZE_Y;
tilemap.width = LEVEL_SIZE_X;
tilemap.y_loc = 0;
tilemap.x_loc = MAP_OFFSET_X;

gfx_FillScreen(gfx_white);

//Render level tiles
gfx_Tilemap_NoClip(&tilemap, 0, 0);

for(i = 0; i < level->num_tanks; i++) {
//Render tanks
int j;
AABB bb;
Tank* tank = &tanks[i];
if(tank->alive) {
gfx_SetTextXY(tank->phys.position_x >> SHIFT_AMOUNT, tank->phys.position_y >> SHIFT_AMOUNT);
gfx_PrintUInt(tank->type, 1);
bb = getAABB(&tank->phys);
renderAABB(bb);
gfx_Line(center_x(bb), center_y(bb), center_x(bb) + tank->bullet_spawn_x, center_y(bb) + tank->bullet_spawn_y);
}

//draw shell hitboxes until I can get sprites
for(j = max_shells[tank->type] - 1; j >= 0; j--) {
Shell* shell = &tank->shells[j];
AABB bb;
if(!(shell->alive)) continue;
bb = getAABB(&shell->phys);
renderAABB(bb);
}
for(j = max_mines[tank->type] - 1; j >= 0; j--) {
Mine* mine = &tank->mines[j];
AABB bb;
if(!(mine->alive)) continue;
bb = getAABB(&mine->phys);
renderAABB(bb);
}
}

gfx_SetTextXY(0,0);
gfx_PrintUInt(timer_1_Counter / 32.768 , 4);

gfx_BlitBuffer();

while(!os_GetCSC);

}

void renderAABB(AABB bb) {
gfx_SetColor(7);
gfx_Rectangle(bb.x1, bb.y1, bb.x2 - bb.x1, bb.y2 - bb.y1);
gfx_SetPixel(center_x(bb), center_y(bb));
}
Loading

0 comments on commit 656da29

Please sign in to comment.