diff --git a/README.md b/README.md index 12ea7b1a..050ddae2 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,13 @@ Its currently a WIP at the time of writing. The marble physics code was taken fr Requires Haxe 4.2.2 You require the following Haxe libraries: - heaps: 1.9.1 (not the git version) with https://github.com/HeapsIO/heaps/pull/573 applied -- hlsdl (You will have to update it manually by replacing the files after doing the below steps) +- hlsdl (You will have to update it manually by replacing the files after doing the below steps) (Hashlink/C native target) +- stb_ogg_sound (JS/Browser target) -You also have to compile your own version of Hashlink with https://github.com/HaxeFoundation/hashlink/pull/444 applied +## Hashlink/Native +You have to compile your own version of Hashlink with https://github.com/HaxeFoundation/hashlink/pull/444 applied After all that has been setup, compile to hashlink by doing `haxe compile.hxml` and then running the game by `hl marblegame.hl` To compile to C, use the instructions in https://gist.github.com/Yanrishatum/d69ed72e368e35b18cbfca726d81279a +## Javascript/Browser +If the build dependencies are fullfilled, compile with `haxe compile-js.hxml` and run the game by running a web server in the same directory as the repo where index.html is located. \ No newline at end of file diff --git a/marblegame.hl b/marblegame.hl index 4f8b7e2a..331b7983 100644 Binary files a/marblegame.hl and b/marblegame.hl differ diff --git a/src/Marble.hx b/src/Marble.hx index 72e77704..2435f721 100644 --- a/src/Marble.hx +++ b/src/Marble.hx @@ -843,7 +843,6 @@ class Marble extends GameObject { // this.velocity = this.velocity.sub(A.multiply(diff)); // this.omega = this.omega.sub(a.multiply(diff)); timeStep = intersectT; - trace('CCD at ${intersectT}'); } var tempState = timeState.clone(); diff --git a/src/MarbleGame.hx b/src/MarbleGame.hx index 804c2f19..78ac4f8e 100644 --- a/src/MarbleGame.hx +++ b/src/MarbleGame.hx @@ -87,7 +87,7 @@ class MarbleGame { } public function handlePauseGame() { - if (paused) { + if (paused && world._ready) { world.setCursorLock(false); exitGameDlg = new ExitGameDlg((sender) -> { canvas.popDialog(exitGameDlg); @@ -120,10 +120,8 @@ class MarbleGame { ][(mission.index + 1) % 3]; AudioManager.playMusic(ResourceLoader.getAudio(musicFileName)); canvas.clearContent(); - mission.load(); world = new MarbleWorld(scene, scene2d, mission); world.init(); - world.start(); } public function render(e:h3d.Engine) { diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index 10d615ed..2801fec9 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -1,5 +1,6 @@ package src; +import gui.Canvas; import hxd.snd.Channel; import hxd.res.Sound; import src.ResourceLoader; @@ -75,6 +76,7 @@ class MarbleWorld extends Scheduler { public var particleManager:ParticleManager; var playGui:PlayGui; + var loadingGui:LoadingGui; public var interiors:Array = []; public var pathedInteriors:Array = []; @@ -118,11 +120,17 @@ class MarbleWorld extends Scheduler { var orientationChangeTime = -1e8; var oldOrientationQuat = new Quat(); + var resourceLoadFuncs:ArrayVoid> = []; + /** The new target camera orientation quat */ public var newOrientationQuat = new Quat(); public var _disposed:Bool = false; + public var _ready:Bool = false; + + var _loadingLength:Int = 0; + public function new(scene:Scene, scene2d:h2d.Scene, mission:Mission) { this.scene = scene; this.scene2d = scene2d; @@ -130,6 +138,13 @@ class MarbleWorld extends Scheduler { } public function init() { + initLoading(); + } + + public function initLoading() { + this.loadingGui = new LoadingGui(this.mission.title); + MarbleGame.canvas.setContent(this.loadingGui); + function scanMission(simGroup:MissionElementSimGroup) { for (element in simGroup.elements) { if ([ @@ -152,14 +167,24 @@ class MarbleWorld extends Scheduler { } } }; - scanMission(this.mission.root); - this.initScene(); - this.initMarble(); + this.resourceLoadFuncs.push(() -> { + this.addSimGroup(this.mission.root); + this._loadingLength = resourceLoadFuncs.length; + }); + this.resourceLoadFuncs.push(() -> this.initMarble()); + this.resourceLoadFuncs.push(() -> this.initScene()); + this.resourceLoadFuncs.push(() -> scanMission(this.mission.root)); + this.resourceLoadFuncs.push(() -> this.mission.load()); + this._loadingLength = resourceLoadFuncs.length; + } - this.addSimGroup(this.mission.root); + public function postInit() { + this._ready = true; + MarbleGame.canvas.clearContent(); this.endPad.generateCollider(); this.playGui.formatGemCounter(this.gemCount, this.totalGems); + start(); } public function initScene() { @@ -330,17 +355,19 @@ class MarbleWorld extends Scheduler { public function addSimGroup(simGroup:MissionElementSimGroup) { if (simGroup.elements.filter((element) -> element._type == MissionElementType.PathedInterior).length != 0) { // Create the pathed interior - var pathedInterior = src.PathedInterior.createFromSimGroup(simGroup, cast this); - this.addPathedInterior(pathedInterior); - if (pathedInterior == null) - return; + resourceLoadFuncs.push(() -> { + var pathedInterior = src.PathedInterior.createFromSimGroup(simGroup, cast this); + this.addPathedInterior(pathedInterior); + if (pathedInterior == null) + return; - // if (pathedInterior.hasCollision) - // this.physics.addInterior(pathedInterior); - for (trigger in pathedInterior.triggers) { - this.triggers.push(trigger); - this.collisionWorld.addEntity(trigger.collider); - } + // if (pathedInterior.hasCollision) + // this.physics.addInterior(pathedInterior); + for (trigger in pathedInterior.triggers) { + this.triggers.push(trigger); + this.collisionWorld.addEntity(trigger.collider); + } + }); return; } @@ -350,17 +377,17 @@ class MarbleWorld extends Scheduler { case MissionElementType.SimGroup: this.addSimGroup(cast element); case MissionElementType.InteriorInstance: - this.addInteriorFromMis(cast element); + resourceLoadFuncs.push(() -> this.addInteriorFromMis(cast element)); case MissionElementType.StaticShape: - this.addStaticShape(cast element); + resourceLoadFuncs.push(() -> this.addStaticShape(cast element)); case MissionElementType.Item: - this.addItem(cast element); + resourceLoadFuncs.push(() -> this.addItem(cast element)); case MissionElementType.Trigger: - this.addTrigger(cast element); + resourceLoadFuncs.push(() -> this.addTrigger(cast element)); case MissionElementType.TSStatic: - this.addTSStatic(cast element); + resourceLoadFuncs.push(() -> this.addTSStatic(cast element)); case MissionElementType.ParticleEmitterNode: - this.addParticleEmitterNode(cast element); + resourceLoadFuncs.push(() -> this.addParticleEmitterNode(cast element)); default: } } @@ -674,6 +701,9 @@ class MarbleWorld extends Scheduler { } public function update(dt:Float) { + if (!_ready) { + return; + } this.updateTimer(dt); this.tickSchedule(timeState.currentAttemptTime); this.updateGameState(); @@ -698,7 +728,22 @@ class MarbleWorld extends Scheduler { } public function render(e:h3d.Engine) { - this.playGui.render(e); + if (!_ready) + asyncLoadResources(); + if (this.playGui != null) + this.playGui.render(e); + } + + function asyncLoadResources() { + if (this.resourceLoadFuncs.length != 0) { + var func = this.resourceLoadFuncs.pop(); + func(); + this.loadingGui.setProgress((1 - resourceLoadFuncs.length / _loadingLength)); + MarbleGame.canvas.render(scene2d); + } else { + if (!_ready) + postInit(); + } } public function updateTimer(dt:Float) { @@ -1028,9 +1073,11 @@ class MarbleWorld extends Scheduler { public function setCursorLock(enabled:Bool) { this.cursorLock = enabled; if (enabled) { - this.marble.camera.lockCursor(); + if (this.marble != null) + this.marble.camera.lockCursor(); } else { - this.marble.camera.unlockCursor(); + if (this.marble != null) + this.marble.camera.unlockCursor(); } } diff --git a/src/Settings.hx b/src/Settings.hx index ee18acd8..0e246bf3 100644 --- a/src/Settings.hx +++ b/src/Settings.hx @@ -57,7 +57,10 @@ class Settings { shadows: false, musicVolume: 1, soundVolume: 0.7, - vsync: true + vsync: #if js true #end + #if hl + false + #end }; public static var controlsSettings:ControlsSettings = { @@ -156,7 +159,9 @@ class Settings { progression = json.progression; highscoreName = json.highscoreName; } + #if hl Window.getInstance().vsync = optionsSettings.vsync; + #end } public static function init() { diff --git a/src/gui/LoadingGui.hx b/src/gui/LoadingGui.hx index ab421496..88531055 100644 --- a/src/gui/LoadingGui.hx +++ b/src/gui/LoadingGui.hx @@ -1,12 +1,13 @@ package gui; +import hxd.res.BitmapFont; import h3d.Vector; import src.ResourceLoader; class LoadingGui extends GuiImage { public var setProgress:Float->Void; - public function new() { + public function new(missionName:String) { super(ResourceLoader.getImage("data/ui/background.jpg").toTile()); this.horizSizing = Width; this.vertSizing = Height; @@ -26,7 +27,16 @@ class LoadingGui extends GuiImage { return [normal, hover, pressed]; } - // TODO mapname + var domcasual32fontdata = ResourceLoader.getFileEntry("data/font/DomCasual32px.fnt"); + var domcasual32 = new BitmapFont(domcasual32fontdata.entry); + @:privateAccess domcasual32.loader = ResourceLoader.loader; + + var mapName = new GuiText(domcasual32); + mapName.position = new Vector(134, 78); + mapName.extent = new Vector(323, 32); + mapName.text.text = missionName; + mapName.text.textColor = 0; + mapName.justify = Center; var progress = new GuiProgress(); progress.vertSizing = Bottom; @@ -46,6 +56,7 @@ class LoadingGui extends GuiImage { overlay.position = new Vector(151, 131); overlay.extent = new Vector(278, 86); + loadingGui.addChild(mapName); loadingGui.addChild(progress); loadingGui.addChild(cancelButton); loadingGui.addChild(overlay);