Skip to content

Posts from the ‘Projects’ Category

Oct 19 10

Pixelatr – SVG powered pixel drawing demo

I’ve wanted to experiment with some of the various graphics libraries in JavaScript for a while now, and deciding to attempt the ambitious task of a 2D clone of the recently popular game, MineCraft, seemed a worthy reason to play around with some of them.

After deciding (perhaps wrongly) that Raphaël would be a good library to do this in (or at least one I would like to try out). A quick weekend of implementing and reimplementing various ways of rendering scrolling around a vast 2D block world (in the end using a massive SVG element that is scrolled with blocks being added or removed as they come into and leave the visible area). The results are (not quite 2D MineCraft yet I know) a massive editable grid of “pixels” which are actually rounded rectangles of various colours.

As I wasn’t going to complete 2D MineCraft in a weekend I decided to add in websocket support using Socket.IO and make it a multi-user editable canvas that persists between sessions. Its quite fun to play with and there is a small demo below (works best in Chrome, Safari or IE9, should work slowly in Firefox), for a full page version click here, the last part of the URL defines the “channel” you are in if you wish to create a private page to share with friends.

If you are interested in the source just view the source of that page, I’ll be uploading the server and client to github shortly (once I’ve tided up some of the code a bit). If I have some time in the future I hope to take this further and make some kind of user editable platformer type game in the general theme of MineCraft. I would also like to try implementing this using the HTML5 canvas element (especially with the recent hardware rendering developments on Chrome and IE9).

Oct 9 10

A genetic algorithm example in JavaScript

So, after several months of neglect I have finally decided to force myself to update my blog. This is the first of what will hopefully be several posts detailed the various projects I have been working on over the past few months. This is the smallest and potentially least useful of these projects, but something I recently made (and therefore easiest for me to write about) and hopefully mildly interesting.

In the 2nd year of my computer science degree a module called “Artificial Intelligence” briefly touched on the idea of Genetic Algorithms. After discussion with a housemate as to how these could be used in a 3rd year project I decided to look into making a simple example of such an algorithm to run using JavaScript in the browser.

After a quick Google the best example I could find (that would be visual enough to be interesting to see and simple enough to write in JavaScript quickly) was to generate the string “Hello, World!”. Starting with randomly generated strings and genetically evolving them based on a fitness function of how close they were to the string I wanted. A little bit more detail on how that is achieved shortly, but first the result is shown below (click on “Hello, World!” to replay the demo) a more detailed output can be seen here.

a
a

So, what is this actually doing? Viewing the detailed output you can see all of the strings generated, how they were combined (the algorithmic equivalent of reproduction) and the mutatations after they reproduced. To start 20 random strings are generated, then the top 2 strings (measured by number of letters that are correct, and then closeness of incorrect letters) are taken. It is worth noting this is perhaps not the best way for a genetic algorithm to work, and strictly all of the strings should have a chance of “reproducing” based on their fitness score, but this works well enough for a simple example. Once the top 2 are taken, they are split at a random point 20 times and combined (shown by the red and green colouring on the detailed output), these resulting strings then have a 75% chance of one of their characters randomly changing (shown with a yellow highlight on the detailed output) and we have 20 (potentially) completely new strings. The scoring process then repeats and more strings are created until we reach the goal string.

The result is we very quickly get a string very close to what we want, which eventually mutates to become exactly what we want, with a nice visual demonstration of what is happening, and hopefully a better understanding of how genetic algorithms work.

Mar 23 10

TapeMeasure – Another Android experiment

I have again become interested in what you can do with Android applications. After some discussion with a housemate (who actually owns an Android, unlike me) about augmented reality applications and how they could be easily done (to some degree) if you could reasonably accurately track a phones location in a building (something that is hard to do with GPS).  I wanted to see if the phones accelerometer could be used (at least for short distances) to work out how a phone had moved since entering a building. Rather than attempt to make an augmented reality app, I decided to go for a slightly easier project of making a tape measure, i.e. an app that could measure distance by moving the phone. Before anyone thinks this will actually be useful I should point out that this was a rather complete failure and the resulting app is fairly useless. However, the code may be useful to anyone looking at writing an Android app that uses any of the internal sensors, it would also be interesting to see if any other phones (I only tested the app on a G1) are any more successful.

So straight to the code, after (briefly) reading the Android documentation it seemed there was very little info about using the sensors, so I turned to Google, this article looked like what I wanted and linked to this code which is the basis of my app. So I updated the code to use the non-deprecated API, changing its functionality slightly and ended up with:

package uk.co.connorhd.android.tapemeasure;
 
