deterministic gem hunt spawn

This commit is contained in:
RandomityGuy 2023-07-19 01:59:41 +05:30
parent 423f551655
commit cc84f4d30e
5 changed files with 110 additions and 2 deletions

View file

@ -581,6 +581,7 @@ class MarbleWorld extends Scheduler {
this.playGui.setCenterText(''); this.playGui.setCenterText('');
this.clearSchedule(); this.clearSchedule();
this.outOfBounds = false; this.outOfBounds = false;
this.gameMode.onRespawn();
AudioManager.playSound(ResourceLoader.getResource('data/sound/spawn_alternate.wav', ResourceLoader.getAudio, this.soundResources)); AudioManager.playSound(ResourceLoader.getResource('data/sound/spawn_alternate.wav', ResourceLoader.getAudio, this.soundResources));
} }

53
src/RandomLCG.hx Normal file
View file

@ -0,0 +1,53 @@
class RandomLCG {
var seed:Int;
static var msSeed:Int = 1376312589;
static var quotient = 127773;
static var remainder = 2836;
public function new(seed = -1) {
this.seed = (seed == -1) ? generateSeed() : seed;
}
inline function generateSeed() {
// A very, VERY crude LCG but good enough to generate
// a nice range of seed values
msSeed = (msSeed * 0x015a4e35) + 1;
msSeed = (msSeed >> 16) & 0x7fff;
return (msSeed);
}
public function setSeed(seed:Int) {
this.seed = seed;
}
public function randInt() {
if (seed <= quotient)
seed = (seed * 16807) % 2147483647;
else {
var high_part:Int = Std.int(seed / quotient);
var low_part = seed % quotient;
var test:Int = (16807 * low_part) - (remainder * high_part);
if (test > 0)
seed = test;
else
seed = test + 2147483647;
}
return seed;
}
public function randFloat() {
return randInt() / 2147483647.0;
}
public function randRange(i:Int, n:Int) {
return (i + (randInt() % (n - i + 1)));
}
public function randRangeF(i:Float, n:Int) {
return (i + (n - i) * randFloat());
}
}

View file

