Because a picture says more than a thousand words (especially as my english is not the best ;) here there are the highlights of my flickr-stream showing yesterday’s Flash Camp Berlin.

On my way to the location I met these guys in Hamburg and had a very nice time with them.

Train to FlashCamp Berlin Walking to FlashCamp Berlin

Speakers were Matthias Kannengiesser, Cedric Madelaine, Andre Michelle, Sven Claas, Duane Nickull and others.

Matthias Kannengiesser & Thomas Reppa - FlashCamp Berlin Cedric Madelaine - FlashCamp Berlin Andre Michelle - FlashCamp Berlin Duane Nickull - FlashCamp Berlin

The attendees were all nice and the food was okay as well.

FlashCamp Berlin FlashCamp Berlin

That was the first time for me to see flash community members in person and it was definitively worth it. Unfortunately the next big City Kiel has no Flex User Group, but there is one in Hamburg (flexughh) and I’m looking forward to attending their meetings in the future.

Today the Software Challenge finals took place in Kiel and I’m proud to announce that our team won the challenge!

Software Challenge 2009 Finals Software Challenge 2009 Finals

The task was to create an AI for a simple game. Initially there were 38 teams who comped against each other in the first phase of the Software Challenge. The best eight of them were present at the finals today.

Each encounter was made up of six games.

The quarter-final was very thrilling, but we managed to win four out of the six games. In the semi-final we did a superior 6:0 and the finale then was 4:2 again.

During the play one member of each of the two teams was on the stage, interviewed by the annotator. Our team let me go for that, because I’m most familiar with the strategy of our AI. So I stood in front of all the spectators, being totally nervous and watching our client win. That was so cool!

Software Challenge 2009 Finals software challenge finalis

We got that big cup, 1000 € for our school and some more money for us.

Additional resources


My post on the AS3 twitter API got some feedback, last of which was Mark asking how to set your status using the API.
I don’t really know what’s been his problem, but it took only a few seconds to create an example.

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="init()">
	<mx:Script>
		<![CDATA[
			import twitter.api.Twitter;

			public static const USER:String = "USERNAME";
			public static const PASSWORD:String = "PASSWORD";

			private var t:Twitter;

			private function init():void {
				t = new Twitter();
				t.setAuthenticationCredentials(USER, PASSWORD);
			}
			private function buttonClickHandler():void {
				button.enabled = false;
				t.setStatus(input.text);
			}
		]]>
	</mx:Script>
	<mx:TextArea editable="true" id="input"/>
	<mx:Button label="go" id="button" click="buttonClickHandler()" />
</mx:WindowedApplication>

Just create an AIR application in Flex Builder 3 or FlashDevelop, insert this code and make sure to put the TwitterScript SWC into your libs folder.

For the lazy ones of you, grab this Flex Project Archive into FlexBuilder.
Download Archive

All January entries of the 25lines ActionScript contest were released yesterday: http://www.25lines.com/?p=227

I’ve updated the 25lines browser, so now you can view the SWFs comfortable at http://xathis.com/25lines/0901/. Be careful, entry #020 crashed my browser.

You’ll find my submission as #18.

The 25lines January finalists were announced today, some really awesome stuff.
I’ve set up a new 25lines browser page for them, but it isn’t really worth it until all January codes are available.

My entry isn’t among them, so its code will be published in a few days at 25lines.com when the voting has ended.
If you want to see it by now, here it goes.

I could watch it for hours.

The Flash plugin is required to view this object.


