Implented collision detection, now fully working
This commit is contained in:
272
src/game.c
272
src/game.c
@@ -20,10 +20,172 @@ void game_init(game_t* game) {
|
|||||||
game->state=prestart;
|
game->state=prestart;
|
||||||
game->ticks_per_pixel = SPEED_DEFAULT;
|
game->ticks_per_pixel = SPEED_DEFAULT;
|
||||||
game->ticks_leftover =0;
|
game->ticks_leftover =0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool game_check_line_collision(player_t* player, point_t start, point_t end, uint8_t pixels){
|
||||||
|
|
||||||
void game_step(game_t* game, uint64_t deltaTime) {
|
bool line_is_horizontal = (start.y == end.y);
|
||||||
|
bool player_is_horizontal = (player->direction == left || player->direction == right);
|
||||||
|
|
||||||
|
if(line_is_horizontal == player_is_horizontal){ // if player moves parallel to the line, there is no point in checking
|
||||||
|
return false; // no collision possible because parallel moving
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!player_is_horizontal && (player->position.x < min(start.x, end.x) || player->position.x > max(start.x, end.x))){
|
||||||
|
return false; // if player is passing by horizontally, no collision possible
|
||||||
|
}
|
||||||
|
|
||||||
|
if(player_is_horizontal && (player->position.y < min(start.y, end.y) || player->position.y > max(start.y, end.y))){
|
||||||
|
return false; // if player is passing by vertically, no collision possible
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(player->direction){
|
||||||
|
case up:
|
||||||
|
if(player->position.y > start.y && ((int16_t)player->position.y - pixels) <= start.y) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case down:
|
||||||
|
if(player->position.y < start.y && ((int16_t)player->position.y + pixels) >= start.y) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case left:
|
||||||
|
if(player->position.x > start.x && ((int16_t)player->position.x - pixels) <= start.x) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case right:
|
||||||
|
if(player->position.x < start.x && ((int16_t)player->position.x + pixels) >= start.x) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool game_player_check_collision(game_t* game, player_t* player, uint8_t pixels){
|
||||||
|
|
||||||
|
// Check bounding collision
|
||||||
|
switch(player->direction){
|
||||||
|
case up:
|
||||||
|
if((int16_t)(player->position.y) - pixels <= TFT_GAME_FIELD_TOP){
|
||||||
|
return true; // Collision at top
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case down:
|
||||||
|
if((int16_t)(player->position.y) + pixels >= (TFT_HEIGHT - TFT_GAME_FIELD_BOTTOM - 1)){
|
||||||
|
return true; // Collision at bottom
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case left:
|
||||||
|
if((int16_t)(player->position.x) - pixels <= TFT_GAME_FIELD_LEFT){
|
||||||
|
return true; // Collision at left
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case right:
|
||||||
|
if((int16_t)(player->position.x) + pixels >= (TFT_WIDTH - TFT_GAME_FIELD_RIGHT - 1)){
|
||||||
|
return true; // Collision at right
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check collision with players (including self)
|
||||||
|
for(int i = 0; i < PLAYER_COUNT; i++){
|
||||||
|
|
||||||
|
player_t* colliding = &(game->player[i]); // pointer to player whose lines we want to check (against opponent or self)
|
||||||
|
point_t last_point = colliding->past_positions[0]; // start point of the line
|
||||||
|
|
||||||
|
// For each line segment (last_point to curr_point)
|
||||||
|
for(int j = 1; j < colliding->num_positions; j++ ){
|
||||||
|
point_t curr_point = colliding->past_positions[j]; // end point of the line
|
||||||
|
|
||||||
|
if(game_check_line_collision(player, last_point, curr_point, pixels)){ // check if player collides with line segment
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_point = curr_point; // set new start point
|
||||||
|
}
|
||||||
|
|
||||||
|
if( player != colliding && // do not check against yourself
|
||||||
|
game_check_line_collision(player, last_point, colliding->position, pixels)){ // check if player collides with newest segment of opponent
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // no collision!
|
||||||
|
}
|
||||||
|
|
||||||
|
void game_player_update(game_t* game, player_t* player, uint8_t pixels){
|
||||||
|
|
||||||
|
bool directionChange = false;
|
||||||
|
|
||||||
|
// Check for button presses
|
||||||
|
if(io_button_has_edge(player->btn_left)) {
|
||||||
|
player->direction= (player->direction + (4 - 1)) % 4 ; // "decrement enum value"
|
||||||
|
directionChange = true;
|
||||||
|
} else if(io_button_has_edge(player->btn_right)) {
|
||||||
|
player->direction= (player->direction + 1) % 4 ; // "increment enum value"
|
||||||
|
directionChange = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if player is alive
|
||||||
|
if(player->state != alive){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Change direction
|
||||||
|
if(directionChange) {
|
||||||
|
player_append_position(player,player->position);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pixels) {
|
||||||
|
|
||||||
|
// Check if a collision is about to happen
|
||||||
|
if(game_player_check_collision(game, player, pixels)){
|
||||||
|
player->state=dead;
|
||||||
|
}
|
||||||
|
|
||||||
|
point_t last_point = player->past_positions[player->num_positions-1];
|
||||||
|
|
||||||
|
switch(player->direction) {
|
||||||
|
case down:
|
||||||
|
player->position.y+=pixels;
|
||||||
|
LCD_DrawRectF( player->position.x,
|
||||||
|
last_point.y,
|
||||||
|
PLAYER_WIDTH,
|
||||||
|
player->position.y - last_point.y,
|
||||||
|
player->color);
|
||||||
|
break;
|
||||||
|
case left:
|
||||||
|
player->position.x-=pixels;
|
||||||
|
LCD_DrawRectF( player->position.x,
|
||||||
|
player->position.y,
|
||||||
|
last_point.x -player->position.x,
|
||||||
|
PLAYER_WIDTH,
|
||||||
|
player->color);
|
||||||
|
break;
|
||||||
|
case up:
|
||||||
|
player->position.y-=pixels;
|
||||||
|
LCD_DrawRectF( player->position.x,
|
||||||
|
player->position.y,
|
||||||
|
PLAYER_WIDTH,
|
||||||
|
last_point.y - player->position.y,
|
||||||
|
player->color);
|
||||||
|
break;
|
||||||
|
case right:
|
||||||
|
player->position.x+=pixels;
|
||||||
|
LCD_DrawRectF( last_point.x,
|
||||||
|
player->position.y,
|
||||||
|
player->position.x - last_point.x,
|
||||||
|
PLAYER_WIDTH,
|
||||||
|
player->color);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool game_step(game_t* game, uint64_t deltaTime) {
|
||||||
static long l = 0;
|
static long l = 0;
|
||||||
switch(game->state) {
|
switch(game->state) {
|
||||||
case prestart:
|
case prestart:
|
||||||
@@ -37,85 +199,71 @@ void game_step(game_t* game, uint64_t deltaTime) {
|
|||||||
//wait on game accept response
|
//wait on game accept response
|
||||||
|
|
||||||
//setup
|
//setup
|
||||||
//void player_init(player_t* player, uint8_t btn_left, uint8_t btn_right, point_t pos, uint16_t color, direction_t direction);
|
player_init(&(game->player[0]),
|
||||||
player_init(&(game->player[0]), BTN_PLAYER_1_LEFT, BTN_PLAYER_1_RIGHT, (point_t){.x=10,.y=120}, GUI_COLOR_BLUE, right);
|
BTN_PLAYER_1_LEFT,
|
||||||
player_init(&(game->player[1]), BTN_PLAYER_2_LEFT, BTN_PLAYER_2_RIGHT, (point_t){.x=230,.y=120}, GUI_COLOR_RED, left);
|
BTN_PLAYER_1_RIGHT,
|
||||||
|
(point_t){
|
||||||
|
.x=(TFT_GAME_FIELD_START_OFFSET + TFT_GAME_FIELD_LEFT),
|
||||||
|
.y=(((TFT_HEIGHT - TFT_GAME_FIELD_TOP - TFT_GAME_FIELD_BOTTOM) / 2) + TFT_GAME_FIELD_TOP)
|
||||||
|
},
|
||||||
|
GUI_COLOR_BLUE,
|
||||||
|
right);
|
||||||
|
|
||||||
|
player_init(&(game->player[1]),
|
||||||
|
BTN_PLAYER_2_LEFT,
|
||||||
|
BTN_PLAYER_2_RIGHT,
|
||||||
|
(point_t){
|
||||||
|
.x=(TFT_WIDTH - 1 - TFT_GAME_FIELD_RIGHT - TFT_GAME_FIELD_START_OFFSET),
|
||||||
|
.y=(((TFT_HEIGHT - TFT_GAME_FIELD_TOP - TFT_GAME_FIELD_BOTTOM) / 2) + TFT_GAME_FIELD_TOP)
|
||||||
|
},
|
||||||
|
GUI_COLOR_RED,
|
||||||
|
left);
|
||||||
|
|
||||||
//switch state
|
//switch state
|
||||||
game->state = running;
|
game->state = running;
|
||||||
|
|
||||||
LCD_Clear(GUI_COLOR_BLACK);
|
LCD_Clear(GUI_COLOR_BLACK);
|
||||||
break;
|
LCD_DrawRect(TFT_GAME_FIELD_LEFT,
|
||||||
|
TFT_GAME_FIELD_TOP,
|
||||||
|
(TFT_WIDTH - TFT_GAME_FIELD_LEFT - TFT_GAME_FIELD_RIGHT - 1),
|
||||||
|
(TFT_HEIGHT - TFT_GAME_FIELD_TOP - TFT_GAME_FIELD_BOTTOM - 1),
|
||||||
|
GUI_COLOR_WHITE);
|
||||||
|
return true;
|
||||||
|
|
||||||
case running:
|
case running:
|
||||||
{
|
{
|
||||||
uint16_t ticks;
|
uint16_t ticks;
|
||||||
uint16_t pixels = 0;
|
uint16_t pixels = 0;
|
||||||
|
|
||||||
if(deltaTime) {
|
if(deltaTime) {
|
||||||
|
|
||||||
ticks = game->ticks_leftover + deltaTime;
|
ticks = game->ticks_leftover + deltaTime;
|
||||||
pixels = ticks / game->ticks_per_pixel;
|
pixels = ticks / game->ticks_per_pixel;
|
||||||
|
|
||||||
game->ticks_leftover = ticks % game->ticks_per_pixel;
|
game->ticks_leftover = ticks % game->ticks_per_pixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For each player do ...
|
||||||
|
bool all_players_dead = true;
|
||||||
for(int i = 0; i < PLAYER_COUNT; i++) {
|
for(int i = 0; i < PLAYER_COUNT; i++) {
|
||||||
|
player_t* player = &(game->player[i]);
|
||||||
|
game_player_update(game, player, pixels);
|
||||||
|
if(player->state!=dead) {
|
||||||
|
all_players_dead=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool directionChange = false;
|
if(all_players_dead) {
|
||||||
player_t* player = &(game->player[i]);
|
game->state=ended;
|
||||||
|
LCD_Clear(GUI_COLOR_BLACK);
|
||||||
if(io_button_has_edge(player->btn_left)) {
|
return true;
|
||||||
player->direction= (player->direction + (4 - 1)) % 4 ; // "decrement enum value"
|
} else {
|
||||||
directionChange = true;
|
return false;
|
||||||
} else if(io_button_has_edge(player->btn_right)) {
|
}
|
||||||
player->direction= (player->direction + 1) % 4 ; // "increment enum value"
|
|
||||||
directionChange = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(directionChange) {
|
|
||||||
player_append_position(player,player->position);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pixels) {
|
|
||||||
point_t last_point = player->past_positions[player->num_positions-1];
|
|
||||||
switch(player->direction) {
|
|
||||||
case down:
|
|
||||||
player->position.y+=pixels;
|
|
||||||
LCD_DrawRectF( player->position.x,
|
|
||||||
last_point.y,
|
|
||||||
PLAYER_WIDTH,
|
|
||||||
player->position.y - last_point.y,
|
|
||||||
player->color);
|
|
||||||
break;
|
|
||||||
case left:
|
|
||||||
player->position.x-=pixels;
|
|
||||||
LCD_DrawRectF( player->position.x,
|
|
||||||
player->position.y,
|
|
||||||
last_point.x -player->position.x,
|
|
||||||
PLAYER_WIDTH,
|
|
||||||
player->color);
|
|
||||||
break;
|
|
||||||
case up:
|
|
||||||
player->position.y-=pixels;
|
|
||||||
LCD_DrawRectF( player->position.x,
|
|
||||||
player->position.y,
|
|
||||||
PLAYER_WIDTH,
|
|
||||||
last_point.y - player->position.y,
|
|
||||||
player->color);
|
|
||||||
break;
|
|
||||||
case right:
|
|
||||||
player->position.x+=pixels;
|
|
||||||
LCD_DrawRectF( last_point.x,
|
|
||||||
player->position.y,
|
|
||||||
player->position.x - last_point.x,
|
|
||||||
PLAYER_WIDTH,
|
|
||||||
player->color);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ended:
|
||||||
|
|
||||||
|
game->state= prestart;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
23
src/game.h
23
src/game.h
@@ -3,13 +3,14 @@
|
|||||||
|
|
||||||
#include<stdint.h>
|
#include<stdint.h>
|
||||||
#include<stdlib.h>
|
#include<stdlib.h>
|
||||||
|
#include<stdbool.h>
|
||||||
#include"player.h"
|
#include"player.h"
|
||||||
|
|
||||||
#define PLAYER_COUNT 2
|
#define PLAYER_COUNT 2
|
||||||
#define PLAYER_WIDTH 0 // Don't change
|
#define PLAYER_WIDTH 0 // Don't change
|
||||||
#define SPEED_SLOW 10
|
#define SPEED_SLOW 10
|
||||||
#define SPEED_FAST 1
|
#define SPEED_FAST 1
|
||||||
#define SPEED_DEFAULT (SPEED_SLOW)
|
#define SPEED_DEFAULT (SPEED_FAST)
|
||||||
|
|
||||||
#define BTN_START 0
|
#define BTN_START 0
|
||||||
#define BTN_PLAYER_1_LEFT 3
|
#define BTN_PLAYER_1_LEFT 3
|
||||||
@@ -17,6 +18,12 @@
|
|||||||
#define BTN_PLAYER_2_LEFT 1
|
#define BTN_PLAYER_2_LEFT 1
|
||||||
#define BTN_PLAYER_2_RIGHT 0
|
#define BTN_PLAYER_2_RIGHT 0
|
||||||
|
|
||||||
|
#define TFT_GAME_FIELD_TOP 20
|
||||||
|
#define TFT_GAME_FIELD_BOTTOM 5
|
||||||
|
#define TFT_GAME_FIELD_LEFT 5
|
||||||
|
#define TFT_GAME_FIELD_RIGHT 5
|
||||||
|
#define TFT_GAME_FIELD_START_OFFSET 10
|
||||||
|
|
||||||
typedef struct game_s{
|
typedef struct game_s{
|
||||||
//public section
|
//public section
|
||||||
|
|
||||||
@@ -35,7 +42,19 @@ typedef struct game_s{
|
|||||||
uint8_t ticks_leftover;
|
uint8_t ticks_leftover;
|
||||||
} game_t;
|
} game_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Initializes the game object
|
||||||
|
@param game
|
||||||
|
*/
|
||||||
void game_init(game_t* game);
|
void game_init(game_t* game);
|
||||||
void game_step(game_t* game, uint64_t deltaTime);
|
|
||||||
|
/**
|
||||||
|
@brief Calculates one step of the game
|
||||||
|
@param game Game to calculate a step for
|
||||||
|
@param deltaTime Time that passed since the last call to this method (in ticks)
|
||||||
|
@return true if the next call to this method should be made with a delta time of zero.
|
||||||
|
|
||||||
|
*/
|
||||||
|
bool game_step(game_t* game, uint64_t deltaTime);
|
||||||
|
|
||||||
#endif /* GAME_H */
|
#endif /* GAME_H */
|
||||||
|
|||||||
@@ -53,8 +53,11 @@ int main(void)
|
|||||||
game_init(&gameobj);
|
game_init(&gameobj);
|
||||||
while(1) {
|
while(1) {
|
||||||
uint64_t curTicks = ticks;
|
uint64_t curTicks = ticks;
|
||||||
game_step(&gameobj,curTicks-lastTicks); //calculate next game step, and pass it the delta time
|
if(game_step(&gameobj,curTicks-lastTicks)) { //calculate next game step, and pass it the delta time
|
||||||
lastTicks = curTicks;
|
lastTicks = ticks;
|
||||||
|
} else {
|
||||||
|
lastTicks = curTicks;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user