#include "world/course.h" #include "world/site.h" #define LANE 3.5f /* meters between the lanes */ typedef enum { LOG, BRANCH, FIREWOOD, CRATE, BENCH, COOLBOX, WALL, STUMP, BLOCK } Piece; typedef struct { Piece piece; float side, along; /* lane (-1 left, 0 middle, 1 right) and meters down the course */ Vec3 size; /* LOG: diameter; boxes: across, high, deep */ float kg; } Obstacle; static const Obstacle COURSE[] = { /* left: spaced out, getting higher */ { BRANCH, -1, 4.0f, { 0.0f, 0.9f, 0.0f }, 1.5f }, { FIREWOOD, -1, 8.0f, { 0.3f, 0.45f, 2.0f }, 0.0f }, { LOG, -1, 12.0f, { 0.20f, 0, 0 }, 0.0f }, { LOG, -1, 16.0f, { 0.30f, 0, 0 }, 0.0f }, { LOG, -1, 20.0f, { 0.42f, 0, 0 }, 0.0f }, { CRATE, -1, 24.0f, { 0.8f, 0.3f, 0.4f }, 12.0f }, { CRATE, -1, 28.0f, { 0.4f, 0.4f, 0.4f }, 6.0f }, /* the orange cube */ { CRATE, -1, 32.0f, { 0.6f, 0.45f, 0.45f }, 18.0f }, { CRATE, -1, 36.0f, { 0.8f, 0.6f, 0.6f }, 20.0f }, /* too high to step over */ /* middle: close together */ { LOG, 0, 4.0f, { 0.30f, 0, 0 }, 0.0f }, { LOG, 0, 5.0f, { 0.30f, 0, 0 }, 0.0f }, { LOG, 0, 6.2f, { 0.30f, 0, 0 }, 0.0f }, { LOG, 0, 7.6f, { 0.30f, 0, 0 }, 0.0f }, { LOG, 0, 9.2f, { 0.30f, 0, 0 }, 0.0f }, { LOG, 0, 12.0f, { 0.18f, 0, 0 }, 0.0f }, { LOG, 0, 12.7f, { 0.18f, 0, 0 }, 0.0f }, { LOG, 0, 13.4f, { 0.18f, 0, 0 }, 0.0f }, { CRATE, 0, 16.0f, { 0.8f, 0.3f, 0.4f }, 12.0f }, { CRATE, 0, 17.2f, { 0.8f, 0.3f, 0.4f }, 12.0f }, { LOG, 0, 18.4f, { 0.36f, 0, 0 }, 0.0f }, /* right: things that stay put */ { BENCH, 1, 4.0f, { 1.8f, 0.45f, 0.36f }, 0.0f }, { COOLBOX, 1, 8.0f, { 0.6f, 0.45f, 0.4f }, 0.0f }, { WALL, 1, 12.0f, { 2.0f, 0.35f, 0.25f }, 0.0f }, { STUMP, 1, 16.0f, { 0.45f, 0.35f, 0.0f }, 0.0f }, { BENCH, 1, 20.0f, { 1.8f, 0.45f, 0.36f }, 0.0f }, { WALL, 1, 21.2f, { 2.0f, 0.25f, 0.25f }, 0.0f }, { BLOCK, 1, 26.0f, { 1.2f, 0.6f, 0.8f }, 0.0f }, /* too high: step up / climb */ { BLOCK, 1, 32.0f, { 1.6f, 1.1f, 1.0f }, 0.0f }, /* climb */ }; #define COURSE_COUNT ((int)(sizeof(COURSE) / sizeof(COURSE[0]))) static float ground(const World *world, Vec3 p) { return Terrain_height(&world->terrain, p.x, p.z); } static Object *place(World *world, const Obstacle *o, Vec3 start, Vec3 along, Vec3 across) { Vec3 p = vec3_add(start, vec3_add(vec3_scale(along, o->along), vec3_scale(across, o->side * LANE))); p.y = ground(world, p); float yaw = atan2f(across.z, across.x); /* (its width runs across the lane) */ Object *obj = NULL; switch (o->piece) { case LOG: { obj = Object_create(OBJ_LOG, PALETTE_WARM, vec3_zero(), vec3(o->size.x, 1.6f, 0.0f), 0.0f); if (obj) Object_makeLog(obj, vec3_add(p, vec3(0.0f, o->size.x * 0.5f + 0.01f, 0.0f)), across, 1.6f, o->size.x); break; } case BRANCH: obj = Object_create(OBJ_BRANCH, PALETTE_WARM, vec3_add(p, vec3(0.0f, 0.15f, 0.0f)), o->size, o->kg); if (obj) Object_setRotation(obj, euler_yxz_from_axes(across, vec3(0.0f, 1.0f, 0.0f))); break; case FIREWOOD: obj = Object_create(OBJ_FIREWOOD, PALETTE_WARM, vec3_add(p, vec3(0.0f, 0.15f, 0.0f)), o->size, 0.0f); if (obj) Object_setRotation(obj, euler_yxz_from_axes(across, vec3(0.0f, 1.0f, 0.0f))); break; case CRATE: obj = Object_create(OBJ_BOX, o->kg <= 6.0f ? PALETTE_WARM : PALETTE_STANDARD, p, o->size, o->kg); break; case BENCH: obj = Object_createFurniture(FURN_BENCH, p, o->size, 0.0f); break; case COOLBOX: obj = Object_create(OBJ_SUPPLY, PALETTE_STANDARD, p, o->size, 0.0f); break; case WALL: case BLOCK: obj = Object_create(OBJ_BOX_STATIC, PALETTE_GROUND, p, o->size, 100.0f); break; case STUMP: obj = Object_create(OBJ_STUMP, PALETTE_WARM, vec3_add(p, vec3(0.0f, o->size.y * 0.5f, 0.0f)), o->size, 0.0f); break; } if (obj && o->piece != LOG && o->piece != BRANCH && o->piece != FIREWOOD && o->piece != STUMP) Object_setRotation(obj, vec3(0.0f, yaw, 0.0f)); /* (local x across: see mat4_rotate_y) */ return obj; } bool Course_build(World *world, Object *who, float *yaw) { Vec3 start, along; Site_courseFrame(&start, &along); Vec3 across = vec3(-along.z, 0.0f, along.x); for (int i = 0; i < COURSE_COUNT; i++) { Object *o = place(world, &COURSE[i], start, along, across); if (!o || !World_add(world, o)) return false; } if (!who) return true; /* At the start of the middle lane, looking down the course */ who->position = vec3(start.x, ground(world, start) + 0.05f, start.z); who->rotation.y = atan2f(along.z, along.x) + PI_F / 2.0f; Object_syncColliders(who); *yaw = atan2f(along.z, along.x); return true; }