/**
 * 25-Line ActionScript Contest Entry
 *
 * Project:	periodic fortune
 * Author:	Mathis Lichtenberger <mail@xathis.com>
 * Date:	01/13/2009
 * Share:	YES
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

// 3 free lines! Alter the parameters of the following lines or remove them.
// Do not substitute other code for the three lines in this section
[SWF(width=600,height=540,backgroundColor=0,frameRate=24)]
stage.scaleMode = StageScaleMode.NO_SCALE;
// 25 lines begins here!
import fl.motion.Color
var a={}
function setProps(o,p){for(var i in p)o[i]=p[i]}
function init(){
	for(var i=0;i<(a.n=6+Math.floor(Math.random()*2)*2);i++)a[i]=new Point((a.rd=Math.random)()*240,a.rd()*240)
	setProps(a,{x:a.rd()*600,xx:0,xxx:1-a.rd()*2,y:a.rd()*540,yy:0,yyy:1-a.rd()*2,t:0,tt:0,ttt:3-a.rd()*6,c:a.rd()*200000000,d:a.rd()*200000000,p:0,z:0,zz:20-a.rd()*25,u:0,uu:40-a.rd()*80})}
addEventListener("enterFrame",function(e){
	if(a.s==null||a.x<0||a.y<0||a.x>600||a.y>540)init()
	Shape(addChild(a.s=new Shape())).graphics.beginFill(Color.interpolateColor(a.c,a.d,a.p+=0.1))
	for(var i=0;i<a.n/2;i++)a.s.graphics.curveTo(a[i*2].x,a[i*2].y,a[i*2+1].x,a[i*2+1].y)
	setProps(a.s,{x:a.x+=a.xx+=a.xxx,y:a.y+=a.yy+=a.yyy,rotation:a.t+=a.tt+=a.ttt,z:a.z+=a.zz,rotationX:a.u+=a.uu})
	for(i=0;i<numChildren;i++)if((getChildAt(i).alpha-=0.025)<=0)removeChild(getChildAt(i))
	for(i=0;i<numChildren;i++)getChildAt(i).x+=.5-getChildAt(i).alpha})
// 25 lines ends here!

Actually, it’s only 13 lines of code.
Maybe that’s the reason they didn’t like it? I don’t think so.

The last days I’ve experimented with jiglibflash, a 3D Physics Engine for Papervision3D. I’ve been inspired by a great example demo and made a little game out of it.

The result is Phykick.

phykick-screen

You have to kick the boxes off the platform as fast as possible. That’s all.
The best thing about Phkick is the highscore list.

The game consists of a sinlge class only, here is the code (without highscore implementation):


package {
	import __AS3__.vec.Vector;

	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	import flash.ui.Keyboard;
	import flash.utils.getTimer;

	import jiglib.geometry.*;
	import jiglib.math.*;
	import jiglib.physics.*;
	import jiglib.physics.constraint.*;

	import org.papervision3d.cameras.*;
	import org.papervision3d.core.geom.*;
	import org.papervision3d.core.math.*;
	import org.papervision3d.core.proto.*;
	import org.papervision3d.events.*;
	import org.papervision3d.lights.PointLight3D;
	import org.papervision3d.materials.*;
	import org.papervision3d.materials.shadematerials.*;
	import org.papervision3d.materials.utils.*;
	import org.papervision3d.objects.DisplayObject3D;
	import org.papervision3d.objects.parsers.*;
	import org.papervision3d.objects.primitives.*;
	import org.papervision3d.render.*;
	import org.papervision3d.scenes.*;
	import org.papervision3d.view.Viewport3D;

	[SWF(width=800, height=600, backgroundColor=0x062037, frameRate=60)]

	public class Phykick extends Sprite {

		private var viewport:Viewport3D;
	    private var scene:Scene3D;
	    private var camera:Camera3D;
	    private var renderer:QuadrantRenderEngine;
		private var light:PointLight3D;

		private var playerBody:JSphere;
		private var boxBodies:Vector.<JBox>;

		private var keyRight:Boolean = false;
		private var keyLeft:Boolean = false;
		private var keyForward:Boolean = false;
		private var keyReverse:Boolean = false;

		private static var textFormat:TextFormat = new TextFormat("Arial", 12, 0xffffff);

		private var timeField:TextField;
		private var scoreField:TextField;
		private var fallsField:TextField;
		private var fpsField:TextField;
		private var infoField:TextField;
		private var endScoreField:TextField
		private var aboutField:TextField;

		private var score:int;
		private var numFalls:int;
		private var startTime:int;
		private var lastStepTime:int;
		private var inGame:Boolean;
		private var fpsCount:int;
		private var fpsValue:int;

		public function Phykick() {

			viewport = new Viewport3D(800, 600);
			scene = new Scene3D();
			this.addChild(viewport);

			light = new PointLight3D(true, true);
			light.x = 0;
			light.y = 600;
			light.z = -300;

			// ground
			var materia1s:MaterialsList = new MaterialsList();
			materia1s.addMaterial(new FlatShadeMaterial(light, 0xff9900), "all");
			var groundSkin:Cube = new Cube(materia1s);
			scene.addChild(groundSkin);
			var ground:JBox = new JBox(groundSkin, false);
			PhysicsSystem.getInstance().AddBody(ground);
			ground.Material.Restitution = 0.6;
			ground.Material.StaticFriction = 0.9;

			// player
			var sphereSkin:Sphere = new Sphere(new FlatShadeMaterial(light, 0x990000), 20);
			scene.addChild(sphereSkin);
			playerBody = new JSphere(sphereSkin, true, 20);
			playerBody.setMass(3);
			playerBody.MoveTo(new JNumber3D(0, 500, 0), JMatrix3D.IDENTITY);
			PhysicsSystem.getInstance().AddBody(playerBody);

			//playerBody.Material.Restitution = 0.9;

			// camera
			var cameraTarget:DisplayObject3D = new DisplayObject3D();
			cameraTarget.y = 250;
			camera = new Camera3D();
			camera.x = 0;
			camera.y = 500;
			camera.z = -400;
			camera.lookAt(cameraTarget);

			renderer = new QuadrantRenderEngine(1);

			// boxes
			boxBodies = new Vector.<JBox>();
			for (var i:int = 0; i < 3; i++) boxBodies.push(createBox());

			timeField = new TextField();
			timeField.textColor = 0xffffff;
			timeField.selectable = false;
			timeField.defaultTextFormat = textFormat;
			timeField.x = 3;
			timeField.y = 3;
			addChild(timeField);
			scoreField = new TextField();
			scoreField.textColor = 0xffffff;
			scoreField.selectable = false;
			scoreField.defaultTextFormat = textFormat;
			scoreField.x = 3;
			scoreField.y = 23;
			addChild(scoreField);
			fallsField = new TextField();
			fallsField.textColor = 0xffffff;
			fallsField.selectable = false;
			fallsField.defaultTextFormat = textFormat;
			fallsField.x = 3;
			fallsField.y = 43;
			addChild(fallsField);
			fpsField = new TextField();
			fpsField.textColor = 0xffffff;
			fpsField.selectable = false;
			fpsField.defaultTextFormat = textFormat;
			fpsField.x = 3;
			fpsField.y = 63;
			addChild(fpsField);

			aboutField = new TextField();
			aboutField.selectable = false;
			aboutField.textColor = 0xffffff;
			aboutField.autoSize = TextFieldAutoSize.RIGHT;
			aboutField.defaultTextFormat = textFormat
			aboutField.htmlText = "Phykick v1.0.0\n© Mathis Lichtenberger";
			aboutField.y = stage.stageHeight - aboutField.height;
			aboutField.x = 3;
			addChild(aboutField);

			var infoText:String = "// kick the boxes off the platform";
			infoText += "\n// as fast as possible";
			infoText += "\n// you've got 100 seconds";
			infoText += "\n";
			infoText += "\n// arrow keys:   navigate";
			infoText += "\n// space bar:   start game";
			infoText += "\n// ctrl + F:   fullscreen";

			infoField = new TextField();
			infoField.textColor = 0xffffff;
			infoField.y = 60;
			infoField.width = stage.stageWidth;
			infoField.multiline = true;
			infoField.selectable = false;
			infoField.autoSize = TextFieldAutoSize.CENTER;
			infoField.defaultTextFormat = textFormat;
			infoField.text = infoText;
			addChild(infoField);

			endScoreField = new TextField();
			endScoreField.defaultTextFormat = new TextFormat("Arial", 20, 0xffffff, true, false, false);
			endScoreField.y = 600 - 90;
			endScoreField.width = stage.stageWidth;
			endScoreField.selectable = false;
			endScoreField.autoSize = TextFieldAutoSize.CENTER;
			endScoreField.visible = false;
			addChild(endScoreField);

			timeField.text = "time: 100";
			fallsField.text = "falls: 0";
			scoreField.text = "score: 0";

			stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
			stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
			addEventListener(Event.ENTER_FRAME, step);
		}

		private function startGame():void {
			inGame = true;
			infoField.visible = false;
			endScoreField.visible = false;
			startTime = getTimer();
			lastStepTime = getTimer();
			score = 0;
			numFalls = 0;
			timeField.text = "time: 0";
			fallsField.text = "falls: 0";
			scoreField.text = "score: 0";
		}
		private function stopGame():void {
			inGame = false;
			infoField.visible = true;
			endScoreField.text = score.toString();
			endScoreField.visible = true;
			timeField.text = "time: 100";
		}

		private function step(event:Event):void {

			if (inGame) {
				// update player forces
				if (keyLeft) playerBody.AddWorldForce(new JNumber3D(-100,0,0),playerBody.CurrentState.Position);
				if (keyRight) playerBody.AddWorldForce(new JNumber3D(100,0,0),playerBody.CurrentState.Position);
				if (keyForward) playerBody.AddWorldForce(new JNumber3D(0,0,100),playerBody.CurrentState.Position);
				if (keyReverse) playerBody.AddWorldForce(new JNumber3D(0,0,-100),playerBody.CurrentState.Position);
			}

			// check for kicked boxes
			for (var i:int = boxBodies.length - 1; i >= 0; i--) {
				var boxBody:JBox = boxBodies[i];
				if (boxBody.CurrentState.Position.y < 0) {
					boxBody.MoveTo(new JNumber3D(Math.random()*400-200, 400, Math.random()*400-200), JMatrix3D.IDENTITY);
					if (inGame) score++;
					scoreField.text = "score: " + score;
				}
			}

			// check if player is falling
			if (playerBody.CurrentState.Position.y < 0) {
				playerBody.MoveTo(new JNumber3D(0, 300, 0), JMatrix3D.IDENTITY);
				if (inGame) numFalls++;
				fallsField.text = "falls: " + numFalls;
			}

			if (inGame) {
				timeField.text = "time: " + (getTimer() - startTime) / 1000;
				if (getTimer() - startTime > 100*1000) stopGame();
			}

			var duration:int = getTimer() - lastStepTime;
			var integrateValue:Number = duration / 167;
			lastStepTime = getTimer();

			fpsCount++;
			fpsValue += duration;
			if (fpsCount > 100) {
				fpsField.text = "fps: " + Math.round(1000 / (fpsValue / fpsCount));
				fpsCount = 0;
				fpsValue = 0;
			}

			PhysicsSystem.getInstance().Integrate(integrateValue);
			renderer.renderScene(scene, camera, viewport);
		}

		private function createBox():JBox {
			var materials:MaterialsList = new MaterialsList();
			materials.addMaterial(new FlatShadeMaterial(light,0xeeee00),"all");
			var boxSkin:Cube = new Cube(materials, 40, 40, 40);
			scene.addChild(boxSkin);
			var boxBody:JBox = new JBox(boxSkin, true, 40, 40, 40);
			boxBody.MoveTo(new JNumber3D(Math.random()*400-200, 400, Math.random()*400-200), JMatrix3D.IDENTITY);
			PhysicsSystem.getInstance().AddBody(boxBody);
			return boxBody;
		}

		private function keyDownHandler(event:KeyboardEvent):void {
			switch(event.keyCode) {
				case Keyboard.UP: keyForward = true; break;
				case Keyboard.DOWN: keyReverse = true; break;
				case Keyboard.LEFT: keyLeft = true; break;
				case Keyboard.RIGHT: keyRight = true; break;

				case Keyboard.SPACE: if (!inGame) startGame(); break;
			}
		}
		private function keyUpHandler(event:KeyboardEvent):void {
			switch(event.keyCode) {
				case Keyboard.UP: keyForward = false; break;
				case Keyboard.DOWN: keyReverse = false; break;
				case Keyboard.LEFT: keyLeft = false; break;
				case Keyboard.RIGHT: keyRight = false; break;
			}
		}
	}
}

I’m a big fan of the 25-Line ActionScript Contest and will take part in the current (January) contest. I’ll come back to that in some future post surely.

All entries of the first contest (November / December) have been published on December 29th, but it is hard to browse them, because you can download an archive containing the txts only.
It took way too long looking through them all, so I decided to make things simpler. It was time to create an easy 25lines browser.

So, here it is: 25lines entry browser for Dec. 08
Have fun!

How I’ve done this
The first task was to publish all the SWFs. It would have taken hours to do this manually (open txt, copy&paste script, run test, rename swf).
I’ve always wanted to do some JSFL stuff and this was the opportuneness.
It took not very long to get started due to this two blog posts: JSFL FLA Batch Compiler by gskinner and CS4 MetaData JSFL Script by Keith Peters.


var lastId = 92;

function execute() {
	// open tester.fla
	var testerUrl = fl.browseForFileURL("open", "Please select the tester.fla", false);
	var dirUrl = testerUrl.substr(0, testerUrl.lastIndexOf("/") + 1);
	fl.openDocument(testerUrl);

	// get frame
	var doc = fl.getDocumentDOM();
	var tl = doc.timelines[0];
	var layer = tl.layers[0];
	var frame = layer.frames[0];

	// loop
	for (var i = 1; i <= lastId; i++) {
		var idString = addZeros(i);
		if (!FLfile.exists(dirUrl + idString + ".txt")) continue;
		var code = FLfile.read(dirUrl + idString + ".txt");
		frame.actionScript = code;
		doc.exportSWF(dirUrl + "" + idString + ".swf", true);
		FLfile.write(dirUrl + "idmap.txt", "," + i, "append");
	}
}

function addZeros(n) {
	var str = n.toString();
	while (str.length < 3) str = "0" + str;
	return str;
}

execute();

Maybe there would have been a simpler way without the tester.fla.

Now I created the html page, which wasn’t very difficult.
It uses an iframe to load the SWFs.

You can download the complete project and run it on your local machine.
When the current contest’s codes are released, you will of course be able to browse them here.

It took me quite a while to figure out how to get started with my own twitter app, so I thought it might be usefull writing down the steps to get started.
I use the open source FlashDevelop IDE, but in Flex Builder it should work identical.

First, create your project.
The next thing you need to do is loading the offical AS3 Twitter lib swc from google code.
This SWC contains a few classes only, you can browse them on the Source tab of the google code page.
Just put it into the lib folder of your project and, in FlashDevelop, rightclick it to select Add To Library.

Now, let’s go over to the code


package {

	import flash.display.Sprite;

	import twitter.api.Twitter;
	import twitter.api.events.TwitterEvent;
	import twitter.api.data.TwitterStatus;
	import twitter.api.data.TwitterUser;

	public class Main extends Sprite {

		private var api:Twitter;

		public function Main() {
			api = new Twitter();
			api.setAuthenticationCredentials("xathis", "password");
			api.loadFriendsTimeline("xathis");
			api.addEventListener(TwitterEvent.ON_FRIENDS_TIMELINE_RESULT, resultHandler);
		}

		private function resultHandler(event:TwitterEvent):void {
			for (var i:int = 0; i < event.data.length; i++) {
				var status:TwitterStatus = event.data[i] as TwitterStatus;
				var user:TwitterUser = status.user;
				trace(user.screenName + ": " + status.text);
			}
		}

	}

}

That’s it. There’s only this one Main class. All it does is loading your friend’s timelines and display them in the output panel.
Of course you have to change your username and password.
And remember, this is only an example, you should never leave your password hardcoded in a swf.

For more information on the twitter API take a look at the documentation at the API-Wiki

3 months ago I announced to make a phpMyAdmin theme and now here it is.

I’m no CSS geek, but playing with gradients a bit is no problem, … as long as they’re orange ;)

It looks a little different in the Internet Explorer, but who cares?

dowload theme

The theme files include PHP code, so be sure to check them for backdoors I could have built in…

Falls du noch immer opendir benutzt und dich mit readdir durch das Verzeichnis hangelst, … das geht auch einfacher!

glob ist das Zauberwort


<?php
echo '<images>';
foreach (glob('images/*.jpg') as $filename) {
    echo "\t".'<image><![CDATA['.$filename.']]></image>'."\n";
}
echo '</images>';
?>

Dieser sympatische 5-Zeiler durchsucht den Ordner images nach Dateien mit der Endung .jpg und spuckt eine wunderbare XML aus:


<images>
    <image><![CDATA[images/hund.jpg]]></images>
    <image><![CDATA[images/katze.jpg]]></images>
    <image><![CDATA[images/ziege.jpg]]></images>
</images>

« Previous Entries