add level conversion, loading, basic mechanics

This commit is contained in:
Lephenixnoir 2021-08-21 16:31:19 +02:00
parent 4f72a8f401
commit 96247fbcfa
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
10 changed files with 211 additions and 33 deletions

2
.gitignore vendored
View File

@ -5,7 +5,7 @@
/*.g3a
# Python bytecode
__pycache__/
__pycache__/
# Common IDE files
*.sublime-project

View File

@ -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})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -0,0 +1,3 @@
level*.txt:
custom-type: level
name_regex: level(.*)\.txt level\1

View File

@ -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

View File

@ -13,7 +13,7 @@ square right
middle
righet
right
left

68
converters.py Normal file
View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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;
}