import android.app.Activity;
import android.os.Bundle;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
 
public class TapeMeasure extends Activity implements SensorEventListener,
		OnClickListener {
	private SensorManager sensorMgr;
	private Sensor sensorAccel;
	private TextView accuracyLabel;
	private TextView xLabel, yLabel, zLabel;
	private Button calibrateButton;
 
	private float moved = 0;
	private float speed = 0;
	private float accel = 0;
	private float accelDiff = 0;
 
	private float[] a;
 
	private long lastUpdate = 0;
	private float curAccel = 0;
	private int accelUpdates = 0;
 
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		accuracyLabel = (TextView) findViewById(R.id.accuracy_label);
		xLabel = (TextView) findViewById(R.id.x_label);
		yLabel = (TextView) findViewById(R.id.y_label);
		zLabel = (TextView) findViewById(R.id.z_label);
		calibrateButton = (Button) findViewById(R.id.calibrate_button);
		calibrateButton.setOnClickListener(this);
	}
 
	@Override
	protected void onPause() {
		super.onPause();
		sensorMgr.unregisterListener(this, sensorAccel);
		sensorMgr = null;
	}
 
	@Override
	protected void onResume() {
		super.onResume();
 
		sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
		sensorAccel = sensorMgr.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0);
		boolean accelSupported = sensorMgr.registerListener(this, sensorAccel,
				SensorManager.SENSOR_DELAY_FASTEST);
 
		if (!accelSupported) {
			// on accelerometer on this device
			sensorMgr.unregisterListener(this, sensorAccel);
			accuracyLabel.setText(R.string.no_accelerometer);
		}
	}
 
	public void onClick(View v) {
		if (v == calibrateButton) {
			// Clicked button
			moved = 0;
			speed = 0;
			accelDiff = accel+accelDiff;
			accel = 0;
 
		}
	}
 
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		// this method is called very rarely, so we don't have to
		// limit our updates as we do in onSensorChanged(...)
		if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
			switch (accuracy) {
			case SensorManager.SENSOR_STATUS_UNRELIABLE:
				accuracyLabel.setText(R.string.accuracy_unreliable);
				break;
			case SensorManager.SENSOR_STATUS_ACCURACY_LOW:
				accuracyLabel.setText(R.string.accuracy_low);
				break;
			case SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM:
				accuracyLabel.setText(R.string.accuracy_medium);
				break;
			case SensorManager.SENSOR_STATUS_ACCURACY_HIGH:
				accuracyLabel.setText(R.string.accuracy_high);
				break;
			}
		}
	}
 
	public void onSensorChanged(SensorEvent event) {
		int sensorType = event.sensor.getType();
		if (sensorType == Sensor.TYPE_ACCELEROMETER) {
			a = event.values;
			accel = (float) (Math.sqrt((a[0]*a[0]+a[1]*a[1]+a[2]*a[2]))-SensorManager.GRAVITY_EARTH)-accelDiff;
			curAccel += accel;
			accelUpdates++;
 
			long curTime = event.timestamp - lastUpdate;
			if (curTime > 1000000000) {
				curAccel = curAccel/accelUpdates;
				speed += curAccel*curTime*10e-10;
				moved += speed*curTime*10e-10;
 
				lastUpdate = event.timestamp;
 
				xLabel.setText(String.format("Moved: %+2.20f", moved));
				yLabel.setText(String.format("Speed: %+2.20f", speed));
				zLabel.setText(String.format("Accel: %+2.20f Time:  %+2.3f", curAccel, curTime*10e-10));
				curAccel = 0;
				accelUpdates = 0;
			}
		}
	}
}

This calculates the current acceleration of the phone, subtracts gravity (which is added to the raw data), then derives the speed and distance travelled. The calibrate button resets the speed and distance, and assumes the phone is not moving, generating a bias to add to the acceleration in the case of the phones accelerometer being badly calibrated. If you want to try the app it can be downloaded and installed from here. I suggest launching the app, placing the phone on a stable surface and pressing calibrate, if you get any interesting results let me know.

Despite the phone reporting the accelerometer accuracy as “high” (with no description of what high means) and returning values in excess of 10 significant figures,  the acceleration data with the phone sat on a table varied in the range of about 0.5m/s^2 (although this did appear to change depending on the room I was in). This resulted in a massively wrong distance value very quickly increasing to several metres without moving the phone, making any kind of testing almost impossible. It seems the current purpose of accelerometers is to work out if some violent action (such as shaking) has happened to the phone, and not anything much more interesting. All in all a bit of a waste of time, but maybe future phones will have better sensors, and hopefully someone will find the code snippet above useful.