From 51349ed423addca1edd5b8dc767c95ab9b67fe7a Mon Sep 17 00:00:00 2001 From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com> Date: Wed, 28 Jun 2023 01:12:36 +0530 Subject: [PATCH] finally implement marble picker --- data/missions/special/marblepicker.dif | Bin 0 -> 9209 bytes data/missions/special/marblepicker.mis | 97 ++++++++ src/DtsObject.hx | 10 +- src/InteriorObject.hx | 11 +- src/Marble.hx | 107 ++++---- src/MarbleGame.hx | 6 +- src/PathedInterior.hx | 1 + src/PreviewWorld.hx | 70 +++++- src/collision/CollisionWorld.hx | 6 + src/gui/MarblePickerGui.hx | 327 +++++++++++++++++++++++++ src/gui/OptionsListGui.hx | 2 +- 11 files changed, 577 insertions(+), 60 deletions(-) create mode 100644 data/missions/special/marblepicker.dif create mode 100644 data/missions/special/marblepicker.mis create mode 100644 src/gui/MarblePickerGui.hx diff --git a/data/missions/special/marblepicker.dif b/data/missions/special/marblepicker.dif new file mode 100644 index 0000000000000000000000000000000000000000..82575bed220b717c32401d264c49dd11ec5f9bfb GIT binary patch literal 9209 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 literal 0 HcmV?d00001 diff --git a/data/missions/special/marblepicker.mis b/data/missions/special/marblepicker.mis new file mode 100644 index 00000000..f7e0e511 --- /dev/null +++ b/data/missions/special/marblepicker.mis @@ -0,0 +1,97 @@ +//--- OBJECT WRITE BEGIN --- +new SimGroup(MissionGroup) { + + new ScriptObject(MissionInfo) { + desc = "MarblePicker"; + type = "advanced"; + gameType = "Special"; + level = "99"; + time = "10000"; + isInDemoMode = "1"; + include = "1"; + difficulty = "1"; + name = "MarblePicker"; + guid = "{05E97996-657C-45B2-A39E-C6BCC6160D8F}"; + }; + new MissionArea(MissionArea) { + area = "-360 -648 720 1296"; + flightCeiling = "300"; + flightCeilingRange = "20"; + locked = "true"; + }; + new Sky(Sky) { + position = "336 136 0"; + rotation = "1 0 0 0"; + scale = "1 1 1"; + hidden = "0"; + materialList = "~/data/skies/sky_beginner.dml"; + cloudHeightPer[0] = "0"; + cloudHeightPer[1] = "0"; + cloudHeightPer[2] = "0"; + cloudSpeed1 = "0.0001"; + cloudSpeed2 = "0.0002"; + cloudSpeed3 = "0.0003"; + visibleDistance = "1500"; + fogDistance = "1000"; + fogColor = "0.600000 0.600000 0.600000 1.000000"; + fogStorm1 = "0"; + fogStorm2 = "0"; + fogStorm3 = "0"; + fogVolume1 = "-1 7.45949e-031 1.3684e-038"; + fogVolume2 = "-1 1.07208e-014 8.756e-014"; + fogVolume3 = "-1 5.1012e-010 2.05098e-008"; + windVelocity = "1 0 0"; + windEffectPrecipitation = "0"; + SkySolidColor = "0.600000 0.600000 0.600000 1.000000"; + useSkyTextures = "1"; + renderBottomTexture = "1"; + noRenderBans = "1"; + renderBanOffsetHeight = "50"; + skyGlow = "0"; + skyGlowColor = "0.000000 0.000000 0.000000 0.000000"; + fogVolumeColor3 = "128.000000 128.000000 128.000000 14435505.000000"; + fogVolumeColor1 = "128.000000 128.000000 128.000000 0.000000"; + fogVolumeColor2 = "128.000000 128.000000 128.000000 0.000004"; + }; + new Sun() { + direction = "-0.614021 0.433884 -0.659336"; + color = "1.400000 1.200000 0.400000 1.000000"; + ambient = "0.440000 0.440000 0.440000 1.000000"; + shadowColor = "0.000000 0.000000 0.150000 0.350000"; + }; + new StaticShape() { + position = "0 0 -600"; + rotation = "1 0 0 0"; + scale = "1 1 1"; + hidden = "0"; + dataBlock = "astrolabeShape"; + }; + new InteriorInstance() { + position = "0 0 0"; + rotation = "1 0 0 0"; + scale = "1 1 1"; + hidden = "0"; + interiorFile = "./marblepicker.dif"; + showTerrainInside = "0"; + }; + new SpawnSphere() { + position = "0 -2 -1"; + rotation = "1 0 0 0"; + scale = "1 1 1"; + dataBlock = "CameraSpawnSphereMarker"; + radius = "1"; + sphereWeight = "100"; + indoorWeight = "100"; + outdoorWeight = "100"; + }; + new Trigger(Bounds) { + position = "-5.5 7.5 -4"; + rotation = "1 0 0 0"; + scale = "11 15 22"; + hidden = "0"; + dataBlock = "InBoundsTrigger"; + polyhedron = "0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 -1.0000000 0.0000000 0.0000000 0.0000000 1.0000000"; + }; +}; +//--- OBJECT WRITE END --- + diff --git a/src/DtsObject.hx b/src/DtsObject.hx index 6d50afa9..220d95c5 100644 --- a/src/DtsObject.hx +++ b/src/DtsObject.hx @@ -1,5 +1,6 @@ package src; +import collision.CollisionWorld; import shaders.EnvMap; import h3d.shader.CubeMap; import dts.TSDrawPrimitive; @@ -85,6 +86,7 @@ class DtsObject extends GameObject { var dtsResource:Resource; var level:MarbleWorld; + var collisionWorld:CollisionWorld; var materials:Array = []; var materialInfos:Map> = new Map(); @@ -135,8 +137,10 @@ class DtsObject extends GameObject { this.dts.importSequences(this.sequencePath); this.directoryPath = Path.directory(this.dtsPath); - if (level != null) + if (level != null) { this.level = level; + this.collisionWorld = this.level.collisionWorld; + } isInstanced = false; if (this.level != null) @@ -1099,7 +1103,7 @@ class DtsObject extends GameObject { super.setTransform(mat); if (this.isBoundingBoxCollideable) { this.boundingCollider.setTransform(mat); - this.level.collisionWorld.updateTransform(this.boundingCollider); + this.collisionWorld.updateTransform(this.boundingCollider); } for (i in 0...this.dirtyTransforms.length) { this.dirtyTransforms[i] = true; @@ -1447,7 +1451,7 @@ class DtsObject extends GameObject { var absTform = this.graphNodes[this.colliders[i].userData].getAbsPos().clone(); if (this.colliders[i] != null) { this.colliders[i].setTransform(absTform); - this.level.collisionWorld.updateTransform(this.colliders[i]); + this.collisionWorld.updateTransform(this.colliders[i]); } } } diff --git a/src/InteriorObject.hx b/src/InteriorObject.hx index a63f711f..5358af91 100644 --- a/src/InteriorObject.hx +++ b/src/InteriorObject.hx @@ -1,5 +1,6 @@ package src; +import collision.CollisionWorld; import src.MarbleWorld; import src.DifBuilder; import h3d.Matrix; @@ -12,6 +13,7 @@ class InteriorObject extends GameObject { public var interiorFile:String; public var useInstancing = true; public var level:MarbleWorld; + public var collisionWorld:CollisionWorld; public function new() { super(); @@ -21,13 +23,16 @@ class InteriorObject extends GameObject { public function init(level:MarbleWorld, onFinish:Void->Void) { this.identifier = this.interiorFile; this.level = level; + if (this.level != null) + this.collisionWorld = this.level.collisionWorld; DifBuilder.loadDif(this.interiorFile, cast this, onFinish, -1, this.isCollideable); } public override function setTransform(transform:Matrix) { super.setTransform(transform); - collider.setTransform(transform); - if (level != null) - this.level.collisionWorld.updateTransform(this.collider); + if (this.isCollideable) { + collider.setTransform(transform); + collisionWorld.updateTransform(this.collider); + } } } diff --git a/src/Marble.hx b/src/Marble.hx index 612176fa..df5ae605 100644 --- a/src/Marble.hx +++ b/src/Marble.hx @@ -192,6 +192,7 @@ class Marble extends GameObject { public var omega:Vector; public var level:MarbleWorld; + public var collisionWorld:CollisionWorld; public var _radius = 0.2; @@ -315,8 +316,10 @@ class Marble extends GameObject { public function init(level:MarbleWorld, onFinish:Void->Void) { this.level = level; + if (this.level != null) + this.collisionWorld = this.level.collisionWorld; - var isUltra = level.mission.game.toLowerCase() == "ultra"; + var isUltra = true; var marbleDts = new DtsObject(); Console.log("Marble: " + Settings.optionsSettings.marbleModel + " (" + Settings.optionsSettings.marbleSkin + ")"); @@ -332,7 +335,8 @@ class Marble extends GameObject { // mat.mainPass.culling = None; if (Settings.optionsSettings.reflectiveMarble) { - this.cubemapRenderer = new CubemapRenderer(level.scene, level.sky); + var csky = level != null ? level.sky : (@:privateAccess MarbleGame.instance.previewWorld.sky); + this.cubemapRenderer = new CubemapRenderer(MarbleGame.instance.scene, csky); if (Settings.optionsSettings.marbleShader == null || Settings.optionsSettings.marbleShader == "Default" @@ -342,8 +346,7 @@ class Marble extends GameObject { } else { // Generate tangents for next shaders, only for Ultra for (node in marbleDts.graphNodes) { - for (ch in node.children) { - var chmesh = cast(ch, Mesh); + for (chmesh in node.getMeshes()) { var chpoly = cast(chmesh.primitive, mesh.Polygon); chpoly.addTangents(); } @@ -483,10 +486,14 @@ class Marble extends GameObject { this.helicopter.z = 1e8; this.helicopter.scale(0.3 / 0.2); - var worker = new ResourceLoaderWorker(onFinish); - worker.addTask(fwd -> level.addDtsObject(this.helicopter, fwd)); - worker.addTask(fwd -> level.addDtsObject(this.blastWave, fwd)); - worker.run(); + if (this.controllable) { + var worker = new ResourceLoaderWorker(onFinish); + worker.addTask(fwd -> level.addDtsObject(this.helicopter, fwd)); + worker.addTask(fwd -> level.addDtsObject(this.blastWave, fwd)); + worker.run(); + } else { + onFinish(); + } } function findContacts(collisiomWorld:CollisionWorld, timeState:TimeState) { @@ -502,28 +509,34 @@ class Marble extends GameObject { public function getMarbleAxis() { var motiondir = new Vector(0, -1, 0); - motiondir.transform(Matrix.R(0, 0, camera.CameraYaw)); - motiondir.transform(level.newOrientationQuat.toMatrix()); - var updir = this.level.currentUp; - var sidedir = motiondir.cross(updir); + if (this.controllable) { + motiondir.transform(Matrix.R(0, 0, camera.CameraYaw)); + motiondir.transform(level.newOrientationQuat.toMatrix()); + var updir = this.level.currentUp; + var sidedir = motiondir.cross(updir); - sidedir.normalize(); - motiondir = updir.cross(sidedir); - return [sidedir, motiondir, updir]; + sidedir.normalize(); + motiondir = updir.cross(sidedir); + return [sidedir, motiondir, updir]; + } else { + return [new Vector(1, 0, 0), motiondir, new Vector(0, 0, 1)]; + } } function getExternalForces(currentTime:Float, m:Move, dt:Float) { if (this.mode == Finish) return this.velocity.multiply(-16); - var gWorkGravityDir = this.level.currentUp.multiply(-1); + var gWorkGravityDir = this.level != null ? this.level.currentUp.multiply(-1) : new Vector(0, 0, -1); var A = new Vector(); A = gWorkGravityDir.multiply(this._gravity); if (currentTime - this.helicopterEnableTime < 5) { A = A.multiply(0.25); } - for (obj in level.forceObjects) { - var force = cast(obj, ForceObject).getForce(this.collider.transform.getPosition()); - A = A.add(force.multiply(1 / _mass)); + if (this.level != null) { + for (obj in level.forceObjects) { + var force = cast(obj, ForceObject).getForce(this.collider.transform.getPosition()); + A = A.add(force.multiply(1 / _mass)); + } } if (contacts.length != 0 && this.mode != Start) { var contactForce = 0.0; @@ -575,7 +588,7 @@ class Marble extends GameObject { } function computeMoveForces(m:Move, aControl:Vector, desiredOmega:Vector) { - var currentGravityDir = this.level.currentUp.multiply(-1); + var currentGravityDir = this.level != null ? this.level.currentUp.multiply(-1) : new Vector(0, 0, -1); var R = currentGravityDir.multiply(-this._radius); var rollVelocity = this.omega.cross(R); var axes = this.getMarbleAxis(); @@ -751,7 +764,7 @@ class Marble extends GameObject { function applyContactForces(dt:Float, m:Move, isCentered:Bool, aControl:Vector, desiredOmega:Vector, A:Vector) { var a = new Vector(); this._slipAmount = 0; - var gWorkGravityDir = this.level.currentUp.multiply(-1); + var gWorkGravityDir = this.level != null ? this.level.currentUp.multiply(-1) : new Vector(0, 0, -1); var bestSurface = -1; var bestNormalForce = 0.0; for (i in 0...contacts.length) { @@ -852,6 +865,8 @@ class Marble extends GameObject { } function bounceEmitter(speed:Float, normal:Vector) { + if (!this.controllable) + return; if (this.bounceEmitDelay == 0 && this._minBounceSpeed <= speed) { this.level.particleManager.createEmitter(bounceParticleOptions, this.bounceEmitterData, this.collider.transform.getPosition().sub(normal.multiply(_radius)), null, new Vector(1, 1, 1).add(normal.multiply(-0.8))); @@ -1002,7 +1017,7 @@ class Marble extends GameObject { searchbox.addSpherePos(position.x, position.y, position.z, _radius); searchbox.addSpherePos(position.x + velocity.x * deltaT, position.y + velocity.y * deltaT, position.z + velocity.z * deltaT, _radius); - var foundObjs = this.level.collisionWorld.boundingSearch(searchbox); + var foundObjs = this.collisionWorld.boundingSearch(searchbox); var finalT = deltaT; var found = false; @@ -1339,7 +1354,7 @@ class Marble extends GameObject { var position = this.collider.transform.getPosition(); - var foundObjs = this.level.collisionWorld.boundingSearch(searchbox); + var foundObjs = this.collisionWorld.boundingSearch(searchbox); // var foundObjs = this.contactEntities; function toDifPoint(vec:Vector) { @@ -1758,14 +1773,14 @@ class Marble extends GameObject { } } - if (this.level.isWatching) { + if (this.controllable && this.level.isWatching) { if (this.level.replay.currentPlaybackFrame.marbleStateFlags.has(Jumped)) move.jump = true; if (this.level.replay.currentPlaybackFrame.marbleStateFlags.has(UsedPowerup)) move.powerup = true; move.d = new Vector(this.level.replay.currentPlaybackFrame.marbleX, this.level.replay.currentPlaybackFrame.marbleY, 0); } else { - if (this.level.isRecording) { + if (this.controllable && this.level.isRecording) { this.level.replay.recordMarbleStateFlags(move.jump, move.powerup, false, false); this.level.replay.recordMarbleInput(move.d.x, move.d.y); } @@ -1774,27 +1789,29 @@ class Marble extends GameObject { playedSounds = []; advancePhysics(timeState, move, collisionWorld, pathedInteriors); - if (!this.level.isWatching) { - if (this.level.isRecording) { - this.level.replay.recordMarbleState(this.getAbsPos().getPosition(), this.velocity, this.getRotationQuat(), this.omega); + if (this.controllable) { + if (!this.level.isWatching) { + if (this.level.isRecording) { + this.level.replay.recordMarbleState(this.getAbsPos().getPosition(), this.velocity, this.getRotationQuat(), this.omega); + } + } else { + var expectedPos = this.level.replay.currentPlaybackFrame.marblePosition.clone(); + var expectedVel = this.level.replay.currentPlaybackFrame.marbleVelocity.clone(); + var expectedOmega = this.level.replay.currentPlaybackFrame.marbleAngularVelocity.clone(); + + this.setPosition(expectedPos.x, expectedPos.y, expectedPos.z); + var tform = this.level.replay.currentPlaybackFrame.marbleOrientation.toMatrix(); + + tform.setPosition(new Vector(expectedPos.x, expectedPos.y, expectedPos.z)); + this.collider.setTransform(tform); + this.velocity = expectedVel; + var rQuat = this.level.replay.currentPlaybackFrame.marbleOrientation.clone(); + this.setRotationQuat(rQuat); + this.omega = expectedOmega; } - } else { - var expectedPos = this.level.replay.currentPlaybackFrame.marblePosition.clone(); - var expectedVel = this.level.replay.currentPlaybackFrame.marbleVelocity.clone(); - var expectedOmega = this.level.replay.currentPlaybackFrame.marbleAngularVelocity.clone(); - - this.setPosition(expectedPos.x, expectedPos.y, expectedPos.z); - var tform = this.level.replay.currentPlaybackFrame.marbleOrientation.toMatrix(); - - tform.setPosition(new Vector(expectedPos.x, expectedPos.y, expectedPos.z)); - this.collider.setTransform(tform); - this.velocity = expectedVel; - var rQuat = this.level.replay.currentPlaybackFrame.marbleOrientation.clone(); - this.setRotationQuat(rQuat); - this.omega = expectedOmega; } - if (this.controllable && !this.level.rewinding) { + if (this.controllable && this.level != null && !this.level.rewinding) { this.camera.update(timeState.currentAttemptTime, timeState.dt); } @@ -1922,6 +1939,8 @@ class Marble extends GameObject { } public function updatePowerupStates(currentTime:Float, dt:Float) { + if (!this.controllable) + return; if (currentTime - this.helicopterEnableTime < 5) { this.helicopter.setPosition(x, y, z); this.helicopter.setRotationQuat(this.level.getOrientationQuat(currentTime)); @@ -1939,6 +1958,8 @@ class Marble extends GameObject { } public function getMass() { + if (this.level == null) + return 1; if (this.level.timeState.currentAttemptTime - this.megaMarbleEnableTime < 10) { return 5; } else { diff --git a/src/MarbleGame.hx b/src/MarbleGame.hx index cac1e486..f08d556e 100644 --- a/src/MarbleGame.hx +++ b/src/MarbleGame.hx @@ -324,14 +324,16 @@ class MarbleGame { previewWorld.destroyAllObjects(); } - public function setPreviewMission(misname:String, onFinish:() -> Void) { + public function setPreviewMission(misname:String, onFinish:() -> Void, physics:Bool = false) { Console.log("Setting preview mission " + misname); - previewWorld.loadMission(misname, onFinish); + previewWorld.loadMission(misname, onFinish, physics); } public function render(e:h3d.Engine) { if (world != null && !world._disposed) world.render(e); + if (previewWorld != null && world == null) + previewWorld.render(e); canvas.renderEngine(e); } } diff --git a/src/PathedInterior.hx b/src/PathedInterior.hx index 2eba450e..020a8bad 100644 --- a/src/PathedInterior.hx +++ b/src/PathedInterior.hx @@ -57,6 +57,7 @@ class PathedInterior extends InteriorObject { onFinish(null); var pathedInterior = new PathedInterior(); pathedInterior.level = level; + pathedInterior.collisionWorld = level.collisionWorld; DifBuilder.loadDif(difFile, pathedInterior, () -> { pathedInterior.identifier = difFile + interiorElement.interiorindex; diff --git a/src/PreviewWorld.hx b/src/PreviewWorld.hx index 4778471e..830bc082 100644 --- a/src/PreviewWorld.hx +++ b/src/PreviewWorld.hx @@ -1,5 +1,6 @@ package src; +import collision.CollisionWorld; import mis.MissionElement.MissionElementSky; import shapes.Astrolabe; import src.Sky; @@ -49,10 +50,12 @@ import src.Console; import src.TimeState; import src.MissionList; import src.Settings; +import src.Marble; class PreviewWorld extends Scheduler { var scene:Scene; var instanceManager:InstanceManager; + var collisionWorld:CollisionWorld; var misFile:MisFile; var currentMission:String; @@ -63,6 +66,7 @@ class PreviewWorld extends Scheduler { var interiors:Array = []; var dtsObjects:Array = []; + var marbles:Array = []; var sky:Sky; @@ -126,18 +130,22 @@ class PreviewWorld extends Scheduler { } } - public function loadMission(misname:String, onFinish:() -> Void) { + public function loadMission(misname:String, onFinish:() -> Void, physics:Bool = false) { if (currentMission == misname) { onFinish(); return; } _loadToken++; - currentMission = misname; var groupName = (misname + "group").toLowerCase(); var group = levelGroups.get(groupName); if (group != null) { destroyAllObjects(); + this.currentMission = misname; this.instanceManager = new InstanceManager(scene); + if (physics) + this.collisionWorld = new CollisionWorld(); + else + this.collisionWorld = null; var p = new h3d.prim.Cube(0.001, 0.001, 0.001); p.addUVs(); @@ -182,8 +190,12 @@ class PreviewWorld extends Scheduler { } } + var difficulty = "beginner"; var mis = MissionList.missionsFilenameLookup.get((misname + '.mis').toLowerCase()); - var difficulty = ["beginner", "intermediate", "advanced"][mis.difficultyIndex]; + if (misname == "marblepicker") + difficulty = "advanced"; + else + difficulty = ["beginner", "intermediate", "advanced"][mis.difficultyIndex]; var curToken = _loadToken; @@ -205,7 +217,7 @@ class PreviewWorld extends Scheduler { addInteriorFromMis(cast elem, curToken, () -> { itrAddTime += Console.time() - startTime; fwd(); - }); + }, physics); } }); } @@ -268,18 +280,23 @@ class PreviewWorld extends Scheduler { public function destroyAllObjects() { currentMission = null; + collisionWorld = null; for (itr in interiors) { itr.dispose(); } for (shape in dtsObjects) { shape.dispose(); } + for (marb in marbles) { + marb.dispose(); + } interiors = []; dtsObjects = []; + marbles = []; scene.removeChildren(); } - public function addInteriorFromMis(element:MissionElementInteriorInstance, token:Int, onFinish:Void->Void) { + public function addInteriorFromMis(element:MissionElementInteriorInstance, token:Int, onFinish:Void->Void, physics:Bool = false) { var difPath = getDifPath(element.interiorfile); if (difPath == "" || token != _loadToken) { onFinish(); @@ -288,6 +305,7 @@ class PreviewWorld extends Scheduler { Console.log('Adding interior: ${difPath}'); var interior = new InteriorObject(); interior.interiorFile = difPath; + interior.isCollideable = physics; // DifBuilder.loadDif(difPath, interior); // this.interiors.push(interior); this.addInterior(interior, token, () -> { @@ -315,12 +333,12 @@ class PreviewWorld extends Scheduler { mat.multiply(mat, tmat); interior.setTransform(mat); - interior.isCollideable = hasCollision; + interior.isCollideable = hasCollision && physics; onFinish(); - }); + }, physics); } - function addInterior(obj:InteriorObject, token:Int, onFinish:Void->Void) { + function addInterior(obj:InteriorObject, token:Int, onFinish:Void->Void, physics:Bool = false) { if (token != _loadToken) { onFinish(); return; @@ -335,6 +353,10 @@ class PreviewWorld extends Scheduler { this.instanceManager.addObject(obj); else this.scene.addChild(obj); + if (physics) { + this.collisionWorld.addEntity(obj.collider); + obj.collisionWorld = this.collisionWorld; + } onFinish(); }); } @@ -543,12 +565,44 @@ class PreviewWorld extends Scheduler { return ""; } + public function spawnMarble(onFinish:Marble->Void) { + var marb = new Marble(); + marb.controllable = false; + marb.init(null, () -> { + marb.collisionWorld = this.collisionWorld; + this.collisionWorld.addMovingEntity(marb.collider); + this.scene.addChild(marb); + this.marbles.push(marb); + onFinish(marb); + }); + } + + public function removeMarble(marb:Marble) { + if (this.marbles.remove(marb)) { + this.scene.removeChild(marb); + this.collisionWorld.removeMovingEntity(marb.collider); + marb.dispose(); + } + } + public function update(dt:Float) { timeState.dt = dt; timeState.timeSinceLoad += dt; for (dts in dtsObjects) { dts.update(timeState); } + for (marb in marbles) { + marb.update(timeState, this.collisionWorld, []); + } this.instanceManager.render(); } + + public function render(e:h3d.Engine) { + for (marble in marbles) { + if (marble != null && marble.cubemapRenderer != null) { + marble.cubemapRenderer.position.load(marble.getAbsPos().getPosition()); + marble.cubemapRenderer.render(e, 0.002); + } + } + } } diff --git a/src/collision/CollisionWorld.hx b/src/collision/CollisionWorld.hx index a65fa016..929a3b93 100644 --- a/src/collision/CollisionWorld.hx +++ b/src/collision/CollisionWorld.hx @@ -120,6 +120,12 @@ class CollisionWorld { this.dynamicEntitySet.set(entity, true); } + public function removeMovingEntity(entity:CollisionEntity) { + this.dynamicEntities.remove(entity); + this.dynamicOctree.remove(entity); + this.dynamicEntitySet.remove(entity); + } + public function updateTransform(entity:CollisionEntity) { if (!dynamicEntitySet.exists(entity)) { this.octree.update(entity); diff --git a/src/gui/MarblePickerGui.hx b/src/gui/MarblePickerGui.hx new file mode 100644 index 00000000..733e1952 --- /dev/null +++ b/src/gui/MarblePickerGui.hx @@ -0,0 +1,327 @@ +package gui; + +import src.Marble; +import src.MarbleGame; +import gui.GuiControl.MouseState; +import hxd.res.BitmapFont; +import h3d.Vector; +import src.ResourceLoader; +import src.Settings; + +class MarblePickerGui extends GuiImage { + public function new() { + var marbleData = [ + { + name: "1", + dts: "data/shapes/balls/marble01.dts", + skin: "base", + shader: "ClassicGlassPureSphere" + }, + { + name: "2", + dts: "data/shapes/balls/marble03.dts", + skin: "base", + shader: "ClassicGlassPureSphere" + }, + { + name: "3", + dts: "data/shapes/balls/marble04.dts", + skin: "base", + shader: "ClassicGlassPureSphere" + }, + { + name: "4", + dts: "data/shapes/balls/marble05.dts", + skin: "base", + shader: "ClassicGlassPureSphere" + }, + { + name: "5", + dts: "data/shapes/balls/marble06.dts", + skin: "base", + shader: "ClassicGlassPureSphere" + }, + { + name: "6", + dts: "data/shapes/balls/marble07.dts", + skin: "base", + shader: "ClassicGlassPureSphere" + }, + { + name: "7", + dts: "data/shapes/balls/marble12.dts", + skin: "base", + shader: "ClassicGlassPureSphere" + }, + { + name: "8", + dts: "data/shapes/balls/marble15.dts", + skin: "base", + shader: "ClassicGlassPureSphere" + }, + { + name: "9", + dts: "data/shapes/balls/marble02.dts", + skin: "base", + shader: "CrystalMarb" + }, + { + name: "10", + dts: "data/shapes/balls/marble26.dts", + skin: "base", + shader: "CrystalMarb" + }, + { + name: "11", + dts: "data/shapes/balls/marble27.dts", + skin: "base", + shader: "CrystalMarb" + }, + { + name: "12", + dts: "data/shapes/balls/marble28.dts", + skin: "base", + shader: "CrystalMarb" + }, + { + name: "13", + dts: "data/shapes/balls/marble29.dts", + skin: "base", + shader: "CrystalMarb" + }, + { + name: "14", + dts: "data/shapes/balls/marble30.dts", + skin: "base", + shader: "CrystalMarb" + }, + { + name: "15", + dts: "data/shapes/balls/marble11.dts", + skin: "base", + shader: "ClassicMetal" + }, + { + name: "16", + dts: "data/shapes/balls/marble18.dts", + skin: "base", + shader: "ClassicMarbGlass18" + }, + { + name: "17", + dts: "data/shapes/balls/marble20.dts", + skin: "base", + shader: "ClassicMarbGlass20" + }, + { + name: "18", + dts: "data/shapes/balls/marble33.dts", + skin: "base", + shader: "ClassicMetal" + }, + { + name: "19", + dts: "data/shapes/balls/marble34.dts", + skin: "base", + shader: "ClassicMarb2" + }, + { + name: "20", + dts: "data/shapes/balls/marble09.dts", + skin: "base", + shader: "ClassicMarb3" + }, + { + name: "21", + dts: "data/shapes/balls/marble13.dts", + skin: "base", + shader: "ClassicMarb3" + }, + { + name: "22", + dts: "data/shapes/balls/marble14.dts", + skin: "base", + shader: "ClassicMarb3" + }, + { + name: "23", + dts: "data/shapes/balls/marble17.dts", + skin: "base", + shader: "ClassicMarb3" + }, + { + name: "24", + dts: "data/shapes/balls/marble19.dts", + skin: "base", + shader: "ClassicMarb3" + }, + { + name: "25", + dts: "data/shapes/balls/marble21.dts", + skin: "base", + shader: "ClassicMarb3" + }, + { + name: "26", + dts: "data/shapes/balls/marble22.dts", + skin: "base", + shader: "ClassicMarb3" + }, + { + name: "27", + dts: "data/shapes/balls/marble23.dts", + skin: "base", + shader: "ClassicMarb3" + }, + { + name: "28", + dts: "data/shapes/balls/marble24.dts", + skin: "base", + shader: "ClassicMarb3" + }, + { + name: "29", + dts: "data/shapes/balls/marble25.dts", + skin: "base", + shader: "ClassicMarb3" + }, + { + name: "30", + dts: "data/shapes/balls/marble31.dts", + skin: "base", + shader: "ClassicMarb3" + }, + { + name: "31", + dts: "data/shapes/balls/marble32.dts", + skin: "base", + shader: "ClassicMarb3" + }, + { + name: "32", + dts: "data/shapes/balls/marble08.dts", + skin: "base", + shader: "ClassicMarb" + }, + { + name: "33", + dts: "data/shapes/balls/marble10.dts", + skin: "base", + shader: "ClassicMarb2" + }, + { + name: "34", + dts: "data/shapes/balls/marble16.dts", + skin: "base", + shader: "ClassicMarb3" + }, + { + name: "35", + dts: "data/shapes/balls/marble35.dts", + skin: "base", + shader: "ClassicMarb3" + } + ]; + + var res = ResourceLoader.getImage("data/ui/xbox/BG_fadeOutSoftEdge.png").resource.toTile(); + super(res); + var domcasual32fontdata = ResourceLoader.getFileEntry("data/font/DomCasualD.fnt"); + var domcasual32b = new BitmapFont(domcasual32fontdata.entry); + @:privateAccess domcasual32b.loader = ResourceLoader.loader; + var domcasual32 = domcasual32b.toSdfFont(cast 42 * Settings.uiScale, MultiChannel); + + this.horizSizing = Width; + this.vertSizing = Height; + this.position = new Vector(); + this.extent = new Vector(640, 480); + + var scene2d = MarbleGame.canvas.scene2d; + + var offsetX = (scene2d.width - 1280) / 2; + var offsetY = (scene2d.height - 720) / 2; + + var subX = 640 - (scene2d.width - offsetX) * 640 / scene2d.width; + var subY = 480 - (scene2d.height - offsetY) * 480 / scene2d.height; + + var innerCtrl = new GuiControl(); + innerCtrl.position = new Vector(offsetX, offsetY); + innerCtrl.extent = new Vector(640 - subX, 480 - subY); + innerCtrl.horizSizing = Width; + innerCtrl.vertSizing = Height; + this.addChild(innerCtrl); + + var coliseumfontdata = ResourceLoader.getFileEntry("data/font/ColiseumRR.fnt"); + var coliseumb = new BitmapFont(coliseumfontdata.entry); + @:privateAccess coliseumb.loader = ResourceLoader.loader; + var coliseum = coliseumb.toSdfFont(cast 44 * Settings.uiScale, MultiChannel); + + var rootTitle = new GuiText(coliseum); + rootTitle.position = new Vector(100, 30); + rootTitle.extent = new Vector(1120, 80); + rootTitle.text.textColor = 0xFFFFFF; + rootTitle.text.text = "SELECT MARBLE APPEARANCE"; + rootTitle.text.alpha = 0.5; + innerCtrl.addChild(rootTitle); + var myMarb:Marble = null; + + var prevPreview = @:privateAccess MarbleGame.instance.previewWorld.currentMission; + + MarbleGame.instance.setPreviewMission("marblepicker", () -> { + @:privateAccess MarbleGame.instance.previewWorld.spawnMarble(marb -> { + var spawnPos = @:privateAccess MarbleGame.instance.scene.camera.pos.add(new Vector(0, 1, 1)); + var velAdd = new Vector((1 - 2 * Math.random()) * 2, (1 - 2 * Math.random()) * 1.5, (1 - 2 * Math.random()) * 1); + velAdd = velAdd.add(new Vector(0, 3, 0)); + marb.setMarblePosition(spawnPos.x, spawnPos.y, spawnPos.z); + marb.velocity.load(velAdd); + myMarb = marb; + }); + }, true); + + var yPos = 160; + + var mbOpt = new GuiXboxOptionsList(1, "Marble Type", marbleData.map(x -> x.name), 0.5, 118); + mbOpt.vertSizing = Bottom; + mbOpt.horizSizing = Right; + mbOpt.alwaysActive = true; + mbOpt.position = new Vector(380, yPos); + mbOpt.extent = new Vector(815, 94); + mbOpt.onChangeFunc = (idx) -> { + var selectedMarble = marbleData[idx]; + Settings.optionsSettings.marbleIndex = idx; + Settings.optionsSettings.marbleCategoryIndex = 0; + Settings.optionsSettings.marbleSkin = selectedMarble.skin; + Settings.optionsSettings.marbleModel = selectedMarble.dts; + Settings.optionsSettings.marbleShader = selectedMarble.shader; + @:privateAccess MarbleGame.instance.previewWorld.removeMarble(myMarb); + @:privateAccess MarbleGame.instance.previewWorld.spawnMarble(marb -> { + var spawnPos = @:privateAccess MarbleGame.instance.scene.camera.pos.add(new Vector(0, 1, 1)); + var velAdd = new Vector((1 - 2 * Math.random()) * 2, (1 - 2 * Math.random()) * 1.5, (1 - 2 * Math.random()) * 1); + velAdd = velAdd.add(new Vector(0, 3, 0)); + marb.setMarblePosition(spawnPos.x, spawnPos.y, spawnPos.z); + marb.velocity.load(velAdd); + myMarb = marb; + }); + return true; + } + innerCtrl.addChild(mbOpt); + + var bottomBar = new GuiControl(); + bottomBar.position = new Vector(0, 590); + bottomBar.extent = new Vector(640, 200); + bottomBar.horizSizing = Width; + bottomBar.vertSizing = Bottom; + innerCtrl.addChild(bottomBar); + + var backButton = new GuiXboxButton("Ok", 160); + backButton.position = new Vector(960, 0); + backButton.vertSizing = Bottom; + backButton.horizSizing = Right; + backButton.gamepadAccelerator = ["OK"]; + backButton.pressedAction = (e) -> { + MarbleGame.canvas.setContent(new OptionsListGui()); + MarbleGame.instance.setPreviewMission(prevPreview, () -> {}, false); + }; + + bottomBar.addChild(backButton); + } +} diff --git a/src/gui/OptionsListGui.hx b/src/gui/OptionsListGui.hx index e823120e..e0210be4 100644 --- a/src/gui/OptionsListGui.hx +++ b/src/gui/OptionsListGui.hx @@ -55,7 +55,7 @@ class OptionsListGui extends GuiImage { innerCtrl.addChild(btnList); btnList.addButton(3, 'Marble Appearance', (e) -> { - MarbleGame.canvas.pushDialog(new MarbleSelectGui()); + MarbleGame.canvas.setContent(new MarblePickerGui()); }); btnList.addButton(3, 'Input and Sound Options', (e) -> { MarbleGame.canvas.setContent(new InputOptionsGui(pauseGui));