fix a lot of things, camera (attempt), improve pathedinteriors scalability, touch support things, spectator mode mobile camera

This commit is contained in:
RandomityGuy 2024-07-12 00:38:10 +05:30
parent 3964b43aca
commit e216be4ec9
18 changed files with 383 additions and 216 deletions

View file

@ -127,12 +127,20 @@ class CameraController extends Object {
public function enableSpectate() {
spectate = true;
@:privateAccess this.level.playGui.setSpectateMenu(true);
if (@:privateAccess this.level.playGui.setSpectateMenu(true)) {
if (Util.isTouchDevice()) {
MarbleGame.instance.touchInput.setSpectatorControls(true);
MarbleGame.instance.touchInput.setSpectatorControlsVisibility(false);
}
}
}
public function stopSpectate() {
spectate = false;
@:privateAccess this.level.playGui.setSpectateMenu(false);
if (Util.isTouchDevice()) {
MarbleGame.instance.touchInput.setSpectatorControls(false);
}
}
public function orbit(mouseX:Float, mouseY:Float, isTouch:Bool = false) {
@ -163,7 +171,7 @@ class CameraController extends Object {
}
var factor = isTouch ? Util.lerp(1 / 25, 1 / 15,
Settings.controlsSettings.cameraSensitivity) : Util.lerp(1 / 2500, 1 / 100, Settings.controlsSettings.cameraSensitivity);
Settings.controlsSettings.cameraSensitivity) : Util.lerp(1 / 1000, 1 / 200, Settings.controlsSettings.cameraSensitivity);
// CameraPitch += deltaposY * factor;
// CameraYaw += deltaposX * factor;
@ -264,8 +272,8 @@ class CameraController extends Object {
nextCameraPitch = Math.max(-Math.PI / 2 + Math.PI / 4, Math.min(Math.PI / 2 - 0.0001, nextCameraPitch));
CameraYaw = Util.lerp(CameraYaw, nextCameraYaw, lerpt);
CameraPitch = Util.lerp(CameraPitch, nextCameraPitch, lerpt);
CameraYaw = nextCameraYaw; // Util.lerp(CameraYaw, nextCameraYaw, lerpt);
CameraPitch = nextCameraPitch; // Util.lerp(CameraPitch, nextCameraPitch, lerpt);
CameraPitch = Math.max(-Math.PI / 2 + Math.PI / 4, Math.min(Math.PI / 2 - 0.0001, CameraPitch)); // Util.clamp(CameraPitch, -Math.PI / 12, Math.PI / 2);
@ -331,7 +339,7 @@ class CameraController extends Object {
if (MarbleGame.instance.touchInput.movementInput.pressed) {
dx = -MarbleGame.instance.touchInput.movementInput.value.x * CameraSpeed * dt;
dy = MarbleGame.instance.touchInput.movementInput.value.y * CameraSpeed * dt;
dy = -MarbleGame.instance.touchInput.movementInput.value.y * CameraSpeed * dt;
}
if ((!Util.isTouchDevice() && Key.isDown(Settings.controlsSettings.powerup))
@ -342,10 +350,12 @@ class CameraController extends Object {
}
if (Key.isPressed(Settings.controlsSettings.blast)
|| (MarbleGame.instance.touchInput.blastbutton.pressed)
|| (MarbleGame.instance.touchInput.blastbutton.pressed && MarbleGame.instance.touchInput.blastbutton.didPressIt)
|| Gamepad.isPressed(Settings.gamepadSettings.blast)) {
var freeMarbleIndex = -1;
MarbleGame.instance.touchInput.blastbutton.didPressIt = false;
for (i in 0...level.marbles.length) {
var marble = level.marbles[i];
@:privateAccess if ((marble.connection != null && !marble.connection.spectator)) {
@ -354,6 +364,7 @@ class CameraController extends Object {
}
}
spectateMarbleIndex = freeMarbleIndex;
MarbleGame.instance.touchInput.setSpectatorControlsVisibility(true);
return;
}
@ -366,7 +377,9 @@ class CameraController extends Object {
camera.target = camera.pos.add(directionVector);
} else {
@:privateAccess level.playGui.setSpectateMenuText(1);
if (Key.isPressed(Settings.controlsSettings.left)) {
if (Key.isPressed(Settings.controlsSettings.left)
|| (MarbleGame.instance.touchInput.leftButton.pressed && MarbleGame.instance.touchInput.leftButton.didPressIt)) {
MarbleGame.instance.touchInput.leftButton.didPressIt = false;
spectateMarbleIndex = (spectateMarbleIndex - 1 + level.marbles.length) % level.marbles.length;
@:privateAccess while (level.marbles[spectateMarbleIndex].connection == null
|| level.marbles[spectateMarbleIndex].connection.spectator) {
@ -374,7 +387,9 @@ class CameraController extends Object {
}
}
if (Key.isPressed(Settings.controlsSettings.right)) {
if (Key.isPressed(Settings.controlsSettings.right)
|| (MarbleGame.instance.touchInput.rightButton.pressed && MarbleGame.instance.touchInput.rightButton.didPressIt)) {
MarbleGame.instance.touchInput.rightButton.didPressIt = false;
spectateMarbleIndex = (spectateMarbleIndex + 1 + level.marbles.length) % level.marbles.length;
@:privateAccess while (level.marbles[spectateMarbleIndex].connection == null
|| level.marbles[spectateMarbleIndex].connection.spectator) {
@ -383,9 +398,16 @@ class CameraController extends Object {
}
if (Key.isPressed(Settings.controlsSettings.blast)
|| (MarbleGame.instance.touchInput.blastbutton.pressed)
|| (MarbleGame.instance.touchInput.blastbutton.pressed && MarbleGame.instance.touchInput.blastbutton.didPressIt)
|| Gamepad.isPressed(Settings.gamepadSettings.blast)) {
MarbleGame.instance.touchInput.blastbutton.didPressIt = false;
spectateMarbleIndex = -1;
MarbleGame.instance.touchInput.setSpectatorControlsVisibility(false);
return;
}
if (@:privateAccess level.marbles.length <= spectateMarbleIndex) {
spectateMarbleIndex = -1;
MarbleGame.instance.touchInput.setSpectatorControlsVisibility(false);
return;
}
@ -479,7 +501,8 @@ class CameraController extends Object {
var camera = level.scene.camera;
var lerpt = Math.pow(0.5, dt / 0.032); // Math.min(1, 1 - Math.pow(0.6, dt / 0.032)); // hxd.Math.min(1, 1 - Math.pow(0.6, dt * 600));
var lerpt = hxd.Math.min(1,
1 - Math.pow(0.6, dt * 600)); // Math.min(1, 1 - Math.pow(0.6, dt / 0.032)); // hxd.Math.min(1, 1 - Math.pow(0.6, dt * 600));
var cameraPitchDelta = (Key.isDown(Settings.controlsSettings.camBackward) ? 1 : 0)
- (Key.isDown(Settings.controlsSettings.camForward) ? 1 : 0)
@ -495,8 +518,8 @@ class CameraController extends Object {
nextCameraPitch = Math.max(-Math.PI / 2 + Math.PI / 4, Math.min(Math.PI / 2 - 0.0001, nextCameraPitch));
CameraYaw = Util.lerp(CameraYaw, nextCameraYaw, lerpt);
CameraPitch = Util.lerp(CameraPitch, nextCameraPitch, lerpt);
CameraYaw = nextCameraYaw; // Util.lerp(CameraYaw, nextCameraYaw, lerpt);
CameraPitch = nextCameraPitch; // Util.lerp(CameraPitch, nextCameraPitch, lerpt);
CameraPitch = Math.max(-Math.PI / 2 + Math.PI / 4, Math.min(Math.PI / 2 - 0.0001, CameraPitch)); // Util.clamp(CameraPitch, -Math.PI / 12, Math.PI / 2);

View file

@ -579,6 +579,38 @@ class DtsObject extends GameObject {
hs.restitution = data.restitution;
}
var drawType = primitive.matIndex & TSDrawPrimitive.TypeMask;
if (drawType == TSDrawPrimitive.Triangles) {
var i = primitive.firstElement;
while (i < primitive.firstElement + primitive.numElements) {
var i1 = dtsMesh.indices[i];
var i2 = dtsMesh.indices[i + 1];
var i3 = dtsMesh.indices[i + 2];
var t1 = vertices[i2].sub(vertices[i1]);
var t2 = vertices[i3].sub(vertices[i1]);
var tarea = Math.abs(t1.cross(t2).length()) / 2.0;
if (tarea < 0.00001)
continue;
for (index in [i1, i2, i3]) {
var vertex = vertices[index];
hs.addPoint(vertex.x, vertex.y, vertex.z);
hs.transformKeys.push(0);
var normal = vertexNormals[index];
hs.addNormal(normal.x, normal.y, normal.z);
}
hs.indices.push(hs.indices.length);
hs.indices.push(hs.indices.length);
hs.indices.push(hs.indices.length);
i += 3;
}
} else if (drawType == TSDrawPrimitive.Strip) {
var k = 0;
for (i in primitive.firstElement...(primitive.firstElement + primitive.numElements - 2)) {
var i1 = dtsMesh.indices[i];
var i2 = dtsMesh.indices[i + 1];
@ -591,6 +623,12 @@ class DtsObject extends GameObject {
i3 = temp;
}
var t1 = vertices[i2].sub(vertices[i1]);
var t2 = vertices[i3].sub(vertices[i1]);
var tarea = Math.abs(t1.cross(t2).length()) / 2.0;
if (tarea < 0.00001)
continue;
for (index in [i1, i2, i3]) {
var vertex = vertices[index];
hs.addPoint(vertex.x, vertex.y, vertex.z);
@ -606,6 +644,35 @@ class DtsObject extends GameObject {
k++;
}
} else if (drawType == TSDrawPrimitive.Fan) {
var i = primitive.firstElement;
while (i < primitive.firstElement + primitive.numElements - 2) {
var i1 = dtsMesh.indices[primitive.firstElement];
var i2 = dtsMesh.indices[i + 1];
var i3 = dtsMesh.indices[i + 2];
var t1 = vertices[i2].sub(vertices[i1]);
var t2 = vertices[i3].sub(vertices[i1]);
var tarea = Math.abs(t1.cross(t2).length()) / 2.0;
if (tarea < 0.00001)
continue;
for (index in [i1, i2, i3]) {
var vertex = vertices[index];
hs.addPoint(vertex.x, vertex.y, vertex.z);
hs.transformKeys.push(0);
var normal = vertexNormals[index];
hs.addNormal(normal.x, normal.y, normal.z);
}
hs.indices.push(hs.indices.length);
hs.indices.push(hs.indices.length);
hs.indices.push(hs.indices.length);
i++;
}
}
hs.generateBoundingBox();
ent.addSurface(hs);

View file

@ -1276,6 +1276,8 @@ class Marble extends GameObject {
if (obj.go != null && !obj.go.isCollideable)
continue;
var isDts = obj.go is DtsObject;
var invMatrix = @:privateAccess obj.invTransform;
if (obj.go is PathedInterior)
invMatrix = obj.transform.getInverse();
@ -1338,6 +1340,7 @@ class Marble extends GameObject {
// var vT = v.transformed(obj.transform);
// var v2T = v2.transformed(obj.transform);
// var vN = surfaceNormal.transformed3x3(obj.transform);
if (!isDts)
testTriangles.push({
v: [v0.clone(), v.clone(), v2.clone()],
n: surfaceNormal.clone(),

View file

@ -224,9 +224,9 @@ class MarbleWorld extends Scheduler {
public var currentInputMoves:Array<InputRecorderFrame>;
// Multiplayer
public var isMultiplayer:Bool;
public var isMultiplayer:Bool = false;
public var serverStartTicks:Int;
public var serverStartTicks:Int = 0;
public var startTime:Float = 1e8;
public var multiplayerStarted:Bool = false;
@ -2762,6 +2762,7 @@ class MarbleWorld extends Scheduler {
// this.oobCameraPosition = camera.position.clone();
if (marble == this.marble) {
playGui.setCenterText('outofbounds');
if (@:privateAccess !this.marble.isNetUpdate)
AudioManager.playSound(ResourceLoader.getResource('data/sound/whoosh.wav', ResourceLoader.getAudio, this.soundResources));
// if (this.replay.mode != = 'playback')
this.oobSchedule = this.schedule(this.timeState.currentAttemptTime + 2, () -> {

View file

@ -59,6 +59,7 @@ class PathedInterior extends InteriorObject {
var savedVelocity:Vector;
var savedStopped:Bool;
var savedStoppedPosition:Vector;
var savedInvPosition:Vector;
var savedTime:Float;
var soundChannel:Channel;
@ -115,7 +116,14 @@ class PathedInterior extends InteriorObject {
this.markerData = this.path.markers.map(x -> {
var marker = new PathedInteriorMarker();
marker.msToNext = MisParser.parseNumber(x.mstonext) / 1000;
marker.smoothingType = x.smoothingtype;
marker.smoothingType = switch (x.smoothingtype) {
case "Accelerate":
PathedInteriorMarker.SMOOTHING_ACCELERATE;
case "Spline":
PathedInteriorMarker.SMOOTHING_SPLINE;
default:
PathedInteriorMarker.SMOOTHING_LINEAR;
};
marker.position = MisParser.parseVector3(x.position);
marker.position.x = -marker.position.x;
marker.rotation = MisParser.parseRotation(x.rotation);
@ -214,9 +222,10 @@ class PathedInterior extends InteriorObject {
return;
if (this.velocity.length() == 0)
return;
static var tform = new Matrix();
velocity.w = 0;
var newp = position.add(velocity.multiply(timeDelta));
var tform = this.getAbsPos().clone();
tform.load(this.getAbsPos()); // .clone();
tform.setPosition(newp);
if (this.isCollideable) {
@ -251,6 +260,7 @@ class PathedInterior extends InteriorObject {
public function pushTickState() {
savedPosition = this.position.clone();
savedInvPosition = @:privateAccess this.collider.invTransform.getPosition();
savedVelocity = this.velocity.clone();
savedStopped = this.stopped;
savedStoppedPosition = this.stoppedPosition != null ? this.stoppedPosition.clone() : null;
@ -262,7 +272,17 @@ class PathedInterior extends InteriorObject {
this.velocity.load(savedVelocity);
this.stopped = savedStopped;
this.stoppedPosition = savedStoppedPosition;
var oldtPos = this.collider.transform.getPosition();
this.collider.transform.setPosition(savedPosition);
@:privateAccess this.collider.invTransform.setPosition(savedInvPosition);
this.collider.boundingBox.xMin += savedPosition.x - oldtPos.x;
this.collider.boundingBox.xMax += savedPosition.x - oldtPos.x;
this.collider.boundingBox.yMin += savedPosition.y - oldtPos.y;
this.collider.boundingBox.yMax += savedPosition.y - oldtPos.y;
this.collider.boundingBox.zMin += savedPosition.z - oldtPos.z;
this.collider.boundingBox.zMax += savedPosition.z - oldtPos.z;
collisionWorld.updateTransform(this.collider);
this.currentTime = savedTime;
@ -301,7 +321,8 @@ class PathedInterior extends InteriorObject {
if (m1 == null) {
// Incase there are no markers at all
var tmp = new Matrix();
var mat = Matrix.S(this.baseScale.x, this.baseScale.y, this.baseScale.z);
var mat = new Matrix();
mat.initScale(this.baseScale.x, this.baseScale.y, this.baseScale.z);
this.baseOrientation.toMatrix(tmp);
mat.multiply3x4(mat, tmp);
mat.setPosition(this.basePosition);
@ -324,10 +345,10 @@ class PathedInterior extends InteriorObject {
var duration = m2Time - m1Time;
var position:Vector = null;
var compvarion = Util.clamp(duration != 0 ? (time - m1Time) / duration : 1, 0, 1);
if (m1.smoothingType == "Accelerate") {
if (m1.smoothingType == PathedInteriorMarker.SMOOTHING_ACCELERATE) {
// A simple easing function
compvarion = Math.sin(compvarion * Math.PI - (Math.PI / 2)) * 0.5 + 0.5;
} else if (m1.smoothingType == "Spline") {
} else if (m1.smoothingType == PathedInteriorMarker.SMOOTHING_SPLINE) {
// Smooth the path like it's a Catmull-Rom spline.
var preStart = (i - 2) - 1;
var postEnd = (i - 1) + 1;
@ -355,7 +376,8 @@ class PathedInterior extends InteriorObject {
position = position.add(basePosition); // Add the base position
var tmp = new Matrix();
var mat = Matrix.S(this.baseScale.x, this.baseScale.y, this.baseScale.z);
var mat = new Matrix();
mat.initScale(this.baseScale.x, this.baseScale.y, this.baseScale.z);
this.baseOrientation.toMatrix(tmp);
mat.multiply3x4(mat, tmp);
mat.setPosition(position);

View file

@ -5,10 +5,14 @@ import h3d.Vector;
class PathedInteriorMarker {
public var msToNext:Float;
public var smoothingType:String;
public var smoothingType:Int;
public var position:Vector;
public var rotation:Quat;
public static var SMOOTHING_LINEAR = 0;
public static var SMOOTHING_ACCELERATE = 1;
public static var SMOOTHING_SPLINE = 2;
public function new() {}
public function clone() {

View file

@ -11,6 +11,7 @@ class Renderer extends h3d.scene.Renderer {
super();
defaultPass = new h3d.pass.Default("default");
allPasses = [defaultPass, shadow];
shadow.enabled = false;
}
inline function get_def()

View file

@ -146,110 +146,14 @@ class Collision {
}
public static inline function TriangleSphereIntersection(v0:Vector, v1:Vector, v2:Vector, N:Vector, P:Vector, r:Float, point:Vector, normal:Vector) {
var A = v0.sub(P);
var B = v1.sub(P);
var C = v2.sub(P);
var ca = C.sub(A);
var ba = B.sub(A);
var radiusSq = r * r;
var cp = ba.cross(ca);
var aDotCp = A.dot(cp);
var cpLenSq = cp.lengthSq();
if (aDotCp * aDotCp > radiusSq * cpLenSq) {
return false;
}
var aSq = A.dot(A);
var aDotB = A.dot(B);
var aDotC = A.dot(C);
var bSq = B.dot(B);
var bDotC = B.dot(C);
var cSq = C.dot(C);
if (aSq > radiusSq && aDotB > aSq && aDotC > aSq) {
return false;
}
if (bSq > radiusSq && aDotB > bSq && bDotC > bSq) {
return false;
}
if (cSq > radiusSq && aDotC > cSq && bDotC > cSq) {
return false;
}
var cSubB = C.sub(B);
var aSubC = A.sub(C);
var baSq = ba.lengthSq();
var cSubBSq = cSubB.lengthSq();
var aSubCSq = aSubC.lengthSq();
var aTest = A.multiply(baSq).sub(ba.multiply(aDotB - aSq));
var bTest = B.multiply(cSubBSq).sub(cSubB.multiply(bDotC - bSq));
var cTest = C.multiply(aSubCSq).sub(aSubC.multiply(aDotC - cSq));
var rhs = C.multiply(baSq).sub(aTest);
var rhs2 = A.multiply(cSubBSq).sub(bTest);
var rhs3 = B.multiply(aSubCSq).sub(cTest);
if (aTest.dot(aTest) > radiusSq * baSq * baSq && aTest.dot(rhs) > 0) {
return false;
}
if (bTest.dot(bTest) > radiusSq * cSubBSq * cSubBSq && bTest.dot(rhs2) > 0) {
return false;
}
if (cTest.dot(cTest) > radiusSq * aSubCSq * aSubCSq && cTest.dot(rhs3) > 0) {
return false;
}
var lhs = P.sub(v0);
var baca = ba.dot(ca);
var caSq = ca.lengthSq();
var lhsBa = lhs.dot(ba);
var lhsCa = lhs.dot(ca);
var len = baSq * caSq - baca * baca;
var d1 = (caSq * lhsBa - baca * lhsCa) / len;
var d2 = (baSq * lhsCa - baca * lhsBa) / len;
if (1 - d1 - d2 >= 0 && d1 >= 0 && d2 >= 0) {
normal.load(N);
point.load(P.sub(N.multiply(P.sub(v0).dot(N))));
ClosestPtPointTriangle(P, v0, v1, v2, point);
var v = point.sub(P);
if (v.dot(v) <= r * r) {
normal.load(P.sub(point));
normal.normalize();
return true;
} else {
var closestPt = P.sub(N.multiply(P.sub(v0).dot(N)));
var r1 = ClosestPointLine(v0, v1, closestPt);
var r2 = ClosestPointLine(v1, v2, closestPt);
var r3 = ClosestPointLine(v2, v0, closestPt);
var chosenEdge = 0; // Bitfield
var chosenPt:Vector = new Vector();
if (r1.distanceSq(P) < r2.distanceSq(P)) {
chosenPt.load(r1);
chosenEdge = 1;
} else {
chosenPt.load(r2);
chosenEdge = 2;
}
if (chosenPt.distanceSq(P) < r3.distanceSq(P))
point.load(chosenPt);
else {
chosenEdge = 4;
point.load(r3);
}
normal.load(P.sub(point).normalized());
return true;
// if (res.normal.dot(N) > 0.8) {
// // Internal edge
// if (chosenEdge & edgeData > 0) {
// chosenEdge -= 1;
// if (chosenEdge > 2)
// chosenEdge--;
// // if (edgeNormals[chosenEdge].length() < 0.5) {
// // res.normal = center.sub(res.point).normalized();
// // } else
// if (edgeConcavities[chosenEdge]) { // Our edge is concave
// res.normal = N.clone();
// }
// }
// }
return false;
}
}
@ -431,38 +335,65 @@ class Collision {
return null;
}
public static function ClosestPtPointTriangle(pt:Vector, radius:Float, p0:Vector, p1:Vector, p2:Vector, normal:Vector) {
var closest:Vector = null;
var ptDot = pt.dot(normal);
var triDot = p0.dot(normal);
if (Math.abs(ptDot - triDot) > radius * 1.1) {
return null;
public static inline function ClosestPtPointTriangle(p:Vector, a:Vector, b:Vector, c:Vector, outP:Vector) {
// Check if P in vertex region outside A
var ab = b.sub(a);
var ac = c.sub(a);
var ap = p.sub(a);
var d1 = ab.dot(ap);
var d2 = ac.dot(ap);
if (d1 <= 0.0 && d2 <= 0.0) { // barycentric coordinates (1,0,0)
outP.load(a);
return;
}
closest = pt.add(normal.multiply(triDot - ptDot));
if (Collision.PointInTriangle2(closest, p0, p1, p2)) {
return closest;
// Check if P in vertex region outside B
var bp = p.sub(b);
var d3 = ab.dot(bp);
var d4 = ac.dot(bp);
if (d3 >= 0.0 && d4 <= d3) { // barycentric coordinates (0,1,0
outP.load(b);
return;
}
var t = 10.0;
var r1 = Collision.IntersectSegmentCapsule(pt, pt, p0, p1, radius);
if (r1.result && r1.tSeg < t) {
closest = p0.add((p1.sub(p0).multiply(r1.tCap)));
t = r1.tSeg;
// Check if P in edge region of AB, if so return projection of P onto AB
var vc = d1 * d4 - d3 * d2;
if (vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0) {
var v = d1 / (d1 - d3);
outP.load(a.add(ab.multiply(v)));
return;
}
var r2 = Collision.IntersectSegmentCapsule(pt, pt, p1, p2, radius);
if (r2.result && r2.tSeg < t) {
closest = p1.add((p2.sub(p1).multiply(r2.tCap)));
t = r2.tSeg;
// Check if P in vertex region outside C
var cp = p.sub(c);
var d5 = ab.dot(cp);
var d6 = ac.dot(cp);
if (d6 >= 0.0 && d5 <= d6) { // barycentric coordinates (0,0,1)
outP.load(c);
return;
}
var r3 = Collision.IntersectSegmentCapsule(pt, pt, p2, p0, radius);
if (r3.result && r3.tSeg < t) {
closest = p2.add((p2.sub(p2).multiply(r3.tCap)));
t = r3.tSeg;
// Check if P in edge region of AC, if so return projection of P onto AC
var vb = d5 * d2 - d1 * d6;
if (vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0) {
var w = d2 / (d2 - d6);
outP.load(a.add(ac.multiply(w)));
return;
}
var res = t < 1;
if (res) {
return closest;
// Check if P in edge region of BC, if so return projection of P onto BC
var va = d3 * d6 - d5 * d4;
if (va <= 0.0 && (d4 - d3) >= 0.0 && (d5 - d6) >= 0.0) {
var w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
outP.load(b.add((c.sub(b)).multiply(w)));
return;
}
return null;
// P inside face region. Compute Q through its barycentric coordinates (u,v,w)
var denom = 1.0 / (va + vb + vc);
var v = vb * denom;
var w = vc * denom;
outP.load(a.add(ab.multiply(v)).add(ac.multiply(w)));
return;
}
public static function capsuleSphereNearestOverlap(a0:Vector, a1:Vector, radA:Float, b:Vector, radB:Float) {

View file

@ -96,26 +96,39 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
if (this.transform.equal(transform))
return;
// Speedup
// if (this.fastTransform && Util.mat3x3equal(this.transform, transform)) {
// var oldPos = this.transform.getPosition();
// var newPos = transform.getPosition();
// this.transform.setPosition(newPos);
// this.invTransform = this.transform.getInverse();
// if (this.boundingBox == null)
// generateBoundingBox();
// else {
// this.boundingBox.xMin += newPos.x - oldPos.x;
// this.boundingBox.xMax += newPos.x - oldPos.x;
// this.boundingBox.yMin += newPos.y - oldPos.y;
// this.boundingBox.yMax += newPos.y - oldPos.y;
// this.boundingBox.zMin += newPos.z - oldPos.z;
// this.boundingBox.zMax += newPos.z - oldPos.z;
// }
// } else {
if (this.fastTransform && Util.mat3x3equal(this.transform, transform)) {
var oldPos = this.transform.getPosition();
var newPos = transform.getPosition();
this.transform.setPosition(newPos);
this.invTransform.prependTranslation(oldPos.x - newPos.x, oldPos.y - newPos.y, oldPos.z - newPos.z);
if (this.boundingBox == null)
generateBoundingBox();
else {
this.boundingBox.xMin += newPos.x - oldPos.x;
this.boundingBox.xMax += newPos.x - oldPos.x;
this.boundingBox.yMin += newPos.y - oldPos.y;
this.boundingBox.yMax += newPos.y - oldPos.y;
this.boundingBox.zMin += newPos.z - oldPos.z;
this.boundingBox.zMax += newPos.z - oldPos.z;
if (Debug.drawBounds) {
if (_dbgEntity == null) {
_dbgEntity = cast this.boundingBox.makeDebugObj();
_dbgEntity.getMaterials()[0].mainPass.wireframe = true;
MarbleGame.instance.scene.addChild(_dbgEntity);
} else {
_dbgEntity.remove();
_dbgEntity = cast this.boundingBox.makeDebugObj();
_dbgEntity.getMaterials()[0].mainPass.wireframe = true;
MarbleGame.instance.scene.addChild(_dbgEntity);
}
}
}
} else {
this.transform.load(transform);
this.invTransform = transform.getInverse();
generateBoundingBox();
// }
}
_transformKey++;
}

View file

@ -168,11 +168,11 @@ class MPPreGameDlg extends GuiControl {
};
dialogImg.addChild(levelName);
var levelDesc = new GuiText(markerFelt18);
var levelDesc = new GuiMLText(markerFelt18, null);
levelDesc.text.textColor = 0xFFFFFF;
levelDesc.position = new Vector(60, 185);
levelDesc.extent = new Vector(516, 63);
levelDesc.text.text = MarbleGame.instance.world.mission.description;
levelDesc.text.text = StringTools.htmlEscape(MarbleGame.instance.world.mission.description);
levelDesc.text.dropShadow = {
dx: 1,
dy: 1,
@ -244,8 +244,8 @@ class MPPreGameDlg extends GuiControl {
ready: Net.lobbyHostReady,
spectate: Net.hostSpectate
});
spectateBtn.pressed = Net.hostSpectate;
readyBtn.pressed = Net.lobbyHostReady;
spectateBtn.anim.currentFrame = Net.hostSpectate ? 2 : 0;
readyBtn.anim.currentFrame = Net.lobbyHostReady ? 2 : 0;
}
if (Net.isClient) {
playerListArr.push({
@ -253,8 +253,8 @@ class MPPreGameDlg extends GuiControl {
ready: Net.lobbyClientReady,
spectate: Net.clientSpectate
});
spectateBtn.pressed = Net.clientSpectate;
readyBtn.pressed = Net.lobbyClientReady;
spectateBtn.anim.currentFrame = Net.clientSpectate ? 2 : 0;
readyBtn.anim.currentFrame = Net.lobbyClientReady ? 2 : 0;
}
if (Net.clientIdMap != null) {
for (c => v in Net.clientIdMap) {

View file

@ -346,8 +346,8 @@ class OptionsDlg extends GuiImage {
makeSlider("Field of View:", (Settings.optionsSettings.fovX - 60) / (140 - 60), yPos, generalPanel, (val) -> {
Settings.optionsSettings.fovX = cast(60 + val * (140 - 60));
});
makeSlider("Mouse Speed:", (Settings.controlsSettings.cameraSensitivity - 0.2) / (3 - 0.2), yPos, generalPanel, (val) -> {
Settings.controlsSettings.cameraSensitivity = cast(0.2 + val * (3 - 0.2));
makeSlider("Mouse Speed:", (Settings.controlsSettings.cameraSensitivity - 0.12) / (1.2 - 0.12), yPos, generalPanel, (val) -> {
Settings.controlsSettings.cameraSensitivity = cast(0.12 + val * (1.2 - 0.12));
}, true);
function getConflictingBinding(bindingName:String, key:Int) {

View file

@ -225,7 +225,7 @@ class PlayGui {
}
if (Util.isTouchDevice()) {
MarbleGame.instance.touchInput.showControls(this.playGuiCtrl, game == 'ultra');
MarbleGame.instance.touchInput.showControls(this.playGuiCtrl, game == 'ultra' || MarbleGame.instance.world.isMultiplayer);
}
playGuiCtrl.render(scene2d);
@ -592,6 +592,10 @@ class PlayGui {
}
public function setBlastValue(value:Float) {
if (Net.clientSpectate || Net.hostSpectate) {
MarbleGame.instance.touchInput.blastbutton.setEnabled(true);
return; // Is not changed
}
if (value <= 1) {
if (blastFill.extent.y == 16) { // Was previously charged
blastFrame.bmp.tile = ResourceLoader.getResource("data/ui/game/blastbar.png", ResourceLoader.getImage, this.imageResources).toTile();
@ -862,9 +866,10 @@ class PlayGui {
public function setSpectateMenu(enabled:Bool) {
if (enabled && spectatorCtrl == null) {
initSpectatorMenu();
playGuiCtrl.render(MarbleGame.canvas.scene2d);
spectatorCtrl.render(MarbleGame.canvas.scene2d, @:privateAccess playGuiCtrl._flow);
blastFill.bmp.visible = false;
blastFrame.bmp.visible = false;
return true;
}
if (!enabled && spectatorCtrl != null) {
spectatorCtrl.dispose();
@ -872,7 +877,9 @@ class PlayGui {
blastFill.bmp.visible = true;
blastFrame.bmp.visible = true;
spectatorTxtMode = -1;
return true;
}
return false;
}
public function setSpectateMenuText(mode:Int) {

View file

@ -550,10 +550,6 @@ class HuntMode extends NullMode {
var beam = gemToBeamMap.get(gem);
beam.setHide(true);
if (!this.level.isMultiplayer || Net.isHost) {
spawnHuntGems();
}
var incr = 0;
switch (gem.gemColor.toLowerCase()) {
case "red.gem":
@ -641,6 +637,9 @@ class HuntMode extends NullMode {
if (this.level.isMultiplayer && Net.isClient) {
gem.pickUpClient = @:privateAccess marble.connection == null ? Net.clientId : @:privateAccess marble.connection.id;
}
if (!this.level.isMultiplayer || Net.isHost) {
spawnHuntGems();
}
}
public function setCompetitiveTimerStartTicks(ticks:Int) {

View file

@ -8,10 +8,16 @@ import src.ResourceLoader;
import src.Settings;
class BlastButton extends TouchButton {
public var didPressIt:Bool = true;
public function new() {
var mode = MarbleGame.instance.world != null ? @:privateAccess MarbleGame.instance.world.marble.camera.spectate : false;
super(ResourceLoader.getImage(mode ? "data/ui/touch/video-camera.png" : "data/ui/touch/explosion.png").resource,
new Vector(Settings.touchSettings.blastButtonPos[0], Settings.touchSettings.blastButtonPos[1]), Settings.touchSettings.blastButtonSize);
this.setEnabled(false);
this.onClick = () -> {
this.pressed = true;
didPressIt = true;
}
}
}

View file

@ -87,9 +87,9 @@ class CameraInput {
if (jumpcam) {
scaleFactor /= Settings.touchSettings.buttonJoystickMultiplier;
}
if (Math.abs(delta.x) < 0.03)
if (Math.abs(delta.x) < 0.05)
delta.x = 0;
if (Math.abs(delta.y) < 0.03)
if (Math.abs(delta.y) < 0.05)
delta.y = 0;
MarbleGame.instance.world.marble.camera.orbit(applyNonlinearScale(delta.x / scaleFactor), applyNonlinearScale(delta.y / scaleFactor), true);
if (delta.x != 0)

View file

@ -12,7 +12,7 @@ class PauseButton extends TouchButton {
this.guiElement.vertSizing = Bottom;
this.onClick = () -> {
if (MarbleGame.instance.world != null) {
if (MarbleGame.instance.world != null && @:privateAccess !MarbleGame.instance.paused) {
@:privateAccess MarbleGame.instance.paused = true;
MarbleGame.instance.handlePauseGame();
}

View file

@ -0,0 +1,25 @@
package touch;
import src.MarbleGame;
import touch.TouchInput.Touch;
import h3d.Vector;
import hxd.Window;
import src.ResourceLoader;
import src.Settings;
class SpectatorChangeTargetButton extends TouchButton {
public var didPressIt:Bool = true;
public function new(rightFacing:Bool) {
super(ResourceLoader.getImage(rightFacing ? "data/ui/touch/right.png" : "data/ui/touch/left.png").resource, new Vector(rightFacing ? 560 : 70, 120),
60);
if (!rightFacing) {
this.guiElement.horizSizing = Right;
}
this.setEnabled(false);
this.onClick = () -> {
this.pressed = true;
didPressIt = true;
}
}
}

View file

@ -4,6 +4,8 @@ import gui.GuiControl;
import src.MarbleWorld;
import h3d.Vector;
import src.Settings;
import src.MarbleGame;
import src.ResourceLoader;
enum TouchState {
Pressed;
@ -44,6 +46,8 @@ class TouchInput {
public var pauseButton:PauseButton;
public var rewindButton:RewindButton;
public var restartButton:RestartButton;
public var leftButton:SpectatorChangeTargetButton;
public var rightButton:SpectatorChangeTargetButton;
public var currentTouchState:TouchEventState;
@ -118,17 +122,19 @@ class TouchInput {
this.movementInput = new MovementInput();
this.jumpButton = new JumpButton();
this.powerupButton = new PowerupButton();
if (Settings.optionsSettings.rewindEnabled)
if (Settings.optionsSettings.rewindEnabled && !MarbleGame.instance.world.isMultiplayer)
this.rewindButton = new RewindButton();
if (ultra)
this.blastbutton = new BlastButton();
this.pauseButton = new PauseButton();
if (!MarbleGame.instance.world.isMultiplayer)
this.restartButton = new RestartButton();
pauseButton.add(parentGui);
if (!MarbleGame.instance.world.isMultiplayer)
restartButton.add(parentGui);
jumpButton.add(parentGui);
powerupButton.add(parentGui);
if (Settings.optionsSettings.rewindEnabled)
if (Settings.optionsSettings.rewindEnabled && !MarbleGame.instance.world.isMultiplayer)
rewindButton.add(parentGui);
if (ultra)
blastbutton.add(parentGui);
@ -147,6 +153,10 @@ class TouchInput {
this.restartButton.setVisible(false);
if (this.rewindButton != null)
this.rewindButton.setVisible(false);
if (this.leftButton != null)
this.leftButton.setVisible(false);
if (this.rightButton != null)
this.rightButton.setVisible(false);
}
}
@ -157,10 +167,15 @@ class TouchInput {
this.blastbutton.setVisible(enabled);
this.movementInput.setVisible(enabled);
this.pauseButton.setVisible(enabled);
if (this.restartButton != null)
this.restartButton.setVisible(enabled);
if (this.rewindButton != null)
this.rewindButton.setVisible(enabled);
this.cameraInput.enabled = enabled;
if (this.leftButton != null)
this.leftButton.setVisible(enabled);
if (this.rightButton != null)
this.rightButton.setVisible(enabled);
if (Settings.touchSettings.hideControls) {
this.jumpButton.setVisible(false);
@ -170,6 +185,10 @@ class TouchInput {
this.movementInput.setVisible(false);
if (this.rewindButton != null)
this.rewindButton.setVisible(false);
if (this.leftButton != null)
this.leftButton.setVisible(false);
if (this.rightButton != null)
this.rightButton.setVisible(false);
}
}
@ -180,10 +199,19 @@ class TouchInput {
blastbutton.remove(parentGui);
movementInput.remove(parentGui);
pauseButton.remove(parentGui);
if (this.restartButton != null)
restartButton.remove(parentGui);
cameraInput.remove(parentGui);
if (this.rewindButton != null)
rewindButton.remove(parentGui);
if (this.leftButton != null) {
leftButton.remove(parentGui);
leftButton.dispose();
}
if (this.rightButton != null) {
rightButton.remove(parentGui);
rightButton.dispose();
}
jumpButton.dispose();
powerupButton.dispose();
movementInput.dispose();
@ -193,4 +221,41 @@ class TouchInput {
if (this.rewindButton != null)
rewindButton.dispose();
}
public function setSpectatorControls(enabled:Bool) {
var tile = ResourceLoader.getImage(enabled ? "data/ui/touch/video-camera.png" : "data/ui/touch/explosion.png").resource;
@:privateAccess this.blastbutton.guiElement.graphics.content.state.tail.texture = tile.toTexture();
if (enabled) {
jumpButton.setVisible(false);
if (this.leftButton == null) { // both are added at same time so it doesnt matter
var par = jumpButton.guiElement.parent;
this.leftButton = new SpectatorChangeTargetButton(false);
this.rightButton = new SpectatorChangeTargetButton(true);
this.leftButton.add(par);
this.rightButton.add(par);
this.leftButton.guiElement.render(MarbleGame.canvas.scene2d, @:privateAccess par._flow);
this.rightButton.guiElement.render(MarbleGame.canvas.scene2d, @:privateAccess par._flow);
}
} else {
jumpButton.setVisible(true);
if (this.leftButton != null) {
this.leftButton.remove(this.leftButton.guiElement.parent);
this.leftButton.dispose();
this.leftButton = null;
}
if (this.rightButton != null) {
this.rightButton.remove(this.rightButton.guiElement.parent);
this.rightButton.dispose();
this.rightButton = null;
}
}
}
public function setSpectatorControlsVisibility(enabled:Bool) {
if (this.leftButton != null) {
this.leftButton.setVisible(enabled);
this.rightButton.setVisible(enabled);
this.movementInput.setVisible(!enabled);
}
}
}