mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
Trigger and PI stuff
This commit is contained in:
parent
a5704ff8c5
commit
8d47fc0163
10 changed files with 283 additions and 11 deletions
|
|
@ -71,10 +71,10 @@ class DifBuilder {
|
|||
}
|
||||
];
|
||||
|
||||
public static function loadDif(path:String, itr:InteriorObject) {
|
||||
public static function loadDif(path:String, itr:InteriorObject, ?so:Int = -1) {
|
||||
var dif = ResourceLoader.loadInterior(path);
|
||||
|
||||
var geo = dif.interiors[0];
|
||||
var geo = so == -1 ? dif.interiors[0] : dif.subObjects[so];
|
||||
|
||||
var hulls = geo.convexHulls;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package src;
|
||||
|
||||
import src.GameObject;
|
||||
import triggers.Trigger;
|
||||
import src.Mission;
|
||||
import src.TimeState;
|
||||
import gui.PlayGui;
|
||||
import src.ParticleSystem.ParticleManager;
|
||||
|
|
@ -34,18 +37,21 @@ class MarbleWorld extends Scheduler {
|
|||
public var dtsObjects:Array<DtsObject> = [];
|
||||
|
||||
var shapeImmunity:Array<DtsObject> = [];
|
||||
var shapeOrTriggerInside:Array<DtsObject> = [];
|
||||
var shapeOrTriggerInside:Array<GameObject> = [];
|
||||
|
||||
public var timeState:TimeState = new TimeState();
|
||||
public var bonusTime:Float = 0;
|
||||
public var sky:Sky;
|
||||
|
||||
public var scene:Scene;
|
||||
public var mission:Mission;
|
||||
|
||||
public var marble:Marble;
|
||||
public var worldOrientation:Quat;
|
||||
public var currentUp = new Vector(0, 0, 1);
|
||||
public var outOfBounds:Bool = false;
|
||||
public var outOfBoundsTime:TimeState;
|
||||
public var finishTime:TimeState;
|
||||
|
||||
var helpTextTimeState:Float = -1e8;
|
||||
var alertTextTimeState:Float = -1e8;
|
||||
|
|
@ -222,6 +228,13 @@ class MarbleWorld extends Scheduler {
|
|||
this.alertTextTimeState = this.timeState.currentAttemptTime;
|
||||
}
|
||||
|
||||
public function displayHelp(text:String) {
|
||||
this.playGui.setHelpText(text);
|
||||
this.helpTextTimeState = this.timeState.currentAttemptTime;
|
||||
|
||||
// TODO FIX
|
||||
}
|
||||
|
||||
function callCollisionHandlers(marble:Marble) {
|
||||
var contacts = this.collisionWorld.radiusSearch(marble.getAbsPos().getPosition(), marble._radius);
|
||||
var newImmunity = [];
|
||||
|
|
@ -249,11 +262,25 @@ class MarbleWorld extends Scheduler {
|
|||
}
|
||||
|
||||
shape.onMarbleInside(timeState);
|
||||
if (!this.shapeOrTriggerInside.contains(shape)) {
|
||||
this.shapeOrTriggerInside.push(shape);
|
||||
if (!this.shapeOrTriggerInside.contains(contact.go)) {
|
||||
this.shapeOrTriggerInside.push(contact.go);
|
||||
shape.onMarbleEnter(timeState);
|
||||
}
|
||||
inside.push(shape);
|
||||
inside.push(contact.go);
|
||||
}
|
||||
if (contact.go is Trigger) {
|
||||
var trigger:Trigger = cast contact.go;
|
||||
var contacttest = trigger.collider.sphereIntersection(contactsphere, timeState);
|
||||
if (contacttest.length != 0) {
|
||||
trigger.onMarbleContact(timeState);
|
||||
}
|
||||
|
||||
trigger.onMarbleInside(timeState);
|
||||
if (!this.shapeOrTriggerInside.contains(contact.go)) {
|
||||
this.shapeOrTriggerInside.push(contact.go);
|
||||
trigger.onMarbleEnter(timeState);
|
||||
}
|
||||
inside.push(contact.go);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -333,6 +360,19 @@ class MarbleWorld extends Scheduler {
|
|||
this.oldOrientationQuat = currentQuat;
|
||||
this.orientationChangeTime = timeState.currentAttemptTime;
|
||||
}
|
||||
|
||||
public function goOutOfBounds() {
|
||||
if (this.outOfBounds || this.finishTime != null)
|
||||
return;
|
||||
// this.updateCamera(this.timeState); // Update the camera at the point of OOB-ing
|
||||
this.outOfBounds = true;
|
||||
this.outOfBoundsTime = this.timeState.clone();
|
||||
// this.oobCameraPosition = camera.position.clone();
|
||||
playGui.setCenterText('outofbounds');
|
||||
// AudioManager.play('whoosh.wav');
|
||||
// if (this.replay.mode != = 'playback')
|
||||
this.schedule(this.timeState.currentAttemptTime + 2, () -> this.restart());
|
||||
}
|
||||
}
|
||||
|
||||
typedef ScheduleInfo = {
|
||||
|
|
|
|||
13
src/Mission.hx
Normal file
13
src/Mission.hx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package src;
|
||||
|
||||
import src.ResourceLoader;
|
||||
|
||||
class Mission {
|
||||
public function getDifPath(rawElementPath:String) {
|
||||
rawElementPath = rawElementPath.toLowerCase();
|
||||
var path = rawElementPath;
|
||||
if (StringTools.contains(path, 'interiors_mbg/'))
|
||||
path = StringTools.replace(path, 'interiors_mbg/', 'interiors/');
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,13 @@
|
|||
package src;
|
||||
|
||||
import src.DifBuilder;
|
||||
import mis.MisParser;
|
||||
import mis.MissionElement;
|
||||
import triggers.MustChangeTrigger;
|
||||
import mis.MissionElement.MissionElementPathedInterior;
|
||||
import mis.MissionElement.MissionElementSimGroup;
|
||||
import mis.MissionElement.MissionElementPath;
|
||||
import h3d.Quat;
|
||||
import src.TimeState;
|
||||
import src.MarbleWorld;
|
||||
import h3d.Matrix;
|
||||
|
|
@ -18,6 +26,11 @@ typedef PIState = {
|
|||
}
|
||||
|
||||
class PathedInterior extends InteriorObject {
|
||||
var path:MissionElementPath;
|
||||
var simGroup:MissionElementSimGroup;
|
||||
var element:MissionElementPathedInterior;
|
||||
var triggers:Array<MustChangeTrigger> = [];
|
||||
|
||||
public var markerData:Array<PathedInteriorMarker> = [];
|
||||
|
||||
public var duration:Float;
|
||||
|
|
@ -25,6 +38,10 @@ class PathedInterior extends InteriorObject {
|
|||
public var targetTime:Float;
|
||||
public var changeTime:Float;
|
||||
|
||||
var basePosition:Vector;
|
||||
var baseOrientation:Quat;
|
||||
var baseScale:Vector;
|
||||
|
||||
public var prevPosition:Vector;
|
||||
public var currentPosition:Vector;
|
||||
|
||||
|
|
@ -33,14 +50,72 @@ class PathedInterior extends InteriorObject {
|
|||
var stopped:Bool = false;
|
||||
var stopTime:Float;
|
||||
|
||||
public var level:MarbleWorld;
|
||||
|
||||
var previousState:PIState;
|
||||
|
||||
public static function createFromSimGroup(simGroup:MissionElementSimGroup, level:MarbleWorld) {
|
||||
var interiorElement:MissionElementPathedInterior = cast simGroup.elements.filter((element) -> element._type == MissionElementType.PathedInterior)[0];
|
||||
var difFile = level.mission.getDifPath(interiorElement.interiorresource);
|
||||
if (difFile == null)
|
||||
return null;
|
||||
var pathedInterior = new PathedInterior();
|
||||
pathedInterior.level = level;
|
||||
|
||||
DifBuilder.loadDif(difFile, pathedInterior, cast MisParser.parseNumber(interiorElement.interiorindex)); // (difFile, path, level, );
|
||||
|
||||
pathedInterior.simGroup = simGroup;
|
||||
pathedInterior.element = interiorElement;
|
||||
level.interiors.push(pathedInterior);
|
||||
// await
|
||||
// Util.wait(10); // See shapes for the meaning of this hack
|
||||
// await
|
||||
pathedInterior.init(level);
|
||||
return pathedInterior;
|
||||
}
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
}
|
||||
|
||||
public override function init(level:MarbleWorld) {
|
||||
this.basePosition = MisParser.parseVector3(this.element.baseposition);
|
||||
this.baseOrientation = MisParser.parseRotation(this.element.baserotation);
|
||||
this.baseScale = MisParser.parseVector3(this.element.basescale);
|
||||
// this.hasCollision = this.baseScale.x != 0
|
||||
// && this.baseScale.y != = 0 && this.baseScale.z != = 0; // Don't want to add buggy geometry
|
||||
|
||||
// Fix zero-volume interiors so they receive correct lighting
|
||||
if (this.baseScale.x == 0)
|
||||
this.baseScale.x = 0.0001;
|
||||
if (this.baseScale.y == 0)
|
||||
this.baseScale.y = 0.0001;
|
||||
if (this.baseScale.z == 0)
|
||||
this.baseScale.z = 0.0001;
|
||||
|
||||
this.setRotationQuat(this.baseOrientation);
|
||||
|
||||
this.path = cast this.simGroup.elements.filter((element) -> element._type == MissionElementType.Path)[0];
|
||||
|
||||
this.markerData = this.path.markers.map(x -> {
|
||||
var marker = new PathedInteriorMarker();
|
||||
marker.msToNext = MisParser.parseNumber(x.mstonext) / 1000;
|
||||
marker.smoothingType = x.smoothingtype;
|
||||
marker.position = MisParser.parseVector3(x.position);
|
||||
marker.rotation = MisParser.parseRotation(x.rotation);
|
||||
return marker;
|
||||
});
|
||||
|
||||
this.computeDuration();
|
||||
|
||||
var triggers = this.simGroup.elements.filter((element) -> element._type == MissionElementType.Trigger);
|
||||
for (triggerElement in triggers) {
|
||||
var te:MissionElementTrigger = cast triggerElement;
|
||||
if (te.targettime == null)
|
||||
continue; // Not a pathed interior trigger
|
||||
var trigger = new MustChangeTrigger(te, cast this);
|
||||
this.triggers.push(trigger);
|
||||
}
|
||||
this.reset();
|
||||
}
|
||||
|
||||
|
|
@ -147,7 +222,10 @@ class PathedInterior extends InteriorObject {
|
|||
var m2:PathedInteriorMarker = this.markerData[1];
|
||||
if (m1 == null) {
|
||||
// Incase there are no markers at all
|
||||
var mat = this.getTransform();
|
||||
var mat = new Matrix();
|
||||
this.baseOrientation.toMatrix(mat);
|
||||
mat.setPosition(this.basePosition);
|
||||
mat.scale(this.baseScale.x, this.baseScale.y, this.baseScale.z);
|
||||
return mat;
|
||||
} else {
|
||||
m1 = this.markerData[0];
|
||||
|
|
@ -197,17 +275,32 @@ class PathedInterior extends InteriorObject {
|
|||
// Offset by the position of the first marker
|
||||
var firstPosition = this.markerData[0].position;
|
||||
position.sub(firstPosition);
|
||||
var tform = this.getTransform().clone();
|
||||
var basePosition = tform.getPosition();
|
||||
position.add(basePosition); // Add the base position
|
||||
tform.setPosition(position);
|
||||
return tform;
|
||||
|
||||
var mat = new Matrix();
|
||||
this.baseOrientation.toMatrix(mat);
|
||||
mat.setPosition(position);
|
||||
mat.scale(this.baseScale.x, this.baseScale.y, this.baseScale.z);
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
override function reset() {
|
||||
this.currentTime = 0;
|
||||
this.targetTime = -1;
|
||||
this.changeTime = 0;
|
||||
|
||||
if (this.element.initialposition != "") {
|
||||
this.currentTime = MisParser.parseNumber(this.element.initialposition) / 1000;
|
||||
}
|
||||
|
||||
if (this.element.initialtargetposition != "") {
|
||||
this.targetTime = MisParser.parseNumber(this.element.initialtargetposition);
|
||||
// Alright this is strange. In Torque, there are some FPS-dependent client/server desync issues that cause the interior to start at the end position whenever the initialTargetPosition is somewhere greater than 1 and, like, approximately below 50.
|
||||
if (this.targetTime > 0 && this.targetTime < 50)
|
||||
this.currentTime = this.duration;
|
||||
}
|
||||
|
||||
this.stopTime = 0;
|
||||
this.stopped = false;
|
||||
// Reset the position
|
||||
|
|
|
|||
|
|
@ -230,6 +230,15 @@ class PlayGui {
|
|||
alertTextBackground.y = scene2d.height - 102 + 1;
|
||||
}
|
||||
|
||||
public function setHelpText(text:String) {
|
||||
this.helpTextForeground.text = text;
|
||||
this.helpTextBackground.text = text;
|
||||
helpTextForeground.x = scene2d.width / 2 - helpTextForeground.textWidth / 2;
|
||||
helpTextForeground.y = scene2d.height - 102;
|
||||
helpTextBackground.x = scene2d.width / 2 - helpTextBackground.textWidth / 2 + 1;
|
||||
helpTextBackground.y = scene2d.height - 102 + 1;
|
||||
}
|
||||
|
||||
public function setPowerupImage(powerupIdentifier:String) {
|
||||
this.powerupImageScene.removeChildren();
|
||||
if (powerupIdentifier == "SuperJump") {
|
||||
|
|
|
|||
11
src/triggers/HelpTrigger.hx
Normal file
11
src/triggers/HelpTrigger.hx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package triggers;
|
||||
|
||||
import src.TimeState;
|
||||
|
||||
class HelpTrigger extends Trigger {
|
||||
override function onMarbleEnter(timeState:TimeState) {
|
||||
// AudioManager.play('infotutorial.wav');
|
||||
this.level.displayHelp(this.element.text);
|
||||
// this.level.replay.recordMarbleEnter(this);
|
||||
}
|
||||
}
|
||||
10
src/triggers/InBoundsTrigger.hx
Normal file
10
src/triggers/InBoundsTrigger.hx
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package triggers;
|
||||
|
||||
import src.TimeState;
|
||||
|
||||
class InBoundsTrigger extends Trigger {
|
||||
override function onMarbleLeave(timeState:TimeState) {
|
||||
this.level.goOutOfBounds();
|
||||
// this.level.replay.recordMarbleLeave(this);
|
||||
}
|
||||
}
|
||||
29
src/triggers/MustChangeTrigger.hx
Normal file
29
src/triggers/MustChangeTrigger.hx
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package triggers;
|
||||
|
||||
import src.PathedInterior;
|
||||
import mis.MissionElement.MissionElementTrigger;
|
||||
import src.TimeState;
|
||||
import mis.MisParser;
|
||||
|
||||
class MustChangeTrigger extends Trigger {
|
||||
var interior:PathedInterior;
|
||||
|
||||
public function new(element:MissionElementTrigger, interior:PathedInterior) {
|
||||
super(element, interior.level);
|
||||
this.interior = interior;
|
||||
}
|
||||
|
||||
public override function onMarbleEnter(time:TimeState) {
|
||||
this.interior.setTargetTime(time, MisParser.parseNumber(this.element.targettime));
|
||||
if (this.element.instant == "1") {
|
||||
if (this.element.icontinuetottime != null && this.element.icontinuetottime != "0") {
|
||||
// Absolutely strange, and not sure if it's even a thing in MBG, but is implement nonetheless.
|
||||
this.interior.currentTime = this.interior.targetTime;
|
||||
this.interior.targetTime = MisParser.parseNumber(this.element.icontinuetottime);
|
||||
} else {
|
||||
this.interior.changeTime = Math.NEGATIVE_INFINITY; // "If instant is 1, the MP will warp to targetTime instantly."
|
||||
}
|
||||
}
|
||||
// this.level.replay.recordMarbleEnter(this);
|
||||
}
|
||||
}
|
||||
10
src/triggers/OutOfBoundsTrigger.hx
Normal file
10
src/triggers/OutOfBoundsTrigger.hx
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package triggers;
|
||||
|
||||
import src.TimeState;
|
||||
|
||||
class OutOfBoundsTrigger extends Trigger {
|
||||
override function onMarbleInside(time:TimeState) {
|
||||
this.level.goOutOfBounds();
|
||||
// this.level.replay.recordMarbleInside(this);
|
||||
}
|
||||
}
|
||||
57
src/triggers/Trigger.hx
Normal file
57
src/triggers/Trigger.hx
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package triggers;
|
||||
|
||||
import h3d.col.Bounds;
|
||||
import h3d.Matrix;
|
||||
import h3d.Vector;
|
||||
import mis.MisParser;
|
||||
import collision.BoxCollisionEntity;
|
||||
import mis.MissionElement.MissionElementTrigger;
|
||||
import src.GameObject;
|
||||
import src.MarbleWorld;
|
||||
|
||||
class Trigger extends GameObject {
|
||||
var id:Float;
|
||||
var level:MarbleWorld;
|
||||
var element:MissionElementTrigger;
|
||||
|
||||
public var collider:BoxCollisionEntity;
|
||||
|
||||
public function new(element:MissionElementTrigger, level:MarbleWorld) {
|
||||
super();
|
||||
this.element = element;
|
||||
this.id = element._id;
|
||||
this.level = level;
|
||||
var coordinates = MisParser.parseNumberList(element.polyhedron);
|
||||
|
||||
var origin = new Vector(coordinates[0], coordinates[1], coordinates[2]);
|
||||
var d1 = new Vector(coordinates[3], coordinates[4], coordinates[5]);
|
||||
var d2 = new Vector(coordinates[6], coordinates[7], coordinates[8]);
|
||||
var d3 = new Vector(coordinates[9], coordinates[10], coordinates[11]);
|
||||
|
||||
// Create the 8 points of the parallelepiped
|
||||
var p1 = origin.clone();
|
||||
var p2 = origin.add(d1);
|
||||
var p3 = origin.add(d2);
|
||||
var p4 = origin.add(d3);
|
||||
var p5 = origin.add(d1).add(d2);
|
||||
var p6 = origin.add(d1).add(d3);
|
||||
var p7 = origin.add(d2).add(d3);
|
||||
var p8 = origin.add(d1).add(d2).add(d3);
|
||||
|
||||
var mat = new Matrix();
|
||||
var quat = MisParser.parseRotation(element.rotation);
|
||||
quat.toMatrix(mat);
|
||||
mat.setPosition(MisParser.parseVector3(element.position));
|
||||
var scale = MisParser.parseVector3(element.scale);
|
||||
mat.scale(scale.x, scale.y, scale.z);
|
||||
|
||||
var vertices = [p1, p2, p3, p4, p5, p6, p7, p8].map((vert) -> vert.transformed(mat));
|
||||
|
||||
var boundingbox = new Bounds();
|
||||
for (vector in vertices) {
|
||||
boundingbox.addPoint(vector.toPoint());
|
||||
}
|
||||
|
||||
collider = new BoxCollisionEntity(boundingbox, this);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue