1
1
Fork 0
Browse Source

code cleanup

master
alistair 2 years ago
parent
commit
dc7f5989f7
  1. 27
      src/audio.c
  2. 1
      src/c-colours
  3. 10
      src/controlscheme.c
  4. 1
      src/datastructures
  5. 107
      src/draw.c
  6. 39
      src/environment.c
  7. 300
      src/game.c
  8. 15
      src/main.c
  9. 10
      src/types.h

27
src/audio.c

@ -9,6 +9,19 @@ struct game_sounds game_sounds; @@ -9,6 +9,19 @@ struct game_sounds game_sounds;
Uint8 big_hum(unsigned int t);
Uint8 func0(unsigned int t);
/**
* ----------------------------------------------------------------------------
* Audio
* ----------------------------------------------------------------------------
*
* Sound-effects are generated at startup, and synthesised using 8-bit
* integer overflow a la bytebeat https://arxiv.org/pdf/1112.1368.pdf.
*
* see generate_audio()
*
*/
int mute = false;
void fill_audio(void *func, Uint8 *stream, int len) {
@ -30,14 +43,6 @@ void callbackfn3(void *unused, Uint8 *stream, int len) { @@ -30,14 +43,6 @@ void callbackfn3(void *unused, Uint8 *stream, int len) {
void start_audio(void) {
//audio_format.callback = callbackfn3;
/* just for playing background music
if (SDL_OpenAudio(&audio_format, NULL)) {
fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError());
exit(1);
}
*/
//SDL_PauseAudio(0);
if (Mix_OpenAudio(G_AUDIO_SFREQ,AUDIO_U8,1,G_AUDIO_BSIZE) < 0) {
fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError());
exit(1);
@ -71,7 +76,6 @@ pitchshift_hit(unsigned int t, void *arg) @@ -71,7 +76,6 @@ pitchshift_hit(unsigned int t, void *arg)
hit = 6 - hit;
int lower = 10 + 2 * (hit > 6 ? 6 : hit);
int higher = 1 + (hit > 6 ? 6 : hit);
// printf("mag %f higher %d lower %d\n", hit, higher, lower);
const double R=8000; // sample rate (samples per second)
const double C=125; // frequency of middle-C (hertz)
@ -81,8 +85,6 @@ pitchshift_hit(unsigned int t, void *arg) @@ -81,8 +85,6 @@ pitchshift_hit(unsigned int t, void *arg)
return ((sin(t*2*M_PI/R*(125 + hit))+1)*10 + (sin(t*2*M_PI/R*(250 + hit))+1)*(50 + hit) + (sin(t*2*M_PI/R*(900 + hit))+1)*100 + (sin(t*2*M_PI/R*(150+ hit))+1)*5) ;
return ((t < 3000) * ((t % higher) * (3000 - t % 3000) * 0.00351));
//+ ((t < 3500) * ((3500 - t % 3500)) * 0.0002 * (t % lower));
}
void
@ -196,6 +198,9 @@ Uint8 rope_attach(unsigned int t) { @@ -196,6 +198,9 @@ Uint8 rope_attach(unsigned int t) {
return (((2000 - (t % 2000)))/40 * (t % 20) | (t % 44) + 20) * 1.6;
}
/*
* Called by startgame() to initialise sound effects.
*/
void generate_audio(void) {
const int sfx_len_ms = 1000;
unsigned int sfx_len = (G_AUDIO_SFREQ/1000) * G_AUDIO_BSIZE * sfx_len_ms;

1
src/c-colours

@ -0,0 +1 @@ @@ -0,0 +1 @@
../c-colours

10
src/controlscheme.c

@ -9,6 +9,16 @@ struct InputMap input_map; @@ -9,6 +9,16 @@ struct InputMap input_map;
#define INPUT_MAP_VERSION 0
#define CONTROLS_FNAME "controls.bin"
/*
* Serialise controlscheme using simple (char *) cast. It is obviously not cross
* platform but it doesnt need to be. Takes a very tentative approach to error
* handling, if something is wrong it resets.
*
* There is no UI for setting controls yet.
*
*/
struct InputMap_Ser {
unsigned int id;
unsigned int ver;

1
src/datastructures

@ -0,0 +1 @@ @@ -0,0 +1 @@
../datastructures

107
src/draw.c

@ -27,20 +27,6 @@ void render_texture_at(struct SDL_Renderer * ren, struct SDL_Texture * texture,i @@ -27,20 +27,6 @@ void render_texture_at(struct SDL_Renderer * ren, struct SDL_Texture * texture,i
SDL_RenderCopy(ren, texture, NULL, &destination);
}
/*SDL_Texture * load_image(SDL_Renderer * ren, char fname[]) {*/
/*[> Load an image into a texture <]*/
/*SDL_Surface * surface = IMG_Load(fname) ;*/
/*if(!surface) {*/
/*printf("IMG_Load: %s\n", IMG_GetError());*/
/*// handle error*/
/*}*/
/*SDL_Texture * png_image = SDL_CreateTextureFromSurface(ren, surface);*/
/*cleanup(surface, SURFACE);*/
/*return (png_image);*/
/*}*/
double sigmoid(double x) {
return exp(x) / (exp(x) + 1);
@ -321,30 +307,6 @@ void new_update_viewport(Body const * const pl) { @@ -321,30 +307,6 @@ void new_update_viewport(Body const * const pl) {
if (recover)
viewport_pos = target;
// emergency
/*if (!(iv.x > width / 3 && iv.x < (2 * (width / 3)))) {*/
/*if (!(iv.y > height / 3 && iv.y < (2 * (height / 3)))) {*/
/*if ( true ||*/
/*( in_view(pl->position).x > xmargin + xrange */
/*|| in_view(pl->position).x < xmargin)*/
/*) */
/*{*/
/*double m = (width / 2) / (2.0 * x_max);*/
/*double x = m * v;*/
/*target.x = pl->position.x - x;*/
/*}*/
//target.y = pl->position.y - height/2; // + y;
/*}*/
/*}*/
double v = pl->vel.x;
if (v > x_max)
@ -452,15 +414,8 @@ void draw_environment(SDL_Renderer * ren, const struct environment *scene) { @@ -452,15 +414,8 @@ void draw_environment(SDL_Renderer * ren, const struct environment *scene) {
struct colour c3 = scene->colours.fg2;
struct colour c4 = scene->colours.fg3;
/*c1->r = 255;*/
/*c2->g = 255;*/
/*c3->b = 255;*/
/*c4->g = 255;*/
/*c4->b = 255;*/
// background colour
SDL_SetRenderDrawColor(ren, c1.r, c1.g, c1.b, 255);
/*SDL_SetRenderDrawColor(ren, 255, 0, 0, 255);*/
SDL_Rect rect;
rect.x = 0;
@ -469,20 +424,8 @@ void draw_environment(SDL_Renderer * ren, const struct environment *scene) { @@ -469,20 +424,8 @@ void draw_environment(SDL_Renderer * ren, const struct environment *scene) {
rect.h = height;
SDL_RenderFillRect(ren, &rect);
/*
* double m = (double)(right.y - left.y) / (double)(right.x - left.x);
* double c = (double)left.y - ((double)left.x * m);
*
* for (int i = left.x; i <= right.x; i++) {
* int y = (int)(m * i + c);
* if (y > 0) {
* SDL_RenderDrawLine(ren, i, y, i, end);
* }
* }
*/
int k = 0;
// printf("from 0 to (room tiles) %d - 1, res %d width %d\n", E_ROOM_TILES, E_ROOM_RES, E_ROOM_WIDTH);
for (int i = 0; i < E_ROOM_TILES - 2; i++) {
for (int j = 0; j < E_ROOM_RES; j++) {
k++;
@ -518,8 +461,6 @@ void draw_environment(SDL_Renderer * ren, const struct environment *scene) { @@ -518,8 +461,6 @@ void draw_environment(SDL_Renderer * ren, const struct environment *scene) {
int y3 = interpolate_h(*left, *right, x) - viewport_pos.y;
x = x - viewport_pos.x;
/*printf("x: %d, ", x);*/
/*printf("y: %d %d %d %d\n", y0, y1, y2, y3);*/
// 3. bg2 to floor
SDL_SetRenderDrawColor(ren, c4.r, c4.g, c4.b, 255);
@ -625,7 +566,6 @@ int draw_end_screen(SDL_Renderer *ren) { @@ -625,7 +566,6 @@ int draw_end_screen(SDL_Renderer *ren) {
int margin = height / 10;
// Vect position = {.x = width - width / 10, .y = height - margin};
long fastest = draw_watch.best_time;
@ -654,13 +594,6 @@ int draw_end_screen(SDL_Renderer *ren) { @@ -654,13 +594,6 @@ int draw_end_screen(SDL_Renderer *ren) {
position.y += 40;
}
/*
char qual_str[250];
snprintf(qual_str, 250, "physics quality: %d", quality);
draw_text_default(ren, position, colour, qual_str);
position.y += 40;
*/
minutes = level_time / 60000;
seconds = level_time * 0.001;
@ -763,7 +696,6 @@ void draw_pause_screen(SDL_Renderer *ren, struct environment *e) { @@ -763,7 +696,6 @@ void draw_pause_screen(SDL_Renderer *ren, struct environment *e) {
draw_text_default(ren, p, textc, te[0]);
p.y += 60;
// SDL_GetScancodeName(input_map.goto_level);
draw_text_default(ren, p, textc, te[1]);
p.y += 5;
draw_text_default(ren, p, textc, te[2]);
@ -791,7 +723,6 @@ void draw_pause_screen(SDL_Renderer *ren, struct environment *e) { @@ -791,7 +723,6 @@ void draw_pause_screen(SDL_Renderer *ren, struct environment *e) {
p.y += 40;
//Vect p = {.x = box_x + 10, .y = box_y + 10};
p.x = width / 8;
p.y = height / 9;
int arlen = sizeof(game_name) / sizeof(game_name[0]);
@ -810,14 +741,6 @@ void redraw_buffer(SDL_Renderer * ren) { @@ -810,14 +741,6 @@ void redraw_buffer(SDL_Renderer * ren) {
static SDL_Point *bgPixels[256];
static int numpixels[256];
/*if (!width && !height) {*/
/*for (int i = 0; i < 256; i++) {*/
/*bgPixels[i] = malloc(sizeof(SDL_Point) * width * height);*/
/*memset(bgPixels[i], 0, sizeof(SDL_Point) * width * height);*/
/*memset(numpixels, 0, (sizeof(int) * 256));*/
/*}*/
/*}*/
int col = 0;
Body lplayer;
@ -836,8 +759,6 @@ void redraw_buffer(SDL_Renderer * ren) { @@ -836,8 +759,6 @@ void redraw_buffer(SDL_Renderer * ren) {
last = now;
//SDL_GetMouseState(&newmousex, &newmousey);
const struct environment* scene = get_scene_watch();
draw_environment(ren, scene);
if (!game_paused)
@ -899,33 +820,5 @@ void redraw_buffer(SDL_Renderer * ren) { @@ -899,33 +820,5 @@ void redraw_buffer(SDL_Renderer * ren) {
draw_text(ren, LARGE, pos, scene->colours.fg1, "Press a Key to Continue");
}
/*if (newmousex != mousex || newmousey != mousey) {*/ /*mousey = newmousey;*/
/*mousex = newmousex;*/
/*for (int i = 0; i < 256; i++) {*/
/*memset(bgPixels[i], 0, sizeof(SDL_Point) * width * height);*/
/*memset(numpixels, 0, (sizeof(int) * 256));*/
/*}*/
/*for (int i=0; i < width; i++) {*/
/*for (int j = 0; j < height; j++) {*/
/*col = distance_colour(i, j, mousex, mousey, 10000);*/
/*SDL_Point *row = bgPixels[col];*/
/*SDL_Point point;*/
/*point.x = i;*/
/*point.y = j;*/
/*row[numpixels[col]] = point;*/
/*numpixels[col] += 1;*/
/*}*/
/*}*/
/*}*/
/*for (int i = 0; i < 255; i++) {*/
/*SDL_Point *row = bgPixels[i];*/
/*col = i;*/
/*SDL_SetRenderDrawColor(ren, col, col, col, 255);*/
/*SDL_RenderDrawPoints(ren, row, numpixels[i]);*/
/*}*/
}

39
src/environment.c

@ -2,8 +2,28 @@ @@ -2,8 +2,28 @@
#include "game.h"
#include "types.h"
struct environment * environment_watch = NULL;
/* ----------------------------------------------------------------------------
* Environment / World Generation
* ----------------------------------------------------------------------------
*
* Worlds have to be shared across threads, since they contain both collision
* bodies and drawing information. Realistically, these should be stored in
* separate datastructures. My solution has been to just store a copy in each
* thread, and lock everything when you move to the next level and need to
* generate a new one.
*
* An 'environment' consists of the cave structure with the collision bodies,
* as well as the colourscheme for drawing it. These are procedurally
* generated. A custom PRNG function is used so the same levels are given on
* every platform.
*
*/
const struct environment* get_scene_watch(void) {
return environment_watch;
}
@ -13,13 +33,6 @@ double linear_interpolate(double a0, double a1, double w) { @@ -13,13 +33,6 @@ double linear_interpolate(double a0, double a1, double w) {
}
int destroy_environment(struct environment *e) {
/*Vect position;*/
/*ArrayList ceil; // doubles*/
/*ArrayList floor; // doubles*/
/*ArrayList bg1; // doubles*/
/*ArrayList bg2; // doubles*/
/*struct colour_pallete colours;*/
/*struct physics_collection physics;*/
arlst_destroy(&e->ceil);
arlst_destroy(&e->floor);
@ -117,6 +130,11 @@ void swap_palletes(struct environment *e) { @@ -117,6 +130,11 @@ void swap_palletes(struct environment *e) {
e->coloursb = b;
}
/*
*
* Generate or just return the environment seeded by the current level number.
*
*/
struct environment get_scene_at(Vect coordinate, int seed) {
// TODO: Environment needs to be shared between threads
// - this implementation duplicates it: each thread that calls
@ -178,10 +196,7 @@ struct environment get_scene_at(Vect coordinate, int seed) { @@ -178,10 +196,7 @@ struct environment get_scene_at(Vect coordinate, int seed) {
int r[4] = {r1, r2, r3, r4};
qsort(r, 4, sizeof(int), comp);
// r[0] == ceiling
// r[3] == floor
//node.y += r[0];
int h[4] = {node.y,node.y,node.y,node.y};
h[0] += r[0];
h[1] = h[0] + r[1];
@ -189,7 +204,6 @@ struct environment get_scene_at(Vect coordinate, int seed) { @@ -189,7 +204,6 @@ struct environment get_scene_at(Vect coordinate, int seed) {
h[3] += h[0] + r[3];
qsort(h, 4, sizeof(int), comp);
// node.y = fmod(perlin(bit), 3000);
Vect *z = malloc(sizeof(Vect));
*z = node;
z->y = h[0];
@ -198,20 +212,17 @@ struct environment get_scene_at(Vect coordinate, int seed) { @@ -198,20 +212,17 @@ struct environment get_scene_at(Vect coordinate, int seed) {
z = malloc(sizeof(Vect));
*z = node;
// z->y += r[1];
z->y = h[1];
arlst_add(&e.bg1, z);
z = malloc(sizeof(Vect));
*z = node;
//z->y += r[2];
z->y = h[2];
arlst_add(&e.bg2, z);
z = malloc(sizeof(Vect));
*z = node;
// z->y += r[3];
z->y = h[3];
arlst_add(&e.ceil, z);

300
src/game.c

@ -1,14 +1,16 @@ @@ -1,14 +1,16 @@
#include "game.h"
#include "draw.h"
#include "audio.h"
#include "environment.h"
#include "types.h"
#include <SDL2/SDL_mixer.h>
#include <SDL2/SDL_scancode.h>
#include <SDL2/SDL_timer.h>
#include <SDL2/SDL_ttf.h>
#include <SDL2/SDL_mutex.h>
#include "game.h"
#include "draw.h"
#include "audio.h"
#include "environment.h"
#include "types.h"
#define FLOOR_THICKNESS 200
#define MAX_ROPE_GRAB_LEN 80000
#define MIN_PHYSICS_STEP 6.0
@ -23,6 +25,22 @@ player_st *glob_player; @@ -23,6 +25,22 @@ player_st *glob_player;
SDL_Renderer *debug_ren;
/*
*
* File containing main game logic, including physics, input handling,
* and user interface.
*
* If multithreading is in use everything in this file will be run in the
* physics thread and communicate with the drawing thread (the main thread)
* using shared heap memory.
*
* At the start of a frame the shared memory is locked
* and copied.
*
*
*/
bool in_game;
bool game_paused = false;
extern bool mute;
@ -44,9 +62,6 @@ struct ui_state gameui = {}; @@ -44,9 +62,6 @@ struct ui_state gameui = {};
struct timespec last_tick;
double time_remaining = 0;
/* array of all the things in the world and their kinds */
//world_thing *world;
void startgame(SDL_Renderer * ren) ;
void process_keydown(SDL_Keysym key);
@ -67,6 +82,12 @@ void ratcheted_winch_motor_update(Motor* motor); @@ -67,6 +82,12 @@ void ratcheted_winch_motor_update(Motor* motor);
void winch_motor_update (struct motorstruct *motor);
void load_level();
/* -----------------------------------------------------------------------------
* User interface
* -----------------------------------------------------------------------------
*/
void reset_textbox(struct textbox_info *tb) {
tb->text_input_bufpos = 0;
memset(tb->text_input, 0, sizeof(tb->text_input));
@ -111,6 +132,15 @@ void new_level_tb_close_callback(struct textbox_info*textbox, void*callback) { @@ -111,6 +132,15 @@ void new_level_tb_close_callback(struct textbox_info*textbox, void*callback) {
}
/* -----------------------------------------------------------------------------
* Scoring
* -----------------------------------------------------------------------------
*/
/*
* Update the level timer each frame.
*/
void level_timer_update(bool reset) {
static int start_point = 0;
long now = SDL_GetTicks();
@ -137,6 +167,9 @@ int win_long_comparator(void *context_unused, const void *a, const void *b) { @@ -137,6 +167,9 @@ int win_long_comparator(void *context_unused, const void *a, const void *b) {
return A - B;
}
/*
* Sort the 'highscores'
*/
void sort_times(void) {
#ifdef __linux__
qsort_r(save_times_lst.times, save_times_lst.size, sizeof(long), long_comparator, NULL);
@ -153,6 +186,12 @@ long get_best_time(void) { @@ -153,6 +186,12 @@ long get_best_time(void) {
}
/*
* Read and parse highschores list from disk.
*
* Will panic if the folder does not exist.
*
*/
int load_score_times(char *filename) {
char *fn;
@ -218,6 +257,11 @@ int load_score_times(char *filename) { @@ -218,6 +257,11 @@ int load_score_times(char *filename) {
return 0;
}
/*
*
* Dynamically add a recorded run time to the list of saved times.
*
*/
int add_time(long time) {
if (save_times_lst.capacity == save_times_lst.size + 5) {
long newcap = save_times_lst.capacity * 2;
@ -230,6 +274,9 @@ int add_time(long time) { @@ -230,6 +274,9 @@ int add_time(long time) {
return 0;
}
/*
* Write out the saved times list.
*/
int write_times(void) {
FILE *f = fopen(save_times_lst.filename, "w");
if (!f) {
@ -244,9 +291,38 @@ int write_times(void) { @@ -244,9 +291,38 @@ int write_times(void) {
}
/* ----------------------------------------------------------------------------
* Physics
* ----------------------------------------------------------------------------
*
* Simple point-mass based physics system. Physics objects are called `Body`s.
*
* Position is calculated by integrating acceleration and velocity, using a
* fixed timestep that is detached from the framerate. Each frame it completes
* as many physics steps as neccessary to catch up to the current time.
*
* Player interactions use forces generated by the 'motor'
* datastructures and functions. Motors can apply a force at a given 'rate':
* they accelerate a body to a maximum velocity and do nothing over that
* velocity. It is posisble to update their output at each physics step.
*
* The grappling hook is controlled by 'string' functions and datastructures,
* which have a parent object (the player) an attachment endpoint position, and
* a motor. Strings can be updated each physics step.
*
* All collisions use convex polygons and the separating axis theorem test.
* They are culled by x-coordinate based on the viewport position, since the
* world is mostly horizontal.
*
*/
// collision poly size must be 2x shape_size + 1
/*
* Update an objects collision poly based on its current position smeared over
* its velocity.
*/
void cast_update_collision_poly(Body *body) {
// collision poly size must be 2x shape_size + 1
for (int i=0; i < body->collision_shape_size; i++) {
double x = body->collision_shape[i].x + body->position.x;
double y = body->collision_shape[i].y + body->position.y;
@ -263,29 +339,31 @@ void cast_update_collision_poly(Body *body) { @@ -263,29 +339,31 @@ void cast_update_collision_poly(Body *body) {
body->collision_poly[k].y = y;
}
/*int i=body->collision_shape_size - 1;*/
/*double x = body->collision_shape[i].x + body->next_position.x;*/
/*double y = body->collision_shape[i].y + body->next_position.y;*/
/*body->collision_poly[body->collision_shape_size - 1 + i].x = x; */
/*body->collision_poly[body->collision_shape_size - 1 + i].y = y; */
/*body->collision_poly[(body->collision_poly_size - 1) * 2 + 1] = body->collision_poly[(body->collision_poly_size - 1) * 2 + 1];*/
/*body->collision_poly[(body->collision_poly_size - 1) * 2 + 2] = body->collision_poly[(body->collision_poly_size - 1)];*/
}
/*
* Constant motor velocity curve.
*/
void default_motor_curve(Motor *motor) {
// constant
return;
}
/*
* Get the i'th world item.
*/
world_thing world_getter(int i) {
world_thing *item = arlst_get(&world.items, i);
return *item;
}
/**
* Random walk to generate the floor based on compiled constant parameters.
*
* \param extend_down: do the polys extend down or up: true => floor, false => ceiling
*
*/
FloorPoly* generate_floor_simple(int num_polys, bool extend_down, int st_height) {
FloorPoly *floor = calloc(num_polys, sizeof(FloorPoly));
Vect last, next;
@ -333,8 +411,13 @@ FloorPoly* generate_floor_simple(int num_polys, bool extend_down, int st_height) @@ -333,8 +411,13 @@ FloorPoly* generate_floor_simple(int num_polys, bool extend_down, int st_height)
return floor;
}
// @param uninitialised Body pointer
// @result: malloc and configure a physics thing pointer
/**
* Get an empty valid physics object.
*
* \param uninitialised Body pointer
* \result: malloc and configure a physics thing pointer
*
*/
void get_new_physics(Body **phys) {
static int uid = 0;
@ -369,16 +452,19 @@ void get_new_physics(Body **phys) { @@ -369,16 +452,19 @@ void get_new_physics(Body **phys) {
return;
}
/*void updatePlayerCollision(Body *physics) {*/
/*physics->collision_poly[0].x = physics->x_pos;*/
/*physics->collision_poly[0].y = physics->y_pos;*/
/*}*/
/*
* noop for static strings.
*
*/
int string_update_fixed(String *string) {
return 0;
}
/*
* Attach the end point of s string to a position in the world.
*
*/
int string_set_end(String *string, Vect *setting) {
string->end_point = *setting;
return 0;
@ -399,8 +485,11 @@ String *get_fixed_strings(int number) { @@ -399,8 +485,11 @@ String *get_fixed_strings(int number) {
return strings;
}
/*
* Create a player object with allocated and zeroed physics at the given
* position in the world.
*/
player_st get_player(int x, int y) {
/* creates player at given postion and zeroes physics */
// player
player_st player;
@ -459,6 +548,9 @@ player_st get_player(int x, int y) { @@ -459,6 +548,9 @@ player_st get_player(int x, int y) {
return (player);
}
/*
* Collision test for two points.
*/
bool point_point_colcheck(Vect one, Vect two) {
if (one.x == two.x && one.y == two.y) {
return true;
@ -471,6 +563,9 @@ typedef struct { @@ -471,6 +563,9 @@ typedef struct {
Vect two;
} Collision;
/*
* Collision test for a point and line.
*/
bool point_line_colcheck(Vect line[2], Vect point) {
// point is outside the rectangle made by the line
if ((point.x > line[0].x && point.x > line[1].x)
@ -494,15 +589,17 @@ bool point_line_colcheck(Vect line[2], Vect point) { @@ -494,15 +589,17 @@ bool point_line_colcheck(Vect line[2], Vect point) {
return false;
}
/*
* Projects a body's collision polygon at the origin onto the line through the
* origin described by V.
*
*/
double *project_col_poly(Body *shape, Vect V) {
double *proj = calloc(shape->collision_poly_size, sizeof(double));
for (int i = 0; i < shape->collision_poly_size; i++) {
Vect point;
point.x = shape->collision_poly[i].x;
point.y = shape->collision_poly[i].y;
//double mag = vect_mag(point);
// printf("point: %f %f mag: %f\n", point.x, point.y, vect_mag(point));
// printf("Vectp: %f %f mag: %f\n", V.x, V.y, vect_mag(V));
proj[i] = vect_scalar_projection(point, V);
}
double min, max;
@ -524,6 +621,9 @@ double *project_col_poly(Body *shape, Vect V) { @@ -524,6 +621,9 @@ double *project_col_poly(Body *shape, Vect V) {
return res;
}
/*
* Get the normal of the line described by the start and end points.
*/
Vect get_normal(Vect start, Vect end) {
Vect norm;
double x = (end.x - start.x);
@ -537,13 +637,35 @@ Vect get_normal(Vect start, Vect end) { @@ -537,13 +637,35 @@ Vect get_normal(Vect start, Vect end) {
return norm;
}
/**
* Collision test for two convex polygons.
*
* Uses the separating axis theorem test.
*
* P: IFF two convex polygons are intersecting, there will exist a line running
* between them that intersects neither.
*
* Corrolary: IFF two convex polygons are intersecting, there will be an edge
* of one of them where if you extend it and project both shapes onto it, the
* shapes will overlap.
*
* Corrolary: Finding all these overlaps and taking the minimum gives the
* minimum vector to take the shapes out of intersection.
*
* \param one: first body
* \param two: second body
* \param translation: The minimum vector to take `one` and `two` out of intersection.
* \return: they are intersecting
*
*/
bool sat_collision_check(Body *one, Body *two, Vect *translation) {
// reference:
// http://www.dyn4j.org/2010/01/sat/#sat-inter
//
// TODO: Maybe avoid calculating the centre of the boxes; have body->position
// be the centre and translate the collision box to be around that. It does
// make placing a little more complex but no bother.
bool sat_collision_check(Body *one, Body *two, Vect *translation) {
int num_axes = one->collision_poly_size + two->collision_poly_size;
Vect *axes = calloc(num_axes, sizeof(Vect));
@ -637,17 +759,12 @@ bool sat_collision_check(Body *one, Body *two, Vect *translation) { @@ -637,17 +759,12 @@ bool sat_collision_check(Body *one, Body *two, Vect *translation) {
two_position.x /= two->collision_poly_size;
two_position.y /= two->collision_poly_size;
/*printf("ONE POS: %f %f", one_position.x, one_position.y);*/
/*printf("TWO POS: %f %f", two_position.x, one_position.y);*/
direction.x = one_position.x - two_position.x;
direction.y = one_position.y - two_position.y;
double dot = vect_scalar_projection(trans, direction);
/*printf("DIRECTION: %f %f\n\n", direction.x, direction.y);*/
/*printf("DOT: %f\n\n", dot);*/
if (dot > 0) {
trans = vect_scalar(trans, -1);
}
@ -662,6 +779,16 @@ bool sat_collision_check(Body *one, Body *two, Vect *translation) { @@ -662,6 +779,16 @@ bool sat_collision_check(Body *one, Body *two, Vect *translation) {
return true;
}
/*
* Check collision between two bodies using an appropriate scheme.
*
*
* \param one: first body
* \param two: second body
* \param translation: The minimum vector to take `one` and `two` out of intersection.
* \return: they are intersecting
*
*/
bool check_collision(Body *one, Body *two, Vect *translation) {
int onesize = one->collision_poly_size;
int twosize = two->collision_poly_size;
@ -766,7 +893,6 @@ void load_level() { @@ -766,7 +893,6 @@ void load_level() {
destroy_physics_collection(&world.uniques_index[ROOM_W]->room->ceil);
destroy_physics_collection(&world.uniques_index[ROOM_W]->room->floor);
//destroy_environment(&world.uniques_index[ROOM_W]->room->env);
get_floor_ceiling();
draw_watch.best_time = get_best_time();
@ -1263,7 +1389,10 @@ bool get_motor_active(Body *thing, int i) { @@ -1263,7 +1389,10 @@ bool get_motor_active(Body *thing, int i) {
return true;
}
/* Basic physics works by adding up the acceleratino caused by all the forces on
/*
* Update the physics state for a body.
*
* Basic physics works by adding up the acceleration caused by all the forces on
* the object, converting it to velocity, then doing collision detection and
* applying various reactive forces (friction etc) and finally adjusting the
* object's position.
@ -1288,11 +1417,6 @@ void advance_thing(Body * thing) { @@ -1288,11 +1417,6 @@ void advance_thing(Body * thing) {
// collisions
if ((numcols = process_collisions(thing, &translation))) {
/*double check = vect_scalar_projection(translation, thing->vel);*/
/*if (check >= 0) {*/
/*translation.x *= -1;*/
/*translation.y *= -1;*/
/*}*/
// correct position using translation vector.
thing->next_position.x += translation.x;
@ -1345,33 +1469,6 @@ void advance_thing(Body * thing) { @@ -1345,33 +1469,6 @@ void advance_thing(Body * thing) {
}
/*double norm = 9.81 * thing->obj_mass;*/
/*Vect x;*/
/*x.y = 0; x.x = 1;*/
/*if (vect_scalar_projection(thing->vel, translation) > 0) {*/
/*friction.x = translation.y;*/
/*friction.y = -translation.x;*/
/*} else {*/
/*friction.x = -translation.y;*/
/*friction.y = translation.x;*/
/*}*/
// force
/*friction.x = friction.x * norm * fric_const;*/
/*friction.y = friction.y * norm * fric_const;*/
// printf("friction accel: %e %e\n", friction.x, friction.y);
// printf("velocity: %e %e\n", thing->vel.x, thing->vel.y);
/*set_motor_newtons(thing, M_FRICTION, friction.x, friction.y);*/
/*set_motor_max_velocity(thing, M_FRICTION, vect_mag(project_vect(thing->vel, friction)));*/
// restitution force
/*rest.x = 0;*/
/*rest.y = 0;*/
/*double impulse = thing->obj_mass * vect_mag(thing->vel) * thing->obj_elasticity;*/
/*rest.x = cos(vect_dir(translation)) * impulse;*/
/*rest.y = sin(vect_dir(translation)) * impulse;*/
/*accel_thing(thing, rest.x, rest.y);*/
}
// pendulums
@ -1444,21 +1541,6 @@ void advance_thing(Body * thing) { @@ -1444,21 +1541,6 @@ void advance_thing(Body * thing) {
double velocity = sqrt((double)(thing->vel.x * thing->vel.x + thing->vel.y * thing->vel.y));
// simple air drag
/*if (velocity > 0.000000000000000) {*/
/*double dir = atan2((double)thing->y_vel, (double)thing->x_vel) + M_PI;*/
/*double absolute_force = 5 * thing->obj_mass * (velocity / time_delta); // 2 * 0.1231 * 5;*/
/*printf("dir %e %e\n\n", dir, dir - M_PI);*/
/*printf("force %e\n\n", absolute_force);*/
/*double f_x = (cos(dir)) * absolute_force;*/
/*double f_y = (sin(dir)) * absolute_force;*/
/*accel_thing(thing, (float)f_x, (float)f_y);*/
/*}*/
if (fabsl((*thing).vel.x) < 0.001) {
(*thing).vel.x = 0;
@ -1489,13 +1571,6 @@ void advance_thing(Body * thing) { @@ -1489,13 +1571,6 @@ void advance_thing(Body * thing) {
}
/*void destroy_projectile(Projectile** proj) {*/
/*for (int i = 0; i < things_in_world; i ++) {*/
/*if (world[i].projectile == *proj) {*/
/*}*/
/*}*/
/*}*/
void *default_projectile_step(struct Projectile *self) {
advance_thing(self->physics);
@ -1542,16 +1617,8 @@ void advance_things(void) { @@ -1542,16 +1617,8 @@ void advance_things(void) {
continue;
case FLOOR:
continue;
/*for (int k = 0; k < world.get(i).floor->numPolys; k++) {*/
/*advance_thing(world.get(i).floor->polys[k].physics);*/
/*}*/
/*break;*/
case CEILING:
continue;
/*for (int k = 0; k < world.get(i).floor->numPolys; k++) {*/
/*advance_thing(world.get(i).floor->polys[k].physics);*/
/*}*/
/*break;*/
case PROJECTILE:
if ((numcols = process_collisions(world.get(i).projectile->physics,
&translation))) {
@ -1619,8 +1686,6 @@ void get_room(void) { @@ -1619,8 +1686,6 @@ void get_room(void) {
FloorPoly *ceil = generate_floor_simple(floorsize, false, 1000);
// printf("floor: %f %f\n", polys[2].left.x, polys[2].left.y);
// printf("ceil: %f %f\n", ceil[2].left.x, ceil[2].left.y);
Floor* ceiling = calloc(1, sizeof(Floor));
ceiling->polys = ceil;
@ -1645,6 +1710,11 @@ GlobWorld create_world() { @@ -1645,6 +1710,11 @@ GlobWorld create_world() {
return c;
}
/*
*
* Run once, intialises the game.
*
*/
void startgame(SDL_Renderer * ren) {
load_fonts();
get_input_map();
@ -1663,8 +1733,6 @@ void startgame(SDL_Renderer * ren) { @@ -1663,8 +1733,6 @@ void startgame(SDL_Renderer * ren) {
SDL_GetRendererOutputSize(ren, &width, &height);
// player = get_player(200,1300);
get_floor_ceiling();
Vect stpos = *world.uniques_index[ROOM_W]->room->ceil.items[2]->collision_poly;
player = get_player(stpos.x, stpos.y - 15);
@ -1684,14 +1752,17 @@ void startgame(SDL_Renderer * ren) { @@ -1684,14 +1752,17 @@ void startgame(SDL_Renderer * ren) {
game_paused = 0;
viewport_pos.x = player.physics->position.x - width / 2;
viewport_pos.y = player.physics->position.y - height / 2;
//get_room();
}
double get_abs(double x,double y) {
return (sqrt(x*x + y*y));
}
/*
*
* Make a player walk along the ground. Only enabled in debug mode.
*
*/
void walk_player(int x, int y) {
set_motor_status(player.physics, M_PLAYER_WALK, true);
@ -1704,6 +1775,12 @@ void walk_player(int x, int y) { @@ -1704,6 +1775,12 @@ void walk_player(int x, int y) {
add_motor_newtons(glob_player->physics, M_PLAYER_WALK, 100 *5* x , 100 * 5 * y);
}
/*
*
* Handle non-window events pertaining to the game logic. Window events are
* handled in main. Bindings are defined in controlscheme.c.
*
*/
void handle_input_event(SDL_Event event) {
SDL_Scancode sc = event.key.keysym.scancode;
static bool mouse_down = false;
@ -1804,7 +1881,10 @@ void handle_input_event(SDL_Event event) { @@ -1804,7 +1881,10 @@ void handle_input_event(SDL_Event event) {
}
/* temporary storage variable *n should be initialised to 1 */
/*
* Basic PRNG for cross-platform consistency.
*
* temporary storage variable *n should be initialised to 1 */
int get_rand(int *n) {
const unsigned c = 11;
const unsigned m = (1 << 31) - 1;
@ -1816,11 +1896,15 @@ int get_rand(int *n) { @@ -1816,11 +1896,15 @@ int get_rand(int *n) {
}
/*
*
* Entry point for update step.
*
*/
int step(void) {
static int first_run = 0;
if (!first_run) {
start_audio();
// play_game_sound(game_sounds.background, -1, BC_MUSIC);
first_run = 1;
game_paused = 1;
}

15
src/main.c

@ -10,11 +10,12 @@ @@ -10,11 +10,12 @@
#include <time.h>
#include <stdbool.h>
#include <math.h>
#include "audio.h" // only for mkdirat lol
#include <stdbool.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "audio.h"
#include "game.h"
#include "draw.h"
#include "types.h"
@ -76,19 +77,19 @@ int physics_loop(void *ptr) { @@ -76,19 +77,19 @@ int physics_loop(void *ptr) {
int game(void) {
//SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "2" );
SDL_Window * win = make_window();
SDL_Renderer * ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
// | SDL_RENDERER_PRESENTVSYNC);
SDL_Renderer * ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED
#ifdef USE_VSYNC
| SDL_RENDERER_PRESENTVSYNC
#endif
);
SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND);
in_game = true;
resume = SDL_CreateSemaphore(0);
// IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG);
if (ren == NULL) {
SDL_DestroyWindow(win);
SDL_Quit();

10
src/types.h

@ -105,13 +105,6 @@ typedef struct BodyStruct{ @@ -105,13 +105,6 @@ typedef struct BodyStruct{
double obj_friction; // between 0 and 1 (fraction of lateral velocity
// that is removed)
//float x_vel;
//float y_vel;
//float x_acc;
//float y_acc;
/*------------------*/
// collisions
Vect *collision_poly;
Vect *collision_shape;
@ -123,7 +116,7 @@ typedef struct BodyStruct{ @@ -123,7 +116,7 @@ typedef struct BodyStruct{
double glob_friction;
bool glob_gravity; // t/f
// uint32_t last_advance_time;
// uint32_t last_advance_time;
struct timespec last_advance_time;
@ -228,7 +221,6 @@ typedef struct world GlobWorld; @@ -228,7 +221,6 @@ typedef struct world GlobWorld;
// environment
enum {
// E_ROOM_WIDTH = 100000,
E_ROOM_WIDTH = 10000,
E_ROOM_RES = 500,
E_ROOM_TILES = E_ROOM_WIDTH / E_ROOM_RES,

Loading…
Cancel
Save