diff --git a/.gitignore b/.gitignore index 2c4f84b..be51d83 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ /*.g3a # Python bytecode - __pycache__/ +__pycache__/ # Common IDE files *.sublime-project diff --git a/CMakeLists.txt b/CMakeLists.txt index bca6ad8..207147b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,10 +15,16 @@ set(SOURCES src/physics.c ) set(ASSETS - assets-cg/example.png - # ... + assets-cg/level/level1.txt + assets-cg/level/level2.txt + assets-cg/level/level3.txt + assets-cg/level/level4.txt + assets-cg/level/level5.txt + assets-cg/level/level6.txt + assets-cg/level/level7.txt ) +fxconv_declare_converters(converters.py) fxconv_declare_assets(${ASSETS} WITH_METADATA) add_executable(addin ${SOURCES} ${ASSETS}) diff --git a/assets-cg/example.png b/assets-cg/example.png deleted file mode 100644 index 8826800..0000000 Binary files a/assets-cg/example.png and /dev/null differ diff --git a/assets-cg/level/fxconv-metadata.txt b/assets-cg/level/fxconv-metadata.txt new file mode 100644 index 0000000..ab3ecf1 --- /dev/null +++ b/assets-cg/level/fxconv-metadata.txt @@ -0,0 +1,3 @@ +level*.txt: + custom-type: level + name_regex: level(.*)\.txt level\1 diff --git a/assets-cg/level/level1.txt b/assets-cg/level/level1.txt index da03b28..fc7962f 100644 --- a/assets-cg/level/level1.txt +++ b/assets-cg/level/level1.txt @@ -1,5 +1,5 @@ #it's good to see you.\nStay close to me and don't touch anything. -long middle vertical +long_vertical middle left diff --git a/assets-cg/level/level5.txt b/assets-cg/level/level5.txt index 4332f9c..14d320d 100644 --- a/assets-cg/level/level5.txt +++ b/assets-cg/level/level5.txt @@ -13,7 +13,7 @@ square right middle -righet +right left diff --git a/converters.py b/converters.py new file mode 100644 index 0000000..31c858a --- /dev/null +++ b/converters.py @@ -0,0 +1,68 @@ +import fxconv + +def convert(input, output, params, target): + if params["custom-type"] == "level": + convert_level(input, output, params, target) + return 0 + else: + return 1 + +def convert_level(input, output, params, target): + with open(input, "r") as fp: + lines = fp.read().split("\n") + lines = [tempo.split(",") for tempo in lines if not tempo.startswith("#")] + + blocks = bytes() + block_count = 0 + + for (tempo, rects) in enumerate(lines): + for r in [r for r in rects if r]: + r = r.strip().split() + print(tempo, r) + shape, action, position = -1, 0, -1 + + # Shape + if "square" in r: + shape = 0 + if "small" in r: + shape = 2 + if "medium" in r: + shape = 3 + if "normal" in r: + shape = 4 + if "long" in r: + shape = 5 + if "huge" in r: + shape = 6 + if "long_vertical" in r: + shape = 7 + + # Action + + # Position + if "left" in r: + position = 0 + if "right" in r: + position = 1 + if "middle" in r: + position = 2 + + # Implicit rules + if shape < 0 and action == 0: + shape = 4 + + if shape < 0 or action < 0 or position < 0: + raise fxconv.FxconvError("Incomplete in '" + " ".join(r) + "'") + + blocks += fxconv.u32(tempo) + blocks += fxconv.u32(shape) + blocks += fxconv.u32(position) + blocks += fxconv.u32(action) + block_count += 1 + + o = fxconv.ObjectData() + o += fxconv.u32(0x40000000) # 2.0 as a float + o += fxconv.u32(block_count) + o += fxconv.ref(blocks) + + fxconv.elf(o, output, "_" + params["name"], **target) diff --git a/src/duet.h b/src/duet.h index 9ca207b..96cce48 100644 --- a/src/duet.h +++ b/src/duet.h @@ -14,12 +14,13 @@ //--- typedef enum { - Shape_Square = 0, - Shape_SmallBar = 2, - Shape_MediumBar = 3, - Shape_NormalBar = 4, - Shape_LongBar = 5, - Shape_HugeBar = 6, + Shape_Square = 0, + Shape_SmallBar = 2, + Shape_MediumBar = 3, + Shape_NormalBar = 4, + Shape_LongBar = 5, + Shape_HugeBar = 6, + Shape_LongVertical = 7, } shape_t; typedef enum { @@ -48,6 +49,7 @@ typedef struct { typedef struct { float tempo; + int block_count; rectmeta_t *blocks; } level_t; @@ -55,16 +57,18 @@ typedef struct { // Game //--- -#define PLAYER_X 55 -#define PLAYER_R 35 -#define PLAYER_SIZE 6 +#define PLAYER_X 60 +#define PLAYER_R 40 +#define PLAYER_SIZE 8 +#define CORRIDOR_SIZE 120 + +#define RECT_SPEED 60 /* px/tempo */ typedef struct { float w, h; /* px */ float x, y; /* px */ - float vx, vy; /* px/s */ float r; /* rad */ - float vr; /* rad/s */ + rectmeta_t const *meta; } rect_t; #define RECT_TABLE_SIZE 20 @@ -73,6 +77,7 @@ typedef struct game { int dead; float time; level_t *level; + rectmeta_t const *current; rect_t table[RECT_TABLE_SIZE]; int cursor; @@ -99,4 +104,21 @@ void player_position(float angle, float *x1, float *y1, float *x2, float *y2); bool player_collision(game_t const *game); + bool rect_circle_collide(rect_t const *r, int cx, int cy, int cr); + +void rect_load(rect_t *r, rectmeta_t const *meta); + +void rect_physics(rect_t *r, rectmeta_t const *meta, float time); + +//--- +// Levels +//--- + +extern level_t level1; +extern level_t level2; +extern level_t level3; +extern level_t level4; +extern level_t level5; +extern level_t level6; +extern level_t level7; diff --git a/src/main.c b/src/main.c index c9e3401..bbfec07 100644 --- a/src/main.c +++ b/src/main.c @@ -44,13 +44,9 @@ int main(void) __printf_enable_fp(); memset(&game, 0x00, sizeof game); - game.level = &level0; - - /* Temporary level */ - game.table[0] = (rect_t){ - .w=80, .h=20, .x=440, .y=50, .vx=-100, .vy=0, .r=0, .vr=0.5 - }; - game.cursor = 1; + game.level = &level3; + game.current = game.level->blocks; + game.time = -5.0; timer = timer_configure(TIMER_ANY, 33000, GINT_CALL_SET(&need_frame)); timer_start(timer); @@ -61,8 +57,8 @@ int main(void) while (need_frame == 0) sleep(); need_frame = 0; - dt = (1.0 / 30) * level0.tempo; - game.time += 1.0 / 30; + dt = (1.0 / 30) * game.level->tempo; + game.time += dt; /* Input analysis */ @@ -81,7 +77,31 @@ int main(void) } /* Level generation */ - /* TODO */ + + // Remove rectangles that have passed their lifetime by 2 seconds + for(int i = 0; i < game.cursor;) { + if(game.time > game.table[i].meta->time + 2) + game.table[i] = game.table[--game.cursor]; + else + i++; + } + + // Find rectangles that need to be loaded + rectmeta_t const *meta = game.current; + while(meta < game.level->blocks + game.level->block_count) { + if(meta - game.current > RECT_TABLE_SIZE - game.cursor) + break; /* oops, not enough array space left */ + if(meta->time - 10 > game.time) + break; + meta++; + } + + // Load everything up to meta + while(game.current < meta) { + rect_t *r = &game.table[game.cursor++]; + r->meta = game.current++; + rect_load(r, r->meta); + } /* Physics */ @@ -89,22 +109,19 @@ int main(void) // break; for(int i = 0; i < game.cursor; i++) { - rect_t *r = &game.table[i]; - r->x += r->vx * dt; - r->y += r->vy * dt; - r->r += r->vr * dt; + rect_physics(&game.table[i], game.table[i].meta, game.time); } if(rotate_left) - game.player_rota += M_PI * dt; + game.player_rota += 2.1 * dt; if(rotate_right) - game.player_rota -= M_PI * dt; + game.player_rota -= 2.1 * dt; /* Rendering */ dclear(player_collision(&game) ? C_RED : C_BLACK); dprint(0, 0, C_WHITE, "game time: %.2fs", game.time); - dprint(0, 11, C_WHITE, "player rota: %.2f rad", game.player_rota); + dprint(0, 11, C_WHITE, "rectangles loaded: %d", game.cursor); for(int i = 0; i < game.cursor; i++) drectoid(&game.table[i], C_WHITE); diff --git a/src/physics.c b/src/physics.c index 4614e09..a003dec 100644 --- a/src/physics.c +++ b/src/physics.c @@ -50,5 +50,67 @@ bool rect_circle_collide(rect_t const *r, int cx0, int cy0, int cr) if(cly > r->h/2) cly = r->h/2; /* Determine whether that point is in the circle */ + return (clx - cx) * (clx - cx) + (cly - cy) * (cly - cy) <= cr * cr; } + +void rect_load(rect_t *r, rectmeta_t const *meta) +{ + r->w = 0; + r->h = 0; + + switch(meta->shape) { + case Shape_Square: + r->w = 0.4; + r->h = 0.5; + break; + case Shape_SmallBar: + r->w = 0.2; + r->h = 0.5; + break; + case Shape_MediumBar: + r->w = 0.2; + r->h = 0.65; + break; + case Shape_NormalBar: + r->w = 0.2; + r->h = 1.0; + break; + case Shape_LongBar: + r->w = 0.2; + r->h = 1.15; + break; + case Shape_HugeBar: + r->w = 0.2; + r->h = 1.5; + break; + case Shape_LongVertical: + r->w = 0.8; + r->h = 0.2; + break; + } + + r->w *= 2 * PLAYER_R; + r->h *= 2 * PLAYER_R; + + switch(meta->position) { + case Position_Left: + r->y = DHEIGHT/2 - CORRIDOR_SIZE/2 + r->w/2; + break; + case Position_Right: + r->y = DHEIGHT/2 + CORRIDOR_SIZE/2 - r->w/2; + break; + case Position_Middle: + r->y = DHEIGHT/2; + break; + } +} + +void rect_physics(rect_t *r, rectmeta_t const *meta, float absolute_time) +{ + // TODO: Use position and actions + float time = absolute_time - meta->time; /* <= 0 most of the time */ + + r->x = PLAYER_X - RECT_SPEED * time; + r->r = 0; +}