A friend asked me to give an example of a game state model, I was referring to when I tried to explain him how I develop simple games and touch screen applications. Here I’ll be trying to explain this, by extracting some example code from The secrets of three paintings app.
Be it ActionScript or JavaScript, whenever I’m writing relatively simple games or touch screen applications, I always use these 3:
Here is an up to date version of requestAnimationFrame polyfill. It’s a mashup from different sources.
// Adapted from https://gist.github.com/paulirish/1579671 which derived from | |
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ | |
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating | |
// requestAnimationFrame polyfill by Erik Möller. | |
// Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen Slavič, Darius Bacon | |
// MIT license | |
(function() { | |
'use strict'; | |
var vendors = ['webkit', 'moz']; | |
for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) { | |
var vp = vendors[i]; | |
window.requestAnimationFrame = window[vp+'RequestAnimationFrame']; | |
window.cancelAnimationFrame = (window[vp+'CancelAnimationFrame'] | |
|| window[vp+'CancelRequestAnimationFrame']); | |
} | |
if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) // iOS6 is buggy | |
|| !window.requestAnimationFrame || !window.cancelAnimationFrame) { | |
var lastTime = 0; | |
window.requestAnimationFrame = function(callback) { | |
var now = +new Date; | |
var nextTime = Math.max(lastTime + 16, now); | |
return setTimeout(function() { callback(lastTime = nextTime); }, | |
nextTime - now); | |
}; | |
window.cancelAnimationFrame = clearTimeout; | |
} | |
var hasPerformance = !!(window.performance && window.performance.now); | |
// Add new wrapper for browsers that don't have performance | |
if (!hasPerformance) { | |
// Store reference to existing rAF and initial startTime | |
var rAF = window.requestAnimationFrame, | |
startTime = +new Date; | |
// Override window rAF to include wrapped callback | |
window.requestAnimationFrame = function (callback, element) { | |
// Wrap the given callback to pass in performance timestamp | |
var wrapped = function (timestamp) { | |
// Get performance-style timestamp | |
var performanceTimestamp = (timestamp < 1e12) | |
? timestamp | |
: timestamp - startTime; | |
return callback(performanceTimestamp); | |
}; | |
// Call original rAF with wrapped callback | |
rAF(wrapped, element); | |
} | |
} | |
}()); |
I was playing around with Sonic Visualizer last night, following these great video tutorials. In one of them Mazurka Plugins are used, for which there were no downloadable OS X binaries until now:
Download mazurka-plugins.dylib (OS X Yosemite, 10.10)
I’m not sure if these will work with previous versions of OS X, but maybe give it a try.
If you want to try compiling yourself, here are the sources I used.
You’ll also need XCode with Command Line Tools and fftw3 installed.
import android.os.CountDownTimer; | |
abstract public class CountUpTimer | |
{ | |
private CountDownTimer countDownTimer; | |
private int countDownCycle; | |
public CountUpTimer(long countUpInterval) { | |
countDownTimer = new CountDownTimer(Long.MAX_VALUE, countUpInterval) { | |
@Override | |
public void onTick(long millisUntilFinished) { | |
CountUpTimer.this.onTick(Long.MAX_VALUE * countDownCycle - millisUntilFinished); | |
} | |
@Override | |
public void onFinish() { | |
countDownCycle++; | |
CountUpTimer.this.start(); | |
} | |
}; | |
countDownCycle = 1; | |
} | |
public void start() { | |
countDownTimer.start(); | |
} | |
public void stop() { | |
countDownTimer.cancel(); | |
} | |
public void cancel() { | |
stop(); | |
countDownCycle = 1; | |
} | |
public abstract void onTick(long millisElapsed); | |
} |
Usage:
1 2 3 4 5 6 7 8 | new CountUpTimer(1000L) { @Override public void onTick( long millisElapsed) { Date date = new Date(millisElapsed); DateFormat dateFormat = new SimpleDateFormat(TimeUnit.MILLISECONDS.toHours(millisElapsed) >= 1 ? "HH:mm:ss" : "mm:ss"); Log.i(dateFormat.format(date)); } }; |
Perhaps having come languages like PHP, Javascript or ActionScript, I just can not get used to tagging log output.
Hence I came up with a class: OneLog – one tag.
public class OneLog { | |
public static String TAG = OneLog.class.getName(); | |
private OneLog() { | |
} | |
public static int v(String msg) { | |
return android.util.Log.v(TAG, msg); | |
} | |
public static int v(String msg, Throwable tr) { | |
return android.util.Log.v(TAG, msg, tr); | |
} | |
public static int d(String msg) { | |
return android.util.Log.d(TAG, msg); | |
} | |
public static int d(String msg, Throwable tr) { | |
return android.util.Log.d(TAG, msg, tr); | |
} | |
public static int i(String msg) { | |
return android.util.Log.i(TAG, msg); | |
} | |
public static int i(String msg, Throwable tr) { | |
return android.util.Log.i(TAG, msg, tr); | |
} | |
public static int w(String msg) { | |
return android.util.Log.w(TAG, msg); | |
} | |
public static int w(String msg, Throwable tr) { | |
return android.util.Log.w(TAG, msg, tr); | |
} | |
public static int w(Throwable tr) { | |
return android.util.Log.w(TAG, tr); | |
} | |
public static int e(String msg) { | |
return android.util.Log.e(TAG, msg); | |
} | |
public static int e(String msg, Throwable tr) { | |
return android.util.Log.e(TAG, msg, tr); | |
} | |
} |
I initialise OneLog.TAG in my Application class, but it really can go anywhere appropriate.
1 2 3 4 5 6 7 8 9 | public class MyApp extends Application { public static final String PACKAGE; static { PACKAGE = MyApp. class .getPackage().getName(); OneLog.TAG = PACKAGE; } ... } |
And then you’re free (from tagging):
1 | Log.i("test log"); |
AndroidAsync (https://github.com/koush/AndroidAsync) is an asynchronous socket, http (client+server), websocket, and socket.io library for android. Based on nio, not threads.
Here is an example how to create a working socket server service within seconds, without having to think about threads.
import android.app.Service; | |
import android.content.Intent; | |
import android.os.IBinder; | |
import android.util.Log; | |
import com.koushikdutta.async.AsyncNetworkSocket; | |
import com.koushikdutta.async.AsyncServer; | |
import com.koushikdutta.async.AsyncServerSocket; | |
import com.koushikdutta.async.AsyncSocket; | |
import com.koushikdutta.async.ByteBufferList; | |
import com.koushikdutta.async.DataEmitter; | |
import com.koushikdutta.async.callback.CompletedCallback; | |
import com.koushikdutta.async.callback.DataCallback; | |
import com.koushikdutta.async.callback.ListenCallback; | |
public class AsyncServerExampleService extends Service | |
{ | |
public static final String LOGTAG = AsyncServerExampleService.class.getName(); | |
public static final int SERVER_PORT = 6000; | |
private AsyncServer asyncServer; | |
private AsyncNetworkSocket asyncClient; | |
@Override | |
public void onCreate() { | |
asyncServer = new AsyncServer(); | |
asyncServer.listen(null, SERVER_PORT, listenCallback); | |
} | |
private ListenCallback listenCallback = new ListenCallback() { | |
@Override | |
public void onAccepted(AsyncSocket socket) { | |
// this example service shows only a single server <-> client communication | |
if (asyncClient != null) { | |
asyncClient.close(); | |
} | |
asyncClient = (AsyncNetworkSocket) socket; | |
asyncClient.setDataCallback(new DataCallback() { | |
@Override | |
public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { | |
Log.i(LOGTAG, "Data received: " + bb.readString()); | |
} | |
}); | |
asyncClient.setClosedCallback(new CompletedCallback() { | |
@Override | |
public void onCompleted(Exception ex) { | |
asyncClient = null; | |
Log.i(LOGTAG, "Client socket closed"); | |
} | |
}); | |
Log.i(LOGTAG, "Client socket connected"); | |
} | |
@Override | |
public void onListening(AsyncServerSocket socket) { | |
Log.i(LOGTAG, "Server listening on port " + socket.getLocalPort()); | |
} | |
@Override | |
public void onCompleted(Exception ex) { | |
Log.i(LOGTAG, "Server socket closed"); | |
} | |
}; | |
// call this method to send data to the client socket | |
public void sendData(String message) { | |
asyncClient.write(new ByteBufferList(message.getBytes())); | |
Log.i(LOGTAG, "Data sent: " + message); | |
} | |
@Override | |
public int onStartCommand(Intent intent, int flags, int startId) { | |
return START_STICKY; | |
} | |
@Override | |
public void onDestroy() { | |
if (asyncServer.isRunning()) { | |
asyncServer.stop(); | |
} | |
} | |
@Override | |
public IBinder onBind(Intent intent) { | |
return null; | |
} | |
} |
Daily Words of Buddha has been downloaded more than 5000 times since launched little less than a year ago!
Thanks for the nice reviews:
“Excellent Open Source Dharma App Works well, does what it says, anumodana!”
Yuttadhammo Bhikkhu
“Very inspiring! Thanks for the app!”
Aleksandrs Ritums
“Makes each day more filled with mindfulness”
Neha Mundhra
“Great Good to read the words of the Buddha on a daily basis. App gives Pali written and audio and English translation.”
Faysal Taher
Moved Ilga’s site to WordPress, and did a bit of a redesign.
Ilga Leimanis is a London-based visual artist who works in drawing and painting.