/** * Copyright 2010 The ForPlay Authors * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package forplay.flash; import com.google.gwt.core.client.Duration; import com.google.gwt.core.client.JavaScriptObject; import forplay.core.Touch; import flash.events.Event; import forplay.core.Storage; import flash.display.Sprite; import flash.events.EventType; import forplay.core.Analytics; import forplay.core.Audio; import forplay.core.ForPlay; import forplay.core.Game; import forplay.core.Graphics; import forplay.core.Json; import forplay.core.Keyboard; import forplay.core.Log; import forplay.core.Net; import forplay.core.Platform; import forplay.core.Pointer; import forplay.core.Mouse; import forplay.core.RegularExpression; import forplay.html.HtmlRegularExpression; public class FlashPlatform implements Platform { static final int DEFAULT_WIDTH = 640; static final int DEFAULT_HEIGHT = 480; private static final int LOG_FREQ = 2500; private static final float MAX_DELTA = 100; private static FlashPlatform platform; static { platform = new FlashPlatform(); } public static FlashPlatform register() { ForPlay.setPlatform(platform); platform.init(); return platform; } static native void addEventListener(JavaScriptObject target, String name, EventHandler<?> handler, boolean capture) /*-{ target.addEventListener(name, function(e) { handler.@forplay.flash.EventHandler::handleEvent(Lflash/events/Event;)(e); }, capture); }-*/; private FlashAssetManager assetManager = new FlashAssetManager(); private FlashAudio audio; private HtmlRegularExpression regularExpression; private Game game; private FlashGraphics graphics; private FlashJson json; private FlashKeyboard keyboard; private FlashLog log; private FlashNet net; private FlashPointer pointer; private FlashMouse mouse; private TimerCallback paintCallback; private TimerCallback updateCallback; private Storage storage; private Analytics analytics; // Non-instantiable. public FlashPlatform() { } public void init() { log = new FlashLog(); regularExpression = new HtmlRegularExpression(); net = new FlashNet(); audio = new FlashAudio(); keyboard = new FlashKeyboard(); pointer = new FlashPointer(); mouse = new FlashMouse(); json = new FlashJson(); graphics = new FlashGraphics(); storage = new FlashStorage(); analytics = new FlashAnalytics(); } @Override public FlashAssetManager assetManager() { return assetManager; } @Override public Audio audio() { return audio; } @Override public Graphics graphics() { return graphics; } @Override public Json json() { return json; } @Override public Keyboard keyboard() { return keyboard; } @Override public Log log() { return log; } @Override public Net net() { return net; } @Override public Pointer pointer() { return pointer; } @Override public Mouse mouse() { return mouse; } @Override public Touch touch() { // TODO(pdr): need to implement this. throw new UnsupportedOperationException("Touch is not yet supported on the Flash platform"); } @Override public float random() { return (float) Math.random(); } @Override public RegularExpression regularExpression() { return regularExpression; } @Override public void openURL(String url) { //TODO: implement } private static int FPS_COUNTER_MAX = 300; @Override public void run(final Game game) { final int updateRate = game.updateRate(); this.game = game; // Game loop. paintCallback = new TimerCallback() { private float accum = updateRate; private double lastTime; int frameCounter = 0; private double frameCounterStart = 0; @Override public void fire() { double now = time(); if (frameCounter == 0) { frameCounterStart = now; } float delta = (float)(now - lastTime); if (delta > MAX_DELTA) { delta = MAX_DELTA; } lastTime = now; if (updateRate == 0) { game.update(delta); // log().info("Update took " + (time() - now)); accum = 0; } else { accum += delta; while (accum > updateRate) { game.update(updateRate); // log().info("Update took " + (time() - now)); accum -= updateRate; } } // double now2 = time(); game.paint(accum / updateRate); // log().info("Paint took " + (time() - now2)); graphics.updateLayers(); frameCounter++; if (frameCounter == FPS_COUNTER_MAX) { double frameRate = frameCounter / ((time() - frameCounterStart) / 1000.0); ForPlay.log().info("FPS: " + frameRate); frameCounter = 0; } } }; game.init(); requestAnimationFrame(paintCallback); } @Override public double time() { return Duration.currentTimeMillis(); } private void requestAnimationFrame(final TimerCallback callback) { // http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html#event:enterFrame FlashPlatform.captureEvent(Sprite.ENTERFRAME, new EventHandler<Event>() { public void handleEvent(Event evt) { evt.preventDefault(); callback.fire(); } }); } private native int setInterval(TimerCallback callback, int ms) /*-{ return $wnd.setInterval(function() { callback.@forplay.flash.TimerCallback::fire()(); }, ms); }-*/; private native int setTimeout(TimerCallback callback, int ms) /*-{ return $wnd.setTimeout(function() { callback.@forplay.flash.TimerCallback::fire()(); }, ms); }-*/; public static native void captureEvent(EventType eventType, EventHandler<?> eventHandler) /*-{ $root.addEventListener(eventType, function(arg) { eventHandler.@forplay.flash.EventHandler::handleEvent(Lflash/events/Event;)(arg); }); }-*/; @Override public Storage storage() { return storage; } @Override public Analytics analytics() { return analytics; } }