@ -24,6 +24,7 @@ interface GameMode {
public function applyRewindState(state:RewindableState):Void; public function applyRewindState(state:RewindableState):Void;
public function onTimeExpire():Void; public function onTimeExpire():Void;
public function onRestart():Void; public function onRestart():Void;
public function onRespawn():Void;
public function onGemPickup(gem:Gem):Void; public function onGemPickup(gem:Gem):Void;
public function getPreloadFiles():Array<String>; public function getPreloadFiles():Array<String>;

View file

@ -1,5 +1,6 @@
package modes; package modes;
import hxd.Rand;
import rewind.RewindableState; import rewind.RewindableState;
import gui.AchievementsGui; import gui.AchievementsGui;
import modes.GameMode.ScoreType; import modes.GameMode.ScoreType;
@ -81,6 +82,8 @@ class HuntState implements RewindableState {
var activeGemSpawnGroup:Array<GemSpawnSphere>; var activeGemSpawnGroup:Array<GemSpawnSphere>;
var activeGems:Array<Gem>; var activeGems:Array<Gem>;
var points:Int; var points:Int;
var rngState:Int;
var rngState2:Int;
public function new() {} public function new() {}
@ -94,6 +97,8 @@ class HuntState implements RewindableState {
c.activeGemSpawnGroup = activeGemSpawnGroup.copy(); c.activeGemSpawnGroup = activeGemSpawnGroup.copy();
c.points = points; c.points = points;
c.activeGems = activeGems.copy(); c.activeGems = activeGems.copy();
c.rngState = rngState;
c.rngState2 = rngState2;
return c; return c;
} }
} }
@ -109,6 +114,8 @@ class HuntMode extends NullMode {
var activeGems:Array<Gem> = []; var activeGems:Array<Gem> = [];
var gemBeams:Array<GemBeam> = []; var gemBeams:Array<GemBeam> = [];
var gemToBeamMap:Map<Gem, GemBeam> = []; var gemToBeamMap:Map<Gem, GemBeam> = [];
var rng:RandomLCG = new RandomLCG(100);
var rng2:RandomLCG = new RandomLCG(100);
var points:Int = 0; var points:Int = 0;
@ -131,7 +138,7 @@ class HuntMode extends NullMode {
}; };
override function getSpawnTransform() { override function getSpawnTransform() {
var randomSpawn = playerSpawnPoints[Math.floor(Math.random() * playerSpawnPoints.length)]; var randomSpawn = playerSpawnPoints[Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1))];
var spawnPos = MisParser.parseVector3(randomSpawn.position); var spawnPos = MisParser.parseVector3(randomSpawn.position);
spawnPos.x *= -1; spawnPos.x *= -1;
var spawnRot = MisParser.parseRotation(randomSpawn.rotation); var spawnRot = MisParser.parseRotation(randomSpawn.rotation);
@ -170,6 +177,7 @@ class HuntMode extends NullMode {
var spawnMat = spawnRot.toMatrix(); var spawnMat = spawnRot.toMatrix();
var up = spawnMat.up(); var up = spawnMat.up();
spawnPos = spawnPos.add(up.multiply(0.727843 / 3)); // 1.5 -> 0.5 spawnPos = spawnPos.add(up.multiply(0.727843 / 3)); // 1.5 -> 0.5
return { return {
position: spawnPos, position: spawnPos,
orientation: spawnRot, orientation: spawnRot,
@ -179,6 +187,26 @@ class HuntMode extends NullMode {
return null; return null;
} }
override function onRespawn() {
if (activeGemSpawnGroup.length != 0) {
var gemAvg = new Vector();
for (g in activeGemSpawnGroup) {
gemAvg = gemAvg.add(g.position);
}
gemAvg.scale(1 / activeGemSpawnGroup.length);
var delta = gemAvg.sub(level.marble.getAbsPos().getPosition());
var gravFrame = level.getOrientationQuat(0).toMatrix();
var v1 = gravFrame.front();
var v2 = gravFrame.right();
var deltaRot = new Vector(delta.dot(v2), delta.dot(v1));
if (deltaRot.length() >= 0.001) {
var ang = Math.atan2(deltaRot.x, deltaRot.y);
level.marble.camera.CameraYaw = ang;
level.marble.camera.nextCameraYaw = ang;
}
}
}
override public function getStartTime() { override public function getStartTime() {
return level.mission.qualifyTime; return level.mission.qualifyTime;
} }
@ -188,6 +216,8 @@ class HuntMode extends NullMode {
} }
override function onRestart() { override function onRestart() {
rng.setSeed(100);
rng2.setSeed(100);
setupGems(); setupGems();
points = 0; points = 0;
@:privateAccess level.playGui.formatGemHuntCounter(points); @:privateAccess level.playGui.formatGemHuntCounter(points);
@ -242,9 +272,26 @@ class HuntMode extends NullMode {
} }
} }
} }
activeGemSpawnGroup = [];
activeGems = []; activeGems = [];
refillGemGroups(); refillGemGroups();
var gemAvg = new Vector();
for (g in activeGemSpawnGroup) {
gemAvg = gemAvg.add(g.position);
}
gemAvg.scale(1 / activeGemSpawnGroup.length);
var delta = gemAvg.sub(level.marble.getAbsPos().getPosition());
var gravFrame = level.getOrientationQuat(0).toMatrix();
var v1 = gravFrame.front();
var v2 = gravFrame.right();
var deltaRot = new Vector(delta.dot(v2), delta.dot(v1));
if (deltaRot.length() >= 0.001) {
var ang = Math.atan2(deltaRot.x, deltaRot.y);
level.marble.camera.CameraYaw = ang;
level.marble.camera.nextCameraYaw = ang;
}
} }
function refillGemGroups() { function refillGemGroups() {
@ -320,7 +367,7 @@ class HuntMode extends NullMode {
function findGemSpawnGroup(outSpawnPoint:Vector) { function findGemSpawnGroup(outSpawnPoint:Vector) {
// Pick random spawn point // Pick random spawn point
var rnd:Int = Std.int(Math.random() * gemSpawnPoints.length); var rnd:Int = Std.int(rng.randRange(0, gemSpawnPoints.length - 1));
if (level.isRecording) if (level.isRecording)
level.replay.recordRandomGenState(rnd); level.replay.recordRandomGenState(rnd);
if (level.isWatching) if (level.isWatching)
@ -394,6 +441,8 @@ class HuntMode extends NullMode {
s.points = points; s.points = points;
s.activeGemSpawnGroup = activeGemSpawnGroup; s.activeGemSpawnGroup = activeGemSpawnGroup;
s.activeGems = activeGems.copy(); s.activeGems = activeGems.copy();
s.rngState = @:privateAccess rng.seed;
s.rngState2 = @:privateAccess rng2.seed;
return s; return s;
} }
@ -415,5 +464,7 @@ class HuntMode extends NullMode {
var gemBeam = gemToBeamMap.get(gem); var gemBeam = gemToBeamMap.get(gem);
gemBeam.setHide(false); gemBeam.setHide(false);
} }
rng.setSeed(s.rngState);
rng2.setSeed(s.rngState2);
} }
} }

View file

@ -56,6 +56,8 @@ class NullMode implements GameMode {
public function onRestart() {} public function onRestart() {}
public function onRespawn() {}
public function onGemPickup(gem:Gem) { public function onGemPickup(gem:Gem) {
this.level.gemCount++; this.level.gemCount++;
var string:String; var string:String;