diff --git a/src/CameraController.hx b/src/CameraController.hx index a7fc60a6..badb11f5 100644 --- a/src/CameraController.hx +++ b/src/CameraController.hx @@ -106,7 +106,7 @@ class CameraController extends Object { #end } - function orbit(mouseX:Float, mouseY:Float) { + public function orbit(mouseX:Float, mouseY:Float) { var scaleFactor = 1.0; #if js scaleFactor = 1 / js.Browser.window.devicePixelRatio; diff --git a/src/JSPlatform.hx b/src/JSPlatform.hx new file mode 100644 index 00000000..e189bd44 --- /dev/null +++ b/src/JSPlatform.hx @@ -0,0 +1,52 @@ +package src; + +import src.Util; + +class JSPlatform { + #if js + public static function initFullscreenEnforcer() { + var dislikesFullscreen = false; + var fullscreenEnforcer = js.Browser.document.querySelector("#fullscreen-enforcer"); + + fullscreenEnforcer.addEventListener('click', () -> { + js.Browser.document.documentElement.requestFullscreen(); + }); + + var enterFullscreenButton = js.Browser.document.querySelector("#enter-fullscreen"); + enterFullscreenButton.addEventListener('click', () -> { + js.Browser.document.documentElement.requestFullscreen(); + dislikesFullscreen = false; + }); + + var fullscreenButtonVisibility = true; + + var setEnterFullscreenButtonVisibility = (state:Bool) -> { + fullscreenButtonVisibility = state; + + if (state && Util.isTouchDevice() && !Util.isSafari() && !Util.isInFullscreen()) { + enterFullscreenButton.classList.remove('hidden'); + } else { + enterFullscreenButton.classList.add('hidden'); + } + } + + var lastImmunityTime = Math.NEGATIVE_INFINITY; + + js.Browser.window.setInterval(() -> { + if (js.Browser.document.activeElement != null) { + if (Util.isTouchDevice() && !Util.isSafari()) { + if (Util.isInFullscreen()) { + // They're in fullscreen, hide the overlay + fullscreenEnforcer.classList.add('hidden'); + } else if (!dislikesFullscreen && js.Browser.window.performance.now() - lastImmunityTime > 666) { + // They're not in fullscreen, show the overlay + fullscreenEnforcer.classList.remove('hidden'); + } + } + + setEnterFullscreenButtonVisibility(fullscreenButtonVisibility); + } + }, 250); + } + #end +} diff --git a/src/Main.hx b/src/Main.hx index 24a1c7e1..a0dd7849 100644 --- a/src/Main.hx +++ b/src/Main.hx @@ -1,5 +1,6 @@ package; +import src.Util; import src.ResourceLoader; #if js import fs.ManifestFileSystem; @@ -29,7 +30,7 @@ class Main extends hxd.App { hl.UI.closeConsole(); #end #if js - var zoomRatio = js.Browser.window.innerHeight * js.Browser.window.devicePixelRatio / 768; // js.Browser.window.devicePixelRatio; + var zoomRatio = Util.isTouchDevice() ? js.Browser.window.screen.height * js.Browser.window.devicePixelRatio / 600 : js.Browser.window.devicePixelRatio; // js.Browser.window.devicePixelRatio; s2d.scaleMode = Zoom(zoomRatio); #end ResourceLoader.init(s2d, () -> { diff --git a/src/MarbleGame.hx b/src/MarbleGame.hx index f47c9928..58ddba49 100644 --- a/src/MarbleGame.hx +++ b/src/MarbleGame.hx @@ -1,5 +1,6 @@ package src; +import touch.TouchInput; import src.ResourceLoader; import src.AudioManager; import gui.PlayMissionGui; @@ -10,7 +11,9 @@ import h3d.Vector; import gui.GuiControl.MouseState; import hxd.Window; import src.MarbleWorld; +import src.JSPlatform; import gui.Canvas; +import src.Util; @:publicFields class MarbleGame { @@ -27,14 +30,20 @@ class MarbleGame { var exitGameDlg:ExitGameDlg; + var touchInput:TouchInput; + public function new(scene2d:h2d.Scene, scene:h3d.scene.Scene) { canvas = new Canvas(scene2d, cast this); this.scene = scene; this.scene2d = scene2d; MarbleGame.instance = this; + this.touchInput = new TouchInput(); #if js // Pause shit + if (Util.isTouchDevice()) + this.touchInput.registerTouchInput(); + js.Browser.document.addEventListener('pointerlockchange', () -> { if (!paused && world != null) { if (world.finishTime == null && world._ready) { @@ -115,6 +124,7 @@ class MarbleGame { e.returnValue = ''; } }); + JSPlatform.initFullscreenEnforcer(); #end } @@ -124,6 +134,7 @@ class MarbleGame { world = null; return; } + touchInput.update(); if (!paused) { world.update(dt); } diff --git a/src/Settings.hx b/src/Settings.hx index a14a914b..bd4cc9c8 100644 --- a/src/Settings.hx +++ b/src/Settings.hx @@ -1,5 +1,6 @@ package src; +import haxe.ds.Option; import gui.Canvas; import src.AudioManager; import hxd.Key; @@ -11,6 +12,7 @@ import sys.io.File; #end import src.ResourceLoader; import haxe.Json; +import src.Util; typedef Score = { var name:String; @@ -90,6 +92,8 @@ class Settings { public static var zoomRatio = 1.0; + public static var isTouch:Option = Option.None; + public static function applySettings() { Window.getInstance().resize(optionsSettings.screenWidth, optionsSettings.screenHeight); Window.getInstance().displayMode = optionsSettings.isFullScreen ? FullscreenResize : Windowed; @@ -205,8 +209,7 @@ class Settings { var wnd = Window.getInstance(); var zoomRatio = 1.0; #if js - zoomRatio = js.Browser.window.innerHeight * js.Browser.window.devicePixelRatio / 600; // 768 / js.Browser.window.innerHeight; // js.Browser.window.innerHeight * js.Browser.window.devicePixelRatio / 768; - trace("zoomRatio: " + zoomRatio); + var zoomRatio = Util.isTouchDevice() ? js.Browser.window.screen.height * js.Browser.window.devicePixelRatio / 600 : js.Browser.window.devicePixelRatio; // 768 / js.Browser.window.innerHeight; // js.Browser.window.innerHeight * js.Browser.window.devicePixelRatio / 768; Settings.zoomRatio = zoomRatio; #end #if hl @@ -214,8 +217,12 @@ class Settings { Settings.optionsSettings.screenHeight = cast wnd.height / zoomRatio; #end #if js - Settings.optionsSettings.screenWidth = cast js.Browser.window.innerWidth * js.Browser.window.devicePixelRatio; // 1024; // cast(js.Browser.window.innerWidth / js.Browser.window.innerHeight) * 768; // cast js.Browser.window.innerWidth * js.Browser.window.devicePixelRatio * 0.5; - Settings.optionsSettings.screenHeight = cast js.Browser.window.innerHeight * js.Browser.window.devicePixelRatio; // 768; // cast js.Browser.window.innerHeight * js.Browser.window.devicePixelRatio * 0.5; + Settings.optionsSettings.screenWidth = cast js.Browser.window.screen.width * js.Browser.window.devicePixelRatio; // 1024; // cast(js.Browser.window.innerWidth / js.Browser.window.innerHeight) * 768; // cast js.Browser.window.innerWidth * js.Browser.window.devicePixelRatio * 0.5; + Settings.optionsSettings.screenHeight = cast js.Browser.window.screen.height * js.Browser.window.devicePixelRatio; // 768; // cast js.Browser.window.innerHeight * js.Browser.window.devicePixelRatio * 0.5; + + var canvasElement = js.Browser.document.getElementById("webgl"); + canvasElement.style.width = "100%"; + canvasElement.style.height = "100%"; #end MarbleGame.canvas.scene2d.scaleMode = Zoom(zoomRatio); diff --git a/src/Util.hx b/src/Util.hx index 16988326..0685387c 100644 --- a/src/Util.hx +++ b/src/Util.hx @@ -6,6 +6,7 @@ import h2d.Tile; import h3d.mat.Texture; import hxd.BitmapData; import h3d.Vector; +import src.Settings; class Util { public static function adjustedMod(a:Float, n:Float) { @@ -316,4 +317,50 @@ class Util { v.set(vresult_0, vresult_1, vresult_2); } + + public static function isTouchDevice() { + #if js + switch (Settings.isTouch) { + case None: + Settings.isTouch = Some(js.lib.Object.keys(js.Browser.window).contains('ontouchstart')); + return js.lib.Object.keys(js.Browser.window).contains('ontouchstart'); + case Some(val): + return val; + } + // Let's see if this suffices for now actually (this doesn't match my touchscreen laptop) + #end + #if hl + switch (Settings.isTouch) { + case None: + Settings.isTouch = Some(false); + return false; + case Some(val): + return val; + } + return false; + #end + } + + public static function isSafari() { + #if js + var reg = ~/^((?!chrome|android).)*safari/; + return reg.match(js.Browser.navigator.userAgent); + #end + #if hl + return false; + #end + } + + public static function isInFullscreen() { + #if js + return (js.Browser.window.innerHeight == js.Browser.window.screen.height + || (js.Browser.window.screen.orientation.type == js.html.OrientationType.PORTRAIT_PRIMARY + || js.Browser.window.screen.orientation.type == js.html.OrientationType.PORTRAIT_SECONDARY) + && js.Browser.window.innerHeight == js.Browser.window.screen.width) + || js.Browser.document.fullscreenElement != null; + #end + #if hl + return Settings.optionsSettings.isFullScreen; + #end + } } diff --git a/src/touch/CameraInput.hx b/src/touch/CameraInput.hx new file mode 100644 index 00000000..f056b304 --- /dev/null +++ b/src/touch/CameraInput.hx @@ -0,0 +1,39 @@ +package touch; + +import src.MarbleGame; +import src.Settings; +import touch.TouchInput.TouchEventState; + +class CameraInput { + var identifier:Int = -1; + + var doing = false; + + public function new() {} + + public function update(touchState:TouchEventState) { + if (!doing) { + // Check for touches on the right half of the screen + for (touch in touchState.changedTouches) { + if (touch.position.x >= Settings.optionsSettings.screenWidth / 2 && touch.state == Pressed) { + identifier = touch.identifier; + doing = true; + } + } + } else { + // Get our identifier + for (touch in touchState.changedTouches) { + if (touch.identifier == this.identifier && touch.state == Release) { + doing = false; + return; // lol + } + if (touch.identifier == this.identifier && touch.state == Move) { + MarbleGame.instance.world.marble.camera.orbit(touch.deltaPosition.x, touch.deltaPosition.y); + return; + } + } + // Could not find + doing = false; + } + } +} diff --git a/src/touch/TouchInput.hx b/src/touch/TouchInput.hx new file mode 100644 index 00000000..6bbdeb5a --- /dev/null +++ b/src/touch/TouchInput.hx @@ -0,0 +1,82 @@ +package touch; + +import src.MarbleWorld; +import h3d.Vector; + +enum TouchState { + Pressed; + Move; + Release; +} + +class Touch { + public var state:TouchState; + public var position:Vector; + public var deltaPosition:Vector; + public var identifier:Int; + + public function new(state:TouchState, position:Vector, deltaPos:Vector, id:Int) { + this.state = state; + this.position = position; + this.deltaPosition = deltaPos; + this.identifier = id; + } +} + +class TouchEventState { + public var changedTouches:Array; + + public function new() { + this.changedTouches = []; + } +} + +class TouchInput { + public var cameraInput:CameraInput; + + public var currentTouchState:TouchEventState; + + public var previousTouchState:TouchEventState; + + public function new() { + this.cameraInput = new CameraInput(); + this.currentTouchState = new TouchEventState(); + this.previousTouchState = new TouchEventState(); + } + + // Registers the callbacks to the native stuff + public function registerTouchInput() { + #if js + var pointercontainer = js.Browser.document.querySelector("#pointercontainer"); + pointercontainer.addEventListener('touchstart', (e:js.html.TouchEvent) -> { + for (touch in e.changedTouches) { + var t = new Touch(Pressed, new Vector(touch.clientX, touch.clientY), new Vector(0, 0), touch.identifier); + currentTouchState.changedTouches.push(t); + } + }); + pointercontainer.addEventListener('touchmove', (e:js.html.TouchEvent) -> { + for (touch in e.changedTouches) { + var prevt = previousTouchState.changedTouches.filter(x -> x.identifier == touch.identifier); + var prevDelta = new Vector(0, 0); + if (prevt.length != 0) { + prevDelta = new Vector(touch.clientX, touch.clientY).sub(prevt[0].position); + } + var t = new Touch(Move, new Vector(touch.clientX, touch.clientY), prevDelta, touch.identifier); + currentTouchState.changedTouches.push(t); + } + }); + pointercontainer.addEventListener('touchend', (e:js.html.TouchEvent) -> { + for (touch in e.changedTouches) { + var t = new Touch(Release, new Vector(touch.clientX, touch.clientY), new Vector(0, 0), touch.identifier); + currentTouchState.changedTouches.push(t); + } + }); + #end + } + + public function update() { + this.cameraInput.update(currentTouchState); + previousTouchState = currentTouchState; + currentTouchState = new TouchEventState(); + } +}