sanctuary tweaks
This commit is contained in:
Binary file not shown.
Binary file not shown.
335
src/main.cpp
335
src/main.cpp
@@ -2026,6 +2026,33 @@ public:
|
||||
"normal":[0,1,0],"offset":0,"static":true
|
||||
})"));
|
||||
|
||||
// --- Perimeter physics borders: static stone walls ringing the
|
||||
// 160×160 map (X,Z in [-80,80]) so the player and dynamic props
|
||||
// can't leave the play area. Pink-tinted marble blends with the
|
||||
// sakura quadrant and reads as neutral stone against the others.
|
||||
{
|
||||
const float kBL = 162.0f; // wall length (slight corner overlap)
|
||||
const float kBH = 4.0f; // wall height (above jump apex)
|
||||
const float kBT = 1.0f; // wall thickness
|
||||
const glm::vec3 kBC(0.95f, 0.82f, 0.85f);
|
||||
// North wall (z = +80)
|
||||
addBox("border_n", glm::vec3(0.0f, kBH * 0.5f, 80.5f),
|
||||
glm::vec3(kBL, kBH, kBT), kBC,
|
||||
marble_t, noise_t, 0.0f, 0.75f, -1.0f);
|
||||
// South wall (z = -80)
|
||||
addBox("border_s", glm::vec3(0.0f, kBH * 0.5f, -80.5f),
|
||||
glm::vec3(kBL, kBH, kBT), kBC,
|
||||
marble_t, noise_t, 0.0f, 0.75f, -1.0f);
|
||||
// East wall (x = +80)
|
||||
addBox("border_e", glm::vec3( 80.5f, kBH * 0.5f, 0.0f),
|
||||
glm::vec3(kBT, kBH, kBL), kBC,
|
||||
marble_t, noise_t, 0.0f, 0.75f, -1.0f);
|
||||
// West wall (x = -80)
|
||||
addBox("border_w", glm::vec3(-80.5f, kBH * 0.5f, 0.0f),
|
||||
glm::vec3(kBT, kBH, kBL), kBC,
|
||||
marble_t, noise_t, 0.0f, 0.75f, -1.0f);
|
||||
}
|
||||
|
||||
// ============================ FOREST (NW) =====================
|
||||
// Trees + mossy boulders + glowing mushrooms + fallen logs
|
||||
auto tree = [&](glm::vec3 at, float s) {
|
||||
@@ -4274,10 +4301,25 @@ class SanctuaryDemo : public Engine {
|
||||
static constexpr int kMaxShots = 60;
|
||||
std::mt19937 shot_rng_{1337};
|
||||
|
||||
// Captured initial pose+body params for every dynamic object, so R / Triangle
|
||||
// can put the scene back to t=0.
|
||||
struct InitialState {
|
||||
std::string id;
|
||||
std::string shape; // "box" or "sphere"
|
||||
glm::vec3 position;
|
||||
glm::vec3 rotation; // Euler degrees
|
||||
float mass;
|
||||
float restitution;
|
||||
float friction;
|
||||
};
|
||||
std::vector<InitialState> initial_states_;
|
||||
|
||||
public:
|
||||
SanctuaryDemo()
|
||||
: Engine(1920, 1080, "ZoomEngine - Sanctuary (Full Showcase)") {}
|
||||
|
||||
void ResetScene();
|
||||
|
||||
void FireBall() {
|
||||
glm::vec3 cam_pos = GetCameraPosition();
|
||||
glm::vec3 cam_tgt = GetCameraTarget();
|
||||
@@ -4351,20 +4393,23 @@ public:
|
||||
"fog_density":0.011
|
||||
})"));
|
||||
|
||||
// --- Water & weather ---
|
||||
// --- Water: confined to a single central pool (visual only via water2).
|
||||
// Main water mesh is disabled so the rest of the map is dry land.
|
||||
processAgentCommand(json::parse(R"({"action":"water","enabled":false})"));
|
||||
processAgentCommand(json::parse(R"({
|
||||
"action":"water","enabled":true,
|
||||
"level":-0.45,"size":420,
|
||||
"amplitude":0.18,"wavelength":13,"speed":0.8,
|
||||
"shallow":[0.55,0.42,0.30],"deep":[0.03,0.07,0.13],
|
||||
"density":1.1,"resolution":180
|
||||
"action":"water2","enabled":true,
|
||||
"center":[0, 0, -22], "size":14, "level":0.18,
|
||||
"amplitude":0.06,"wavelength":4,"speed":0.7,
|
||||
"shallow":[0.45,0.55,0.55],
|
||||
"deep":[0.04,0.10,0.16],
|
||||
"resolution":96
|
||||
})"));
|
||||
processAgentCommand(json::parse(R"({
|
||||
"action":"weather","wind_dir":[0.9,0,0.4],
|
||||
"wind_speed":0.6,"storminess":0.08,"current_coef":0.5
|
||||
"wind_speed":0.6,"storminess":0.05,"current_coef":0.3
|
||||
})"));
|
||||
|
||||
// --- Ground ---
|
||||
// --- Ground (visual + solid physics floor) ---
|
||||
auto grass = CreateGameObject(
|
||||
CreatePlane(420.0f, 420.0f, glm::vec3(0.95f, 0.97f, 0.92f)),
|
||||
glm::vec3(0, 0, 0));
|
||||
@@ -4373,6 +4418,13 @@ public:
|
||||
grass->SetUVScale(glm::vec2(0.35f));
|
||||
grass->SetRoughness(0.95f);
|
||||
AddGameObject(grass);
|
||||
// Register the grass as the ground physics body. The plane collider is
|
||||
// infinite at y=0, so it catches anything anywhere on the map.
|
||||
namedObjects_["__ground"] = grass;
|
||||
processAgentCommand(json::parse(R"({
|
||||
"action":"body","id":"__ground","shape":"plane",
|
||||
"normal":[0,1,0],"offset":0,"static":true
|
||||
})"));
|
||||
|
||||
// --- Textures / cached refs ---
|
||||
GLuint wood_tex = TextureCache::Get("wood");
|
||||
@@ -4414,6 +4466,8 @@ public:
|
||||
if (mass > 0 || mass == -1.0f) // -1 = static
|
||||
bodyCmd(id, "box", (mass == -1.0f) ? 0 : mass, rest, frict,
|
||||
mass == -1.0f);
|
||||
if (!id.empty() && mass > 0)
|
||||
initial_states_.push_back({id, "box", pos, rot, mass, rest, frict});
|
||||
return obj;
|
||||
};
|
||||
|
||||
@@ -4430,9 +4484,57 @@ public:
|
||||
AddGameObject(obj);
|
||||
if (!id.empty()) namedObjects_[id] = obj;
|
||||
if (mass > 0) bodyCmd(id, "sphere", mass, rest, frict);
|
||||
if (!id.empty() && mass > 0)
|
||||
initial_states_.push_back({id, "sphere", pos, glm::vec3(0),
|
||||
mass, rest, frict});
|
||||
return obj;
|
||||
};
|
||||
|
||||
// --- Map perimeter walls: 4 static stone walls ringing an 80×80 play
|
||||
// area (X,Z in [-40,40]) so dynamic props can't bounce out of the map.
|
||||
{
|
||||
const float kBL = 81.0f; // wall length (slight corner overlap)
|
||||
const float kBH = 6.0f; // wall height
|
||||
const float kBT = 1.0f; // wall thickness
|
||||
const glm::vec3 kBC(0.92f, 0.88f, 0.82f);
|
||||
addBox("border_n", glm::vec3(0.0f, kBH * 0.5f, 40.5f),
|
||||
glm::vec3(kBL, kBH, kBT), kBC,
|
||||
marble_tex, noise_tex, 0.0f, 0.75f, -1.0f);
|
||||
addBox("border_s", glm::vec3(0.0f, kBH * 0.5f, -40.5f),
|
||||
glm::vec3(kBL, kBH, kBT), kBC,
|
||||
marble_tex, noise_tex, 0.0f, 0.75f, -1.0f);
|
||||
addBox("border_e", glm::vec3( 40.5f, kBH * 0.5f, 0.0f),
|
||||
glm::vec3(kBT, kBH, kBL), kBC,
|
||||
marble_tex, noise_tex, 0.0f, 0.75f, -1.0f);
|
||||
addBox("border_w", glm::vec3(-40.5f, kBH * 0.5f, 0.0f),
|
||||
glm::vec3(kBT, kBH, kBL), kBC,
|
||||
marble_tex, noise_tex, 0.0f, 0.75f, -1.0f);
|
||||
}
|
||||
|
||||
// --- Central pool curb: short stone walls forming a basin around the
|
||||
// visible water at center=[0,0,-22], size 14. The curb hides the visual
|
||||
// water seam at the edge and stops things rolling through into the pool.
|
||||
{
|
||||
const float kPC = -22.0f; // pool center Z
|
||||
const float kPS = 14.0f; // pool size (matches water2)
|
||||
const float kPH = 0.6f; // curb height
|
||||
const float kPT = 0.5f; // curb thickness
|
||||
const glm::vec3 kPCol(0.78f, 0.74f, 0.70f);
|
||||
float half = kPS * 0.5f;
|
||||
addBox("pool_n", glm::vec3(0.0f, kPH * 0.5f, kPC + half + kPT * 0.5f),
|
||||
glm::vec3(kPS + kPT, kPH, kPT), kPCol,
|
||||
marble_tex, noise_tex, 0.0f, 0.55f, -1.0f);
|
||||
addBox("pool_s", glm::vec3(0.0f, kPH * 0.5f, kPC - half - kPT * 0.5f),
|
||||
glm::vec3(kPS + kPT, kPH, kPT), kPCol,
|
||||
marble_tex, noise_tex, 0.0f, 0.55f, -1.0f);
|
||||
addBox("pool_e", glm::vec3( half + kPT * 0.5f, kPH * 0.5f, kPC),
|
||||
glm::vec3(kPT, kPH, kPS), kPCol,
|
||||
marble_tex, noise_tex, 0.0f, 0.55f, -1.0f);
|
||||
addBox("pool_w", glm::vec3(-half - kPT * 0.5f, kPH * 0.5f, kPC),
|
||||
glm::vec3(kPT, kPH, kPS), kPCol,
|
||||
marble_tex, noise_tex, 0.0f, 0.55f, -1.0f);
|
||||
}
|
||||
|
||||
// --- Central forge: stone altar + emissive brazier ---
|
||||
addBox("altar",
|
||||
glm::vec3(0, 0.75f, 0), glm::vec3(3.0f, 1.5f, 3.0f),
|
||||
@@ -4487,89 +4589,93 @@ public:
|
||||
1.0f, 0.2f,
|
||||
0.0f); // static visual
|
||||
|
||||
// --- Physics chain-reaction setup ---
|
||||
// A launch ramp angled down from east toward origin; metal ball at top.
|
||||
// Ramp is a tilted box; static.
|
||||
// ============================================================
|
||||
// PHYSICS PLAYGROUND SECTION — east half of the map (X >= +5).
|
||||
// Self-contained chain reaction + bonus props, kept clear of the
|
||||
// forge (origin) and the southern pool.
|
||||
// ============================================================
|
||||
|
||||
// Static launch ramp. Tilted -18° around Z so the +X end (where the
|
||||
// ball spawns) is the LOW end and the -X end is the HIGH end. Ball
|
||||
// gets a strong -X kick at t=2s, slides off the high end, falls onto
|
||||
// the floor and continues into the domino chain.
|
||||
addBox("ramp",
|
||||
glm::vec3(22.0f, 1.9f, 0.0f), glm::vec3(7.0f, 0.3f, 3.0f),
|
||||
glm::vec3(28.0f, 1.9f, 0.0f), glm::vec3(7.0f, 0.3f, 3.0f),
|
||||
glm::vec3(0.9f, 0.85f, 0.78f),
|
||||
wood_tex, noise_tex, 0.0f, 0.7f, -1.0f,
|
||||
0.0f, 0.0f, glm::vec3(0, 0, -18.0f)); // tilt down
|
||||
0.0f, 0.0f, glm::vec3(0, 0, -18.0f));
|
||||
|
||||
// Domino chain — 12 wooden boards standing in a line from origin out
|
||||
for (int i = 0; i < 12; ++i) {
|
||||
float x = 12.0f - i * 1.6f;
|
||||
addBox("dom_" + std::to_string(i),
|
||||
glm::vec3(x, 1.0f, 0), glm::vec3(0.3f, 2.0f, 1.2f),
|
||||
glm::vec3(0.9f, 0.85f, 0.7f),
|
||||
wood_tex, noise_tex, 0.0f, 0.6f,
|
||||
1.0f, 0.08f, 0.55f);
|
||||
}
|
||||
|
||||
// Crate stack — pyramid of wooden crates east of dominoes, near shore
|
||||
for (int y = 0; y < 3; ++y) {
|
||||
int n = 4 - y;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
float x = -10.0f - (3 - n) * 0.5f + i * 1.1f;
|
||||
float yp = 0.5f + y * 1.0f;
|
||||
addBox("crate_" + std::to_string(y * 4 + i),
|
||||
glm::vec3(x, yp, -8.0f), glm::vec3(1.0f),
|
||||
glm::vec3(0.85f, 0.75f, 0.55f),
|
||||
wood_tex, noise_tex, 0.0f, 0.7f,
|
||||
0.8f, 0.1f, 0.7f);
|
||||
}
|
||||
}
|
||||
|
||||
// Impulse ball — heavy metal sphere at top of ramp
|
||||
auto ball = addSphere("impulse_ball",
|
||||
glm::vec3(25.0f, 5.5f, 0.0f), 0.9f,
|
||||
// Heavy metal impulse ball, sitting near the +X (low) end of the ramp.
|
||||
addSphere("impulse_ball",
|
||||
glm::vec3(30.0f, 4.2f, 0.0f), 0.9f,
|
||||
glm::vec3(0.75f, 0.78f, 0.82f), 0, 0,
|
||||
1.0f, 0.3f,
|
||||
8.0f, 0.3f, 0.25f);
|
||||
(void)ball;
|
||||
|
||||
// --- Bonus physics content: much more to knock around ---
|
||||
|
||||
// Second domino line at an angle, north of the first
|
||||
for (int i = 0; i < 14; ++i) {
|
||||
float x = 8.0f - i * 1.4f;
|
||||
float z = -4.0f - i * 0.4f;
|
||||
addBox("dom2_" + std::to_string(i),
|
||||
glm::vec3(x, 1.0f, z), glm::vec3(0.28f, 2.0f, 1.1f),
|
||||
glm::vec3(0.9f, 0.82f, 0.65f),
|
||||
wood_tex, noise_tex, 0.0f, 0.65f,
|
||||
0.9f, 0.08f, 0.55f,
|
||||
glm::vec3(0, 16.0f, 0));
|
||||
// Primary domino chain — 12 boards along z=0, between ramp and forge.
|
||||
// Spacing 1.5 < domino height 2.0, so each falling domino's tip
|
||||
// overlaps the next domino's base — the chain propagates reliably.
|
||||
for (int i = 0; i < 12; ++i) {
|
||||
float x = 22.0f - i * 1.5f;
|
||||
addBox("dom_" + std::to_string(i),
|
||||
glm::vec3(x, 1.0f, 0.0f), glm::vec3(0.25f, 2.0f, 1.2f),
|
||||
glm::vec3(0.9f, 0.85f, 0.7f),
|
||||
wood_tex, noise_tex, 0.0f, 0.6f,
|
||||
0.6f, 0.05f, 0.7f);
|
||||
}
|
||||
|
||||
// Second crate pyramid, east of the first
|
||||
// Secondary domino chain, parallel to the first at z = +6.
|
||||
for (int i = 0; i < 12; ++i) {
|
||||
float x = 22.0f - i * 1.5f;
|
||||
addBox("dom2_" + std::to_string(i),
|
||||
glm::vec3(x, 1.0f, 6.0f), glm::vec3(0.25f, 2.0f, 1.1f),
|
||||
glm::vec3(0.9f, 0.82f, 0.65f),
|
||||
wood_tex, noise_tex, 0.0f, 0.65f,
|
||||
0.6f, 0.05f, 0.7f);
|
||||
}
|
||||
|
||||
// Crate pyramid, north end of physics section.
|
||||
for (int y = 0; y < 3; ++y) {
|
||||
int n = 4 - y;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
float x = 4.0f + i * 1.1f + (3 - n) * 0.5f;
|
||||
float x = 14.0f + i * 1.1f + (3 - n) * 0.5f;
|
||||
float yp = 0.5f + y * 1.0f;
|
||||
float z = -14.0f;
|
||||
addBox("crate2_" + std::to_string(y * 4 + i),
|
||||
glm::vec3(x, yp, z), glm::vec3(1.0f),
|
||||
addBox("crate_" + std::to_string(y * 4 + i),
|
||||
glm::vec3(x, yp, 14.0f), glm::vec3(1.0f),
|
||||
glm::vec3(0.85f, 0.75f, 0.55f),
|
||||
wood_tex, noise_tex, 0.0f, 0.7f,
|
||||
0.8f, 0.1f, 0.7f);
|
||||
}
|
||||
}
|
||||
|
||||
// Third crate wall (flat stack), on the west side
|
||||
// Second crate pyramid, mid-section.
|
||||
for (int y = 0; y < 3; ++y) {
|
||||
int n = 4 - y;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
float x = 26.0f + i * 1.1f + (3 - n) * 0.5f;
|
||||
float yp = 0.5f + y * 1.0f;
|
||||
addBox("crate2_" + std::to_string(y * 4 + i),
|
||||
glm::vec3(x, yp, 14.0f), glm::vec3(1.0f),
|
||||
glm::vec3(0.85f, 0.75f, 0.55f),
|
||||
wood_tex, noise_tex, 0.0f, 0.7f,
|
||||
0.8f, 0.1f, 0.7f);
|
||||
}
|
||||
}
|
||||
|
||||
// Concrete crate wall, eastern edge of section.
|
||||
for (int i = 0; i < 12; ++i) {
|
||||
int col = i % 4, row = i / 4;
|
||||
float x = -18.0f + col * 1.1f;
|
||||
float x = 32.0f + col * 1.1f;
|
||||
float y = 0.5f + row * 1.1f;
|
||||
addBox("wallc_" + std::to_string(i),
|
||||
glm::vec3(x, y, -6.0f), glm::vec3(1.0f),
|
||||
glm::vec3(0.65f, 0.78f, 0.85f), // blueish
|
||||
glm::vec3(x, y, 22.0f), glm::vec3(1.0f),
|
||||
glm::vec3(0.65f, 0.78f, 0.85f),
|
||||
concrete, noise_tex, 0.0f, 0.75f,
|
||||
0.6f, 0.2f, 0.6f);
|
||||
}
|
||||
|
||||
// Bowling-pin triangle near the center, 10 pins
|
||||
// Bowling-pin triangle, set up to receive whatever falls past the
|
||||
// domino chain.
|
||||
static const float pin_offsets[10][2] = {
|
||||
{ 0.0f, 0.0f},
|
||||
{-0.45f, 0.8f}, { 0.45f, 0.8f},
|
||||
@@ -4577,8 +4683,8 @@ public:
|
||||
{-1.35f, 2.4f}, {-0.45f, 2.4f}, { 0.45f, 2.4f}, { 1.35f, 2.4f}
|
||||
};
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
float px = 16.0f + pin_offsets[i][1];
|
||||
float pz = 3.0f + pin_offsets[i][0];
|
||||
float px = 14.0f - pin_offsets[i][1];
|
||||
float pz = -8.0f + pin_offsets[i][0];
|
||||
auto pin = CreateGameObject(
|
||||
CreateCylinder(0.35f, 1.6f, 14, glm::vec3(0.98f, 0.96f, 0.92f)),
|
||||
glm::vec3(px, 0.8f, pz));
|
||||
@@ -4587,26 +4693,29 @@ public:
|
||||
AddGameObject(pin);
|
||||
std::string id = "pin_" + std::to_string(i);
|
||||
namedObjects_[id] = pin;
|
||||
bodyCmd(id, "box", 0.5f, 0.2f, 0.4f); // box collider is fine for pins
|
||||
bodyCmd(id, "box", 0.5f, 0.2f, 0.4f);
|
||||
initial_states_.push_back({id, "box",
|
||||
glm::vec3(px, 0.8f, pz), glm::vec3(0), 0.5f, 0.2f, 0.4f});
|
||||
}
|
||||
|
||||
// Tall cube tower (8 blocks high) inviting to be knocked down
|
||||
// Cube tower, southeast corner of section.
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
float y = 0.6f + i * 1.2f;
|
||||
addBox("tower_" + std::to_string(i),
|
||||
glm::vec3(-15.0f, y, 8.0f), glm::vec3(1.2f),
|
||||
glm::vec3(30.0f, y, -18.0f), glm::vec3(1.2f),
|
||||
glm::vec3(0.85f, 0.80f, 0.72f),
|
||||
marble_tex, noise_tex, 0.0f, 0.5f,
|
||||
0.9f, 0.12f, 0.55f,
|
||||
glm::vec3(0, i * 7.0f, 0));
|
||||
}
|
||||
|
||||
// Scattered loose objects around the forge area for casual physics
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
float ang = (float)i / 20.0f * 2 * M_PI + rnd(-0.1f, 0.1f);
|
||||
float R = 18.0f + rnd(-3.0f, 3.0f);
|
||||
float x = std::cos(ang) * R;
|
||||
float z = std::sin(ang) * R;
|
||||
// Scattered loose objects across the eastern half (avoiding the pool
|
||||
// and the forge).
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
float x = rnd(8.0f, 36.0f);
|
||||
float z = rnd(-30.0f, 30.0f);
|
||||
// Skip cells that overlap key set-pieces.
|
||||
if (z > -2.0f && z < 8.0f && x > 6.0f && x < 24.0f) continue;
|
||||
bool is_sphere = (i % 2) == 0;
|
||||
std::string id = "loose_" + std::to_string(i);
|
||||
if (is_sphere) {
|
||||
@@ -4627,35 +4736,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// --- Floating barrels on the lake (buoyancy demo) ---
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
float x = rnd(-20.0f, 20.0f);
|
||||
float z = rnd(-55.0f, -25.0f);
|
||||
auto barrel = CreateGameObject(
|
||||
CreateCylinder(0.8f, 1.4f, 12,
|
||||
glm::vec3(0.9f, 0.78f, 0.55f)),
|
||||
glm::vec3(x, 1.5f, z));
|
||||
barrel->SetRotation(glm::vec3(0, jit(180.0f), 90.0f));
|
||||
barrel->SetTexture(wood_tex);
|
||||
barrel->SetNormalMap(noise_tex);
|
||||
barrel->SetRoughness(0.8f);
|
||||
AddGameObject(barrel);
|
||||
std::string id = "barrel_" + std::to_string(i);
|
||||
namedObjects_[id] = barrel;
|
||||
bodyCmd(id, "box", 1.0f, 0.3f, 0.4f); // approximate as box
|
||||
}
|
||||
|
||||
// Floating metal orbs
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
float x = rnd(-12.0f, 12.0f);
|
||||
float z = rnd(-50.0f, -30.0f);
|
||||
addSphere("orb_float_" + std::to_string(i),
|
||||
glm::vec3(x, 1.2f, z), 0.7f,
|
||||
glm::vec3(0.92f, 0.65f, 0.35f), 0, 0,
|
||||
1.0f, 0.3f,
|
||||
0.7f, 0.4f);
|
||||
}
|
||||
|
||||
// --- Distant mountain silhouettes ---
|
||||
for (int i = 0; i < 13; ++i) {
|
||||
float x = -175.0f + i * 28.0f + jit(6.0f);
|
||||
@@ -4774,27 +4854,36 @@ public:
|
||||
std::cout << "Sanctuary demo ready: " << game_objects_.size()
|
||||
<< " objects. Chain reaction fires at t=2s.\n"
|
||||
<< "Camera: WASD/arrows, Space/LCtrl = up/down, LShift = sprint.\n"
|
||||
<< "SHOOT: hold F, click LMB, or hold R1 (gamepad) to fire balls.\n";
|
||||
<< "SHOOT: hold F, click LMB, or hold R1 (gamepad) to fire balls.\n"
|
||||
<< "RESET: press R or Triangle (gamepad) to restart the demo.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnUpdate(float dt) override {
|
||||
time_elapsed_ += dt;
|
||||
|
||||
// Kick off the chain reaction 2 seconds in, once physics is warm
|
||||
// Kick off the chain reaction 2 seconds in, once physics is warm.
|
||||
// Heavy -X impulse sends the ball off the ramp and into the first
|
||||
// domino at x=22.
|
||||
if (!kickoff_fired_ && time_elapsed_ > 2.0f) {
|
||||
kickoff_fired_ = true;
|
||||
// Big left-ward nudge so the ball rolls down the ramp into dominoes
|
||||
json::Object c;
|
||||
c["action"] = json::Value(std::string("impulse"));
|
||||
c["id"] = json::Value(std::string("impulse_ball"));
|
||||
c["impulse"] = json::Value(json::Array{
|
||||
json::Value(-120.0),
|
||||
json::Value(-260.0),
|
||||
json::Value(0.0),
|
||||
json::Value(0.0)});
|
||||
processAgentCommand(json::Value(c));
|
||||
}
|
||||
|
||||
// Reset (R / Triangle) — restore every dynamic prop to its initial
|
||||
// pose with zero velocity, clear shot balls, and re-arm the kickoff.
|
||||
if (Input::IsKeyPressed(GLFW_KEY_R)
|
||||
|| Input::IsGamepadButtonPressed(Input::GamepadButton::Triangle)) {
|
||||
ResetScene();
|
||||
}
|
||||
|
||||
// Shoot balls from camera: F / LMB / R1 — rate-limited
|
||||
shot_cooldown_ -= dt;
|
||||
if (shot_cooldown_ <= 0.0f) {
|
||||
@@ -4867,6 +4956,38 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void SanctuaryDemo::ResetScene() {
|
||||
// Restore each captured dynamic body to its initial pose with zero
|
||||
// velocity. Re-issuing the "body" command rebuilds the physics body at
|
||||
// the GameObject's current position (so we set that first) with linear
|
||||
// and angular velocity = 0.
|
||||
for (const auto& s : initial_states_) {
|
||||
auto it = namedObjects_.find(s.id);
|
||||
if (it == namedObjects_.end()) continue;
|
||||
it->second->SetPosition(s.position);
|
||||
it->second->SetRotation(s.rotation);
|
||||
json::Object c;
|
||||
c["action"] = json::Value(std::string("body"));
|
||||
c["id"] = json::Value(s.id);
|
||||
c["shape"] = json::Value(s.shape);
|
||||
c["mass"] = json::Value((double)s.mass);
|
||||
c["restitution"] = json::Value((double)s.restitution);
|
||||
c["friction"] = json::Value((double)s.friction);
|
||||
processAgentCommand(json::Value(c));
|
||||
}
|
||||
// Despawn any in-flight player-fired balls.
|
||||
for (const auto& id : active_shots_) {
|
||||
json::Object dc;
|
||||
dc["action"] = json::Value(std::string("delete"));
|
||||
dc["id"] = json::Value(id);
|
||||
processAgentCommand(json::Value(dc));
|
||||
}
|
||||
active_shots_.clear();
|
||||
// Re-arm the chain-reaction kickoff.
|
||||
time_elapsed_ = 0.0f;
|
||||
kickoff_fired_ = false;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------
|
||||
// SunsetForestDemo: a composed, cinematic scene built to show off the whole
|
||||
|
||||
Reference in New Issue
Block a user