mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
hunt mode!
This commit is contained in:
parent
1b86022146
commit
d98da24da2
12 changed files with 621 additions and 68 deletions
BIN
data/skies/gemCubemapUp2.png
Normal file
BIN
data/skies/gemCubemapUp2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
BIN
data/skies/gemCubemapUp3.png
Normal file
BIN
data/skies/gemCubemapUp3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
|
|
@ -239,6 +239,7 @@ class Marble extends GameObject {
|
|||
|
||||
public var heldPowerup:PowerUp;
|
||||
public var lastContactNormal:Vector;
|
||||
public var lastContactPosition:Vector;
|
||||
|
||||
var helicopter:HelicopterImage;
|
||||
var blastWave:BlastWave;
|
||||
|
|
@ -269,8 +270,6 @@ class Marble extends GameObject {
|
|||
|
||||
public var mode:Mode = Play;
|
||||
|
||||
public var startPad:StartPad;
|
||||
|
||||
public var prevPos:Vector;
|
||||
|
||||
var cloak:Bool = false;
|
||||
|
|
@ -866,6 +865,7 @@ class Marble extends GameObject {
|
|||
a.set(a.x + aFriction.x, a.y + aFriction.y, a.z + aFriction.z);
|
||||
|
||||
lastContactNormal = bestContact.normal;
|
||||
lastContactPosition = this.getAbsPos().getPosition();
|
||||
}
|
||||
a.set(a.x + aControl.x, a.y + aControl.y, a.z + aControl.z);
|
||||
if (this.mode == Finish) {
|
||||
|
|
|
|||
|
|
@ -89,6 +89,9 @@ import src.ResourceLoaderWorker;
|
|||
import haxe.io.Path;
|
||||
import src.Console;
|
||||
import src.Gamepad;
|
||||
import modes.GameMode;
|
||||
import modes.NullMode;
|
||||
import modes.GameMode.GameModeFactory;
|
||||
|
||||
class MarbleWorld extends Scheduler {
|
||||
public var collisionWorld:CollisionWorld;
|
||||
|
|
@ -120,6 +123,8 @@ class MarbleWorld extends Scheduler {
|
|||
var endPad:EndPad;
|
||||
var skyElement:MissionElementSky;
|
||||
|
||||
public var gameMode:GameMode;
|
||||
|
||||
// Lighting
|
||||
public var ambient:Vector;
|
||||
public var dirLight:Vector;
|
||||
|
|
@ -203,6 +208,7 @@ class MarbleWorld extends Scheduler {
|
|||
this.scene2d = scene2d;
|
||||
this.mission = mission;
|
||||
this.game = mission.game.toLowerCase();
|
||||
this.gameMode = GameModeFactory.getGameMode(this, mission.missionInfo.gamemode);
|
||||
this.replay = new Replay(mission.path, mission.isClaMission ? mission.id : 0);
|
||||
this.isRecording = record;
|
||||
this.rewindManager = new RewindManager(this);
|
||||
|
|
@ -254,6 +260,7 @@ class MarbleWorld extends Scheduler {
|
|||
};
|
||||
this.mission.load();
|
||||
scanMission(this.mission.root);
|
||||
this.gameMode.missionScan(this.mission);
|
||||
this.resourceLoadFuncs.push(fwd -> this.initScene(fwd));
|
||||
this.resourceLoadFuncs.push(fwd -> this.initMarble(fwd));
|
||||
this.resourceLoadFuncs.push(fwd -> {
|
||||
|
|
@ -428,6 +435,14 @@ class MarbleWorld extends Scheduler {
|
|||
return 0; // Load checkpoint
|
||||
}
|
||||
|
||||
if (!full) {
|
||||
var respawnT = this.gameMode.getRespawnTransform();
|
||||
if (respawnT != null) {
|
||||
respawn(respawnT.position, respawnT.orientation, respawnT.up);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.isWatching) {
|
||||
this.replay.clear();
|
||||
} else {
|
||||
|
|
@ -437,7 +452,7 @@ class MarbleWorld extends Scheduler {
|
|||
this.rewindManager.clear();
|
||||
|
||||
this.timeState.currentAttemptTime = 0;
|
||||
this.timeState.gameplayClock = 0;
|
||||
this.timeState.gameplayClock = this.gameMode.getStartTime();
|
||||
this.bonusTime = 0;
|
||||
this.outOfBounds = false;
|
||||
this.blastAmount = 0;
|
||||
|
|
@ -486,12 +501,12 @@ class MarbleWorld extends Scheduler {
|
|||
this.cancel(this.oobSchedule);
|
||||
this.cancel(this.oobSchedule2);
|
||||
|
||||
var startquat = this.getStartPositionAndOrientation();
|
||||
var startquat = this.gameMode.getSpawnTransform();
|
||||
|
||||
this.marble.setMarblePosition(startquat.position.x, startquat.position.y, startquat.position.z + 0.727843);
|
||||
this.marble.setMarblePosition(startquat.position.x, startquat.position.y, startquat.position.z);
|
||||
this.marble.reset();
|
||||
|
||||
var euler = startquat.quat.toEuler();
|
||||
var euler = startquat.orientation.toEuler();
|
||||
this.marble.camera.init(cast this);
|
||||
this.marble.camera.CameraYaw = euler.z + Math.PI / 2;
|
||||
this.marble.camera.CameraPitch = 0.45;
|
||||
|
|
@ -500,7 +515,6 @@ class MarbleWorld extends Scheduler {
|
|||
this.marble.camera.oob = false;
|
||||
this.marble.camera.finish = false;
|
||||
this.marble.setMode(Start);
|
||||
this.marble.startPad = cast startquat.pad;
|
||||
sky.follow = marble.camera;
|
||||
|
||||
var missionInfo:MissionElementScriptObject = cast this.mission.root.elements.filter((element) -> element._type == MissionElementType.ScriptObject
|
||||
|
|
@ -513,18 +527,54 @@ class MarbleWorld extends Scheduler {
|
|||
for (interior in this.interiors)
|
||||
interior.reset();
|
||||
|
||||
this.currentUp = new Vector(0, 0, 1);
|
||||
this.orientationChangeTime = -1e8;
|
||||
this.oldOrientationQuat = new Quat();
|
||||
this.newOrientationQuat = new Quat();
|
||||
this.setUp(startquat.up, this.timeState, true);
|
||||
this.deselectPowerUp();
|
||||
playGui.setCenterText('');
|
||||
|
||||
AudioManager.playSound(ResourceLoader.getResource('data/sound/spawn_alternate.wav', ResourceLoader.getAudio, this.soundResources));
|
||||
|
||||
this.gameMode.onRestart();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function respawn(respawnPos:Vector, respawnQuat:Quat, respawnUp:Vector) {
|
||||
var marble = this.marble;
|
||||
// Determine where to spawn the marble
|
||||
this.marble.setMarblePosition(respawnPos.x, respawnPos.y, respawnPos.z);
|
||||
marble.velocity.set(0, 0, 0);
|
||||
marble.omega.set(0, 0, 0);
|
||||
Console.log('Respawn:');
|
||||
Console.log('Marble Position: ${respawnPos.x} ${respawnPos.y} ${respawnPos.z}');
|
||||
Console.log('Marble Velocity: ${marble.velocity.x} ${marble.velocity.y} ${marble.velocity.z}');
|
||||
Console.log('Marble Angular: ${marble.omega.x} ${marble.omega.y} ${marble.omega.z}');
|
||||
// Set camera orientation
|
||||
var euler = respawnQuat.toEuler();
|
||||
this.marble.camera.CameraYaw = euler.z + Math.PI / 2;
|
||||
this.marble.camera.CameraPitch = 0.45;
|
||||
this.marble.camera.nextCameraYaw = this.marble.camera.CameraYaw;
|
||||
this.marble.camera.nextCameraPitch = this.marble.camera.CameraPitch;
|
||||
this.marble.camera.oob = false;
|
||||
@:privateAccess this.marble.helicopterEnableTime = -1e8;
|
||||
@:privateAccess this.marble.megaMarbleEnableTime = -1e8;
|
||||
if (this.isRecording) {
|
||||
this.replay.recordCameraState(this.marble.camera.CameraYaw, this.marble.camera.CameraPitch);
|
||||
this.replay.recordMarbleInput(0, 0);
|
||||
this.replay.recordMarbleState(respawnPos, marble.velocity, marble.getRotationQuat(), marble.omega);
|
||||
this.replay.recordMarbleStateFlags(false, false, true, false);
|
||||
}
|
||||
|
||||
// In this case, we set the gravity to the relative "up" vector of the checkpoint shape.
|
||||
var up = new Vector(0, 0, 1);
|
||||
up.transform(respawnQuat.toMatrix());
|
||||
this.setUp(up, this.timeState, true);
|
||||
|
||||
this.playGui.setCenterText('');
|
||||
this.clearSchedule();
|
||||
this.outOfBounds = false;
|
||||
AudioManager.playSound(ResourceLoader.getResource('data/sound/spawn_alternate.wav', ResourceLoader.getAudio, this.soundResources));
|
||||
}
|
||||
|
||||
public function updateGameState() {
|
||||
if (this.outOfBounds)
|
||||
return; // We will update state manually
|
||||
|
|
@ -539,25 +589,6 @@ class MarbleWorld extends Scheduler {
|
|||
}
|
||||
}
|
||||
|
||||
function getStartPositionAndOrientation() {
|
||||
// The player is spawned at the last start pad in the mission file.
|
||||
var startPad = this.dtsObjects.filter(x -> x is StartPad).pop();
|
||||
var position:Vector;
|
||||
var quat:Quat = new Quat();
|
||||
if (startPad != null) {
|
||||
// If there's a start pad, start there
|
||||
position = startPad.getAbsPos().getPosition();
|
||||
quat = startPad.getRotationQuat().clone();
|
||||
} else {
|
||||
position = new Vector(0, 0, 300);
|
||||
}
|
||||
return {
|
||||
position: position,
|
||||
quat: quat,
|
||||
pad: startPad
|
||||
};
|
||||
}
|
||||
|
||||
function addToSimgroup(obj:GameObject, simGroup:MissionElementSimGroup) {
|
||||
if (simGroup == null)
|
||||
return;
|
||||
|
|
@ -1098,11 +1129,13 @@ class MarbleWorld extends Scheduler {
|
|||
|
||||
var prevGameplayClock = this.timeState.gameplayClock;
|
||||
|
||||
var timeMultiplier = this.gameMode.timeMultiplier();
|
||||
|
||||
if (!this.isWatching) {
|
||||
if (this.bonusTime != 0 && this.timeState.currentAttemptTime >= 3.5) {
|
||||
this.bonusTime -= dt;
|
||||
if (this.bonusTime < 0) {
|
||||
this.timeState.gameplayClock -= this.bonusTime;
|
||||
this.timeState.gameplayClock -= this.bonusTime * timeMultiplier;
|
||||
this.bonusTime = 0;
|
||||
}
|
||||
if (timeTravelSound == null) {
|
||||
|
|
@ -1115,9 +1148,9 @@ class MarbleWorld extends Scheduler {
|
|||
timeTravelSound = null;
|
||||
}
|
||||
if (this.timeState.currentAttemptTime >= 3.5) {
|
||||
this.timeState.gameplayClock += dt;
|
||||
this.timeState.gameplayClock += dt * timeMultiplier;
|
||||
} else if (this.timeState.currentAttemptTime + dt >= 3.5) {
|
||||
this.timeState.gameplayClock += (this.timeState.currentAttemptTime + dt) - 3.5;
|
||||
this.timeState.gameplayClock += ((this.timeState.currentAttemptTime + dt) - 3.5) * timeMultiplier;
|
||||
}
|
||||
}
|
||||
this.timeState.currentAttemptTime += dt;
|
||||
|
|
@ -1220,37 +1253,7 @@ class MarbleWorld extends Scheduler {
|
|||
}
|
||||
|
||||
public function pickUpGem(gem:Gem) {
|
||||
this.gemCount++;
|
||||
var string:String;
|
||||
|
||||
// Show a notification (and play a sound) based on the gems remaining
|
||||
if (this.gemCount == this.totalGems) {
|
||||
string = "You have all the gems, head for the finish!";
|
||||
// if (!this.rewinding)
|
||||
AudioManager.playSound(ResourceLoader.getResource('data/sound/gem_all.wav', ResourceLoader.getAudio, this.soundResources));
|
||||
|
||||
// Some levels with this package end immediately upon collection of all gems
|
||||
// if (this.mission.misFile.activatedPackages.includes('endWithTheGems')) {
|
||||
// let
|
||||
// completionOfImpact = this.physics.computeCompletionOfImpactWithBody(gem.bodies[0], 2); // Get the exact point of impact
|
||||
// this.touchFinish(completionOfImpact);
|
||||
// }
|
||||
} else {
|
||||
string = "You picked up a gem. ";
|
||||
|
||||
var remaining = this.totalGems - this.gemCount;
|
||||
if (remaining == 1) {
|
||||
string += "Only one gem to go!";
|
||||
} else {
|
||||
string += '${remaining} gems to go!';
|
||||
}
|
||||
|
||||
// if (!this.rewinding)
|
||||
AudioManager.playSound(ResourceLoader.getResource('data/sound/gem_collect.wav', ResourceLoader.getAudio, this.soundResources));
|
||||
}
|
||||
|
||||
displayAlert(string);
|
||||
this.playGui.formatGemCounter(this.gemCount, this.totalGems);
|
||||
this.gameMode.onGemPickup(gem);
|
||||
}
|
||||
|
||||
public function callCollisionHandlers(marble:Marble, timeState:TimeState, start:Vector, end:Vector, startQuat:Quat, endQuat:Quat) {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class Radar {
|
|||
var gemCount = 0;
|
||||
for (gem in level.gems) {
|
||||
if (!gem.pickedUp) {
|
||||
renderArrow(gem.boundingCollider.boundingBox.getCenter().toVector(), 0xE60000);
|
||||
renderArrow(gem.boundingCollider.boundingBox.getCenter().toVector(), gem.radarColor);
|
||||
gemCount++;
|
||||
}
|
||||
}
|
||||
|
|
@ -68,7 +68,6 @@ class Radar {
|
|||
var fovY = (level.scene.camera.fovY * 0.5) * Math.PI / 180.0;
|
||||
|
||||
var blink = time < 3 ? ((Std.int(Math.floor((time * 1000) / 500))) % 2 == 1) : false;
|
||||
trace((Std.int(time * 1000) / 500));
|
||||
|
||||
var gravityMat = level.getOrientationQuat(level.timeState.currentAttemptTime).toMatrix();
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@ class MissionElementScriptObject extends MissionElementBase {
|
|||
var alarmstarttime:String;
|
||||
var game:String;
|
||||
var difficulty:String;
|
||||
var gamemode:String;
|
||||
var gemgroupradius:String;
|
||||
var maxgemspergroup:String;
|
||||
|
||||
public function new() {
|
||||
_type = MissionElementType.ScriptObject;
|
||||
|
|
@ -160,6 +163,7 @@ class MissionElementSpawnSphere extends MissionElementBase {
|
|||
var datablock:String;
|
||||
var resettime:Null<String>;
|
||||
var timeout:Null<String>;
|
||||
var gemdatablock:String;
|
||||
|
||||
public function new() {
|
||||
_type = MissionElementType.SpawnSphere;
|
||||
|
|
|
|||
29
src/modes/GameMode.hx
Normal file
29
src/modes/GameMode.hx
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package modes;
|
||||
|
||||
import shapes.Gem;
|
||||
import h3d.Quat;
|
||||
import h3d.Vector;
|
||||
import src.MarbleWorld;
|
||||
import src.Mission;
|
||||
|
||||
interface GameMode {
|
||||
public function getSpawnTransform():{position:Vector, orientation:Quat, up:Vector};
|
||||
public function getRespawnTransform():{position:Vector, orientation:Quat, up:Vector};
|
||||
public function missionScan(mission:Mission):Void;
|
||||
public function getStartTime():Float;
|
||||
public function timeMultiplier():Float;
|
||||
|
||||
public function onRestart():Void;
|
||||
public function onGemPickup(gem:Gem):Void;
|
||||
}
|
||||
|
||||
class GameModeFactory {
|
||||
public static function getGameMode(level:MarbleWorld, mode:String):GameMode {
|
||||
if (mode != null)
|
||||
switch (mode.toLowerCase()) {
|
||||
case "scrum":
|
||||
return new HuntMode(level);
|
||||
}
|
||||
return new NullMode(level);
|
||||
}
|
||||
}
|
||||
279
src/modes/HuntMode.hx
Normal file
279
src/modes/HuntMode.hx
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
package modes;
|
||||
|
||||
import shapes.GemBeam;
|
||||
import shapes.Gem;
|
||||
import src.Console;
|
||||
import h3d.col.Bounds;
|
||||
import octree.IOctreeObject.RayIntersectionData;
|
||||
import octree.Octree;
|
||||
import octree.IOctreeObject.IOctreeObject;
|
||||
import mis.MisParser;
|
||||
import h3d.Vector;
|
||||
import h3d.Quat;
|
||||
import mis.MissionElement.MissionElementType;
|
||||
import mis.MissionElement;
|
||||
import src.Mission;
|
||||
import mis.MissionElement.MissionElementSpawnSphere;
|
||||
import src.AudioManager;
|
||||
import src.ResourceLoader;
|
||||
|
||||
@:publicFields
|
||||
class GemSpawnSphere {
|
||||
var position:Vector;
|
||||
var rotation:Quat;
|
||||
var element:MissionElementSpawnSphere;
|
||||
var gem:Gem;
|
||||
var gemBeam:GemBeam;
|
||||
var gemColor:String;
|
||||
|
||||
public function new(elem:MissionElementSpawnSphere) {
|
||||
position = MisParser.parseVector3(elem.position);
|
||||
position.x *= -1;
|
||||
rotation = MisParser.parseRotation(elem.rotation);
|
||||
rotation.x *= -1;
|
||||
rotation.w *= -1;
|
||||
element = elem;
|
||||
gemColor = "red";
|
||||
if (elem.gemdatablock != null) {
|
||||
switch (elem.gemdatablock.toLowerCase()) {
|
||||
case "gemitem_2pts":
|
||||
gemColor = "yellow";
|
||||
case "gemitem_5pts":
|
||||
gemColor = "blue";
|
||||
default:
|
||||
gemColor = "red";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GemOctreeElem implements IOctreeObject {
|
||||
public var boundingBox:Bounds;
|
||||
public var spawn:GemSpawnSphere;
|
||||
|
||||
var priority:Int;
|
||||
|
||||
public function new(vec:Vector, spawn:GemSpawnSphere) {
|
||||
boundingBox = new Bounds();
|
||||
boundingBox.addPoint(vec.add(new Vector(-0.5, -0.5, -0.5)).toPoint());
|
||||
boundingBox.addPoint(vec.add(new Vector(0.5, 0.5, 0.5)).toPoint());
|
||||
this.spawn = spawn;
|
||||
}
|
||||
|
||||
public function getElementType() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
public function setPriority(priority:Int) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public function rayCast(rayOrigin:Vector, rayDirection:Vector):Array<RayIntersectionData> {
|
||||
throw new haxe.exceptions.NotImplementedException(); // Not applicable
|
||||
}
|
||||
}
|
||||
|
||||
class HuntMode extends NullMode {
|
||||
var gemSpawnPoints:Array<GemSpawnSphere> = [];
|
||||
var playerSpawnPoints:Array<MissionElementSpawnSphere> = [];
|
||||
|
||||
var gemOctree:Octree;
|
||||
var gemGroupRadius:Float;
|
||||
var maxGemsPerGroup:Int;
|
||||
var activeGemSpawnGroup:Array<GemSpawnSphere>;
|
||||
var activeGems:Array<Gem> = [];
|
||||
var gemBeams:Array<GemBeam> = [];
|
||||
var gemToBeamMap:Map<Gem, GemBeam> = [];
|
||||
|
||||
override function missionScan(mission:Mission) {
|
||||
function scanMission(simGroup:MissionElementSimGroup) {
|
||||
for (element in simGroup.elements) {
|
||||
if ([MissionElementType.SpawnSphere].contains(element._type)) {
|
||||
var spawnSphere:MissionElementSpawnSphere = cast element;
|
||||
var dbname = spawnSphere.datablock.toLowerCase();
|
||||
if (dbname == "spawnspheremarker")
|
||||
playerSpawnPoints.push(spawnSphere);
|
||||
if (dbname == "gemspawnspheremarker")
|
||||
gemSpawnPoints.push(new GemSpawnSphere(spawnSphere));
|
||||
} else if (element._type == MissionElementType.SimGroup) {
|
||||
scanMission(cast element);
|
||||
}
|
||||
}
|
||||
}
|
||||
scanMission(mission.root);
|
||||
};
|
||||
|
||||
override function getSpawnTransform() {
|
||||
var randomSpawn = playerSpawnPoints[Math.floor(Math.random() * playerSpawnPoints.length)];
|
||||
var spawnPos = MisParser.parseVector3(randomSpawn.position);
|
||||
spawnPos.x *= -1;
|
||||
var spawnRot = MisParser.parseRotation(randomSpawn.rotation);
|
||||
spawnRot.x *= -1;
|
||||
spawnRot.w *= -1;
|
||||
var spawnMat = spawnRot.toMatrix();
|
||||
var up = spawnMat.up();
|
||||
spawnPos = spawnPos.add(up.multiply(0.727843 / 3)); // 1.5 -> 0.5
|
||||
return {
|
||||
position: spawnPos,
|
||||
orientation: spawnRot,
|
||||
up: up
|
||||
}
|
||||
}
|
||||
|
||||
override function getRespawnTransform() {
|
||||
var lastContactPos = this.level.marble.lastContactPosition;
|
||||
// Pick closest spawn point
|
||||
var closestSpawn:MissionElementSpawnSphere = null;
|
||||
var closestDistance = 1e10;
|
||||
for (spawn in playerSpawnPoints) {
|
||||
var pos = MisParser.parseVector3(spawn.position);
|
||||
pos.x *= -1;
|
||||
var dist = pos.distance(lastContactPos);
|
||||
if (dist < closestDistance) {
|
||||
closestDistance = dist;
|
||||
closestSpawn = spawn;
|
||||
}
|
||||
}
|
||||
if (closestSpawn != null) {
|
||||
var spawnPos = MisParser.parseVector3(closestSpawn.position);
|
||||
spawnPos.x *= -1;
|
||||
var spawnRot = MisParser.parseRotation(closestSpawn.rotation);
|
||||
spawnRot.x *= -1;
|
||||
spawnRot.w *= -1;
|
||||
var spawnMat = spawnRot.toMatrix();
|
||||
var up = spawnMat.up();
|
||||
spawnPos = spawnPos.add(up.multiply(0.727843 / 3)); // 1.5 -> 0.5
|
||||
return {
|
||||
position: spawnPos,
|
||||
orientation: spawnRot,
|
||||
up: up
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
override public function getStartTime() {
|
||||
return level.mission.qualifyTime;
|
||||
}
|
||||
|
||||
override public function timeMultiplier() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
override function onRestart() {
|
||||
setupGems();
|
||||
}
|
||||
|
||||
override function onGemPickup(gem:Gem) {
|
||||
AudioManager.playSound(ResourceLoader.getResource('data/sound/gem_collect.wav', ResourceLoader.getAudio, @:privateAccess this.level.soundResources));
|
||||
activeGems.remove(gem);
|
||||
var beam = gemToBeamMap.get(gem);
|
||||
beam.setHide(true);
|
||||
refillGemGroups();
|
||||
}
|
||||
|
||||
function setupGems() {
|
||||
gemGroupRadius = 20.0;
|
||||
maxGemsPerGroup = 4;
|
||||
if (level.mission.missionInfo.gemgroupradius != null && level.mission.missionInfo.gemgroupradius != "")
|
||||
gemGroupRadius = Std.parseFloat(level.mission.missionInfo.gemgroupradius);
|
||||
if (level.mission.missionInfo.maxgemspergroup != null && level.mission.missionInfo.maxgemspergroup != "")
|
||||
maxGemsPerGroup = Std.parseInt(level.mission.missionInfo.maxgemspergroup);
|
||||
|
||||
gemOctree = new Octree();
|
||||
for (gemSpawn in gemSpawnPoints) {
|
||||
var vec = gemSpawn.position;
|
||||
gemOctree.insert(new GemOctreeElem(vec, gemSpawn));
|
||||
}
|
||||
|
||||
activeGems = [];
|
||||
refillGemGroups();
|
||||
}
|
||||
|
||||
function refillGemGroups() {
|
||||
if (activeGems.length == 0) {
|
||||
var spawnGroup = pickGemSpawnGroup();
|
||||
activeGemSpawnGroup = spawnGroup;
|
||||
fillGemGroup(spawnGroup);
|
||||
}
|
||||
}
|
||||
|
||||
function fillGemGroup(group:Array<GemSpawnSphere>) {
|
||||
for (gemSpawn in group) {
|
||||
if (gemSpawn.gem != null) {
|
||||
gemSpawn.gem.pickedUp = false;
|
||||
gemSpawn.gem.setHide(false);
|
||||
gemSpawn.gemBeam.setHide(false);
|
||||
this.activeGems.push(gemSpawn.gem);
|
||||
} else {
|
||||
var melem = new MissionElementItem();
|
||||
melem.datablock = "GemItem" + gemSpawn.gemColor;
|
||||
var gem = new Gem(melem);
|
||||
gemSpawn.gem = gem;
|
||||
gem.setPosition(gemSpawn.position.x, gemSpawn.position.y, gemSpawn.position.z);
|
||||
gem.setRotationQuat(gemSpawn.rotation);
|
||||
this.activeGems.push(gem);
|
||||
|
||||
var gemBeam = new GemBeam();
|
||||
gemBeam.setPosition(gemSpawn.position.x, gemSpawn.position.y, gemSpawn.position.z);
|
||||
gemBeam.setRotationQuat(gemSpawn.rotation);
|
||||
this.gemBeams.push(gemBeam);
|
||||
|
||||
gemSpawn.gemBeam = gemBeam;
|
||||
this.gemToBeamMap.set(gem, gemBeam);
|
||||
|
||||
level.addDtsObject(gemBeam, () -> {
|
||||
level.addDtsObject(gem, () -> {
|
||||
level.gems.push(gem);
|
||||
}); // Please be fast lol
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pickGemSpawnGroup() {
|
||||
var searchRadius = gemGroupRadius * 2;
|
||||
|
||||
for (i in 0...6) {
|
||||
var groupMainPt = new Vector();
|
||||
var group = findGemSpawnGroup(groupMainPt);
|
||||
if (group.length == 0) {
|
||||
Console.log("Gem spawn group has no spawn points!");
|
||||
continue;
|
||||
}
|
||||
|
||||
var ok = true;
|
||||
if (activeGemSpawnGroup != null) {
|
||||
for (gemSpawn in activeGemSpawnGroup) {
|
||||
if (gemSpawn.position.distance(groupMainPt) < searchRadius) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ok)
|
||||
continue;
|
||||
return group;
|
||||
}
|
||||
Console.log("Unable to find spawn group that works with active gem groups, using random!");
|
||||
var groupMainPt = new Vector();
|
||||
return findGemSpawnGroup(groupMainPt);
|
||||
}
|
||||
|
||||
function findGemSpawnGroup(outSpawnPoint:Vector) {
|
||||
// Pick random spawn point
|
||||
var spawnPoint = gemSpawnPoints[Math.floor(Math.random() * gemSpawnPoints.length)];
|
||||
var pos = spawnPoint.position;
|
||||
|
||||
var results = [];
|
||||
var search = gemOctree.radiusSearch(pos, gemGroupRadius);
|
||||
for (elem in search) {
|
||||
var gemElem:GemOctreeElem = cast elem;
|
||||
results.push(gemElem.spawn);
|
||||
if (results.length >= maxGemsPerGroup)
|
||||
break;
|
||||
}
|
||||
outSpawnPoint.load(pos);
|
||||
return results;
|
||||
}
|
||||
}
|
||||
82
src/modes/NullMode.hx
Normal file
82
src/modes/NullMode.hx
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
package modes;
|
||||
|
||||
import shapes.Gem;
|
||||
import h3d.Quat;
|
||||
import h3d.Vector;
|
||||
import shapes.StartPad;
|
||||
import src.MarbleWorld;
|
||||
import src.Mission;
|
||||
import src.AudioManager;
|
||||
import src.ResourceLoader;
|
||||
|
||||
class NullMode implements GameMode {
|
||||
var level:MarbleWorld;
|
||||
|
||||
public function new(level:MarbleWorld) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public function getSpawnTransform() {
|
||||
// The player is spawned at the last start pad in the mission file.
|
||||
var startPad = this.level.dtsObjects.filter(x -> x is StartPad).pop();
|
||||
var position:Vector;
|
||||
var quat:Quat = new Quat();
|
||||
if (startPad != null) {
|
||||
// If there's a start pad, start there
|
||||
position = startPad.getAbsPos().getPosition();
|
||||
quat = startPad.getRotationQuat().clone();
|
||||
} else {
|
||||
position = new Vector(0, 0, 300);
|
||||
}
|
||||
position.z += 0.727843;
|
||||
return {
|
||||
position: position,
|
||||
orientation: quat,
|
||||
up: new Vector(0, 0, 1)
|
||||
};
|
||||
}
|
||||
|
||||
public function getRespawnTransform():{up:Vector, position:Vector, orientation:Quat} {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function missionScan(mission:Mission) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
public function getStartTime() {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
public function timeMultiplier() {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
public function onRestart() {}
|
||||
|
||||
public function onGemPickup(gem:Gem) {
|
||||
this.level.gemCount++;
|
||||
var string:String;
|
||||
|
||||
// Show a notification (and play a sound) based on the gems remaining
|
||||
if (this.level.gemCount == this.level.totalGems) {
|
||||
string = "You have all the gems, head for the finish!";
|
||||
AudioManager.playSound(ResourceLoader.getResource('data/sound/gem_all.wav', ResourceLoader.getAudio, @:privateAccess this.level.soundResources));
|
||||
} else {
|
||||
string = "You picked up a gem. ";
|
||||
|
||||
var remaining = this.level.totalGems - this.level.gemCount;
|
||||
if (remaining == 1) {
|
||||
string += "Only one gem to go!";
|
||||
} else {
|
||||
string += '${remaining} gems to go!';
|
||||
}
|
||||
|
||||
AudioManager.playSound(ResourceLoader.getResource('data/sound/gem_collect.wav', ResourceLoader.getAudio,
|
||||
@:privateAccess this.level.soundResources));
|
||||
}
|
||||
|
||||
this.level.displayAlert(string);
|
||||
@:privateAccess this.level.playGui.formatGemCounter(this.level.gemCount, this.level.totalGems);
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ class PriorityQueue<T> {
|
|||
|
||||
public function enqueue(val:T, priority:Float) {
|
||||
var node = new PriorityQueueNode<T>(val, priority);
|
||||
if (this.queue == null) {
|
||||
if (this.queue == null || this.queue.length == 0) {
|
||||
this.queue = [node];
|
||||
} else {
|
||||
if (this.queue[0].priority >= priority) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ class Gem extends DtsObject {
|
|||
|
||||
var gemColor:String;
|
||||
|
||||
public var radarColor:Int;
|
||||
|
||||
public function new(element:MissionElementItem) {
|
||||
super();
|
||||
dtsPath = "data/shapes/items/gem.dts";
|
||||
|
|
@ -30,6 +32,14 @@ class Gem extends DtsObject {
|
|||
this.identifier = "Gem" + color;
|
||||
this.matNameOverride.set('base.gem', color + ".gem");
|
||||
gemColor = color + ".gem";
|
||||
radarColor = switch (color) {
|
||||
case "blue":
|
||||
0x0000E6;
|
||||
case "yellow":
|
||||
0xE6FF00;
|
||||
default:
|
||||
0xE60000;
|
||||
}
|
||||
}
|
||||
|
||||
public override function init(level:MarbleWorld, onFinish:Void->Void) {
|
||||
|
|
@ -68,7 +78,18 @@ class Gem extends DtsObject {
|
|||
|
||||
override function getPreloadMaterials(dts:dts.DtsFile) {
|
||||
var mats = super.getPreloadMaterials(dts);
|
||||
mats.push("data/skies/gemCubemapUp.png");
|
||||
switch (gemColor) {
|
||||
case "yellow":
|
||||
mats.push('data/shapes/items/yellow.gem.png');
|
||||
mats.push("data/skies/gemCubemapUp2.png");
|
||||
case "blue":
|
||||
mats.push('data/shapes/items/blue.gem.png');
|
||||
mats.push("data/skies/gemCubemapUp4.png");
|
||||
default:
|
||||
mats.push('data/shapes/items/red.gem.png');
|
||||
mats.push("data/skies/gemCubemapUp.png");
|
||||
}
|
||||
|
||||
return mats;
|
||||
}
|
||||
|
||||
|
|
@ -94,5 +115,47 @@ class Gem extends DtsObject {
|
|||
material.shadows = false;
|
||||
material.receiveShadows = true;
|
||||
}
|
||||
if (matName == "yellow.gem") {
|
||||
var diffuseTex = ResourceLoader.getTexture('data/shapes/items/yellow.gem.png').resource;
|
||||
diffuseTex.wrap = Repeat;
|
||||
diffuseTex.mipMap = Nearest;
|
||||
|
||||
var cubemapTex = new h3d.mat.Texture(64, 64, [Cube]);
|
||||
var cubemapFace = ResourceLoader.getImage('data/skies/gemCubemapUp2.png').resource;
|
||||
for (i in 0...6) {
|
||||
cubemapTex.uploadPixels(cubemapFace.getPixels(), 0, i);
|
||||
}
|
||||
var shader = new shaders.DefaultCubemapNormalNoSpecMaterial(diffuseTex, 1, cubemapTex);
|
||||
var dtsTex = material.mainPass.getShader(shaders.DtsTexture);
|
||||
dtsTex.passThrough = true;
|
||||
material.mainPass.removeShader(material.textureShader);
|
||||
material.mainPass.addShader(shader);
|
||||
var thisprops:Dynamic = material.getDefaultProps();
|
||||
thisprops.light = false; // We will calculate our own lighting
|
||||
material.props = thisprops;
|
||||
material.shadows = false;
|
||||
material.receiveShadows = true;
|
||||
}
|
||||
if (matName == "blue.gem") {
|
||||
var diffuseTex = ResourceLoader.getTexture('data/shapes/items/blue.gem.png').resource;
|
||||
diffuseTex.wrap = Repeat;
|
||||
diffuseTex.mipMap = Nearest;
|
||||
|
||||
var cubemapTex = new h3d.mat.Texture(64, 64, [Cube]);
|
||||
var cubemapFace = ResourceLoader.getImage('data/skies/gemCubemapUp3.png').resource;
|
||||
for (i in 0...6) {
|
||||
cubemapTex.uploadPixels(cubemapFace.getPixels(), 0, i);
|
||||
}
|
||||
var shader = new shaders.DefaultCubemapNormalNoSpecMaterial(diffuseTex, 1, cubemapTex);
|
||||
var dtsTex = material.mainPass.getShader(shaders.DtsTexture);
|
||||
dtsTex.passThrough = true;
|
||||
material.mainPass.removeShader(material.textureShader);
|
||||
material.mainPass.addShader(shader);
|
||||
var thisprops:Dynamic = material.getDefaultProps();
|
||||
thisprops.light = false; // We will calculate our own lighting
|
||||
material.props = thisprops;
|
||||
material.shadows = false;
|
||||
material.receiveShadows = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
94
src/shapes/GemBeam.hx
Normal file
94
src/shapes/GemBeam.hx
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
package shapes;
|
||||
|
||||
import h3d.mat.Material;
|
||||
import src.DtsObject;
|
||||
import src.ResourceLoader;
|
||||
|
||||
class GemBeam extends DtsObject {
|
||||
public function new() {
|
||||
super();
|
||||
this.dtsPath = "data/shapes/items/gembeam.dts";
|
||||
this.isCollideable = false;
|
||||
this.isTSStatic = false;
|
||||
this.identifier = "GemBeam";
|
||||
this.useInstancing = true;
|
||||
this.animateSubObjectOpacities = true;
|
||||
}
|
||||
|
||||
public override function init(level:src.MarbleWorld, onFinish:() -> Void) {
|
||||
super.init(level, onFinish);
|
||||
}
|
||||
|
||||
override function update(timeState:src.TimeState) {
|
||||
super.update(timeState);
|
||||
}
|
||||
|
||||
override function getPreloadMaterials(dts:dts.DtsFile) {
|
||||
var mats = super.getPreloadMaterials(dts);
|
||||
mats.push("data/shapes/pads/mistyglow.png");
|
||||
return mats;
|
||||
}
|
||||
|
||||
override function postProcessMaterial(matName:String, material:Material) {
|
||||
if (matName == "mistyglow") {
|
||||
var diffuseTex = ResourceLoader.getTexture("data/shapes/pads/mistyglow.png").resource;
|
||||
diffuseTex.wrap = Repeat;
|
||||
diffuseTex.mipMap = Nearest;
|
||||
// aa
|
||||
var trivialShader = new shaders.TrivialMaterial(diffuseTex);
|
||||
material.mainPass.removeShader(material.textureShader);
|
||||
var glowpass = material.mainPass.clone();
|
||||
|
||||
glowpass.addShader(trivialShader);
|
||||
var dtsshader = glowpass.getShader(shaders.DtsTexture);
|
||||
dtsshader.passThrough = true;
|
||||
glowpass.setPassName("glow");
|
||||
glowpass.depthTest = LessEqual;
|
||||
glowpass.depthWrite = false;
|
||||
glowpass.enableLights = false;
|
||||
glowpass.setBlendMode(Alpha);
|
||||
// glowpass.blendSrc = SrcAlpha;
|
||||
// glowpass.blendDst = OneMinusSrcAlpha;
|
||||
material.addPass(glowpass);
|
||||
|
||||
material.mainPass.setPassName("glowPreNoRender");
|
||||
material.mainPass.removeShader(material.textureShader);
|
||||
material.mainPass.addShader(trivialShader);
|
||||
dtsshader = material.mainPass.getShader(shaders.DtsTexture);
|
||||
dtsshader.passThrough = true;
|
||||
material.mainPass.enableLights = false;
|
||||
|
||||
// var thisprops:Dynamic = material.getDefaultProps();
|
||||
// thisprops.light = false; // We will calculate our own lighting
|
||||
// material.props = thisprops;
|
||||
material.shadows = false;
|
||||
// material.blendMode = Alpha;
|
||||
material.mainPass.depthWrite = false;
|
||||
|
||||
// var diffuseTex = ResourceLoader.getTexture("data/shapes/pads/mistyglow.png").resource;
|
||||
// diffuseTex.wrap = Repeat;
|
||||
// diffuseTex.mipMap = Nearest;
|
||||
|
||||
// var trivialShader = new shaders.TrivialMaterial(diffuseTex);
|
||||
|
||||
// // var glowpass = material.mainPass.clone();
|
||||
// // glowpass.addShader(trivialShader);
|
||||
// // var dtsshader = glowpass.getShader(shaders.DtsTexture);
|
||||
// // dtsshader.passThrough = true;
|
||||
// // glowpass.removeShader(dtsshader);
|
||||
// // glowpass.setPassName("glow");
|
||||
// // glowpass.depthTest = LessEqual;
|
||||
// // glowpass.depthWrite = false;
|
||||
// // glowpass.enableLights = false;
|
||||
// // glowpass.setBlendMode(AlphaAdd);
|
||||
// // material.addPass(glowpass);
|
||||
|
||||
// material.mainPass.setPassName("glowPre");
|
||||
// material.mainPass.addShader(trivialShader);
|
||||
// var dtsshader = material.mainPass.getShader(shaders.DtsTexture);
|
||||
// dtsshader.passThrough = true;
|
||||
// material.mainPass.enableLights = false;
|
||||
// material.mainPass.setBlendMode(Alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue