Animation4j - Interpolation Functions

Interpolation Functions are a key concept in animation4j project, they define how to a variable should change from one value to another. To define interpolation functions in animation4j, InterpolatorFunction interface should be implemented, the API looks like this:

public interface InterpolatorFunction {

	/**
	 * @param t
	 *            A real number in the interval [0,1]
	 * @return The interpolated value.
	 */
	float interpolate(float t);

}

So basically, functions works for values of t between interval [0,1]. An example implementation of this function is a linear Bézier:

/**
 * Linear Bézier curve implementation of an InterpolatorFunction.
 * 
 */
public class LinearBezierInterpolatorFunction implements InterpolatorFunction {

	private final float p0, p1;

	public LinearBezierInterpolatorFunction(float p0, float p1) {
		this.p0 = p0;
		this.p1 = p1;
	}

	@Override
	public float interpolate(float t) {
		if (t < 0)
			return p0;
		if (t > 1)
			return p1;
		return (1 - t) * p0 + t * p1;
	}

}

The library already provides some implementations, you could instantiate them using InterpolatorFunctionFactory factory class. The API of the factory looks like this:

	// returns a cubic Bézier interpolation function based on the four specified points.
	InterpolatorFunction cubicBezier(float p0, float p1, float p2, float p3);

	// returns a quadratic Bézier interpolation function based on the four specified points.
	InterpolatorFunction quadratic(float p0, float p1, float p2);

	// returns a cubic Bézier interpolation function with presetted values.
	InterpolatorFunction ease();

	// returns a linear Bézier interpolation function.
	InterpolatorFunction linear();

	// returns a cubic Bézier interpolation function with presetted values.
	InterpolatorFunction easeIn();

	// returns a cubic Bézier interpolation function with presetted values.
	InterpolatorFunction easeOut();

	// returns a cubic Bézier interpolation function with presetted values.
	InterpolatorFunction easeInOut();

In the previous post we talked about transitions of variables from one value to another using Transition interface. When building a transition using the Transitions factory, you could specify the interpolation functions you want to use, if you don't, then linear Bézier functions are used by default. One example of how to create a Transition specifying the interpolation functions looks like this:

Transition<Vector2f> transition = Transitions.transition(
	new Vector2f(0f, 0f), 					// the starting value
	vector2fConverter, 						// the type converter (using two variables)
	InterpolatorFunctionFactory.easeOut(),	// the interpolation function for the first variable
	InterpolatorFunctionFactory.easeIn());	// the interpolation function for the second variable

One thing to mention is that Transitions factory methods use a varargs to specify interpolation functions parameters because we don't know beforehand how many variables you need. In case you specify less functions than variables, then linear Bézier functions will be used for the variables without functions specified.

As we said on the previous post, animation4j API could change since this blog post was written. API used for this post is the one of the current released version 0.0.8 (already uploaded to maven central).

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

JNLP Downloader Tool

Some time ago, Rubén wrote a Java based tool to download all JNLP resources and prepare executable files to run it based on the JNLP file values.

It downloads all the resources specified by the JNLP file and save them into /libs and /natives for jar resources and nativelib resources respectively, in the second case it creates sub folders for each platform (Windows, Mac and Linux). After that, it creates one executable script file to run the application for each platform, configuring classpath and java.library.path inside it.

For example, running the tool:

 
 java -jar jnlpdownloader.jar example http://www.example.com/application.jnlp

where the JNLP contents are:

 
<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+" codebase="http://www.example.com/" href="application.jnlp">
    <information>
            <title>Some Title</title>
            <vendor>Some Vendor</vendor>
            <description>Some Description</description>
    </information>
    <resources>
            <jar href="slf4j-api-1.5.8.jar" />
            <jar href="google-collections-1.0.jar" />
            <jar href="lwjgl-2.4.2.jar" />
    </resources>
    <resources os="Windows">
            <nativelib href="lwjgl-2.4.2-natives-win.jar" />
    </resources>
    <resources os="Linux">
            <nativelib href="lwjgl-2.4.2-natives-linux.jar" />
    </resources>
    <resources os="Mac">
            <nativelib href="lwjgl-2.4.2-natives-mac.jar" />
    </resources>  
    <application-desc main-class="Main" />
</jnlp>

will create the next file structure:

 
./example
./example/natives
./example/natives/Linux
./example/natives/Linux/liblwjgl.so
./example/natives/Windows
./example/natives/Windows/lwjgl.dll
./example/natives/Mac
./example/natives/Mac/liblwjgl.jnilib
./example/libs
./example/libs/google-collections-1.0.jar
./example/libs/slf4j-api-1.5.8.jar
./example/libs/lwjgl-2.4.2.jar
./example/run-windows.bat
./example/run-macosx.sh
./example/run-linux.sh

More info at the project's home page.

We used this tool mainly to take a snapshot of a deployed Java Web Start application to make it run offline, for demo purposes.

VN:F [1.9.22_1171]
Rating: 5.0/5 (1 vote cast)

Games as Applets 2

Talking with kappaOne, one of the LWJGL developers, he pointed us that our applet solution has one problem. When js is disabled or it has failed to load, then the applet tag is not written, then the game is not loaded.

In order to fix this problem, we adopted part of his solution. He always creates the applet tag for the game and then hides it using js. If for some reason js fails, then the applet starts automatically.

The new html needed looks like this:

Html:

  
<div id="applet" class="applet" align="center">
	<applet id="gameApplet" width="800" height="600" code="com.gemserk.games.appletverifier.AppletVerifier" archive="http://www.gemserk.com/appletverifier-0.0.1-SNAPSHOT.jar">
		<param name="jnlp_href" value="http://www.gemserk.com/prototipos/zombierockers-webstart-release/launch-applet.jnlp" >
	</applet>
</div>

And this is the modified js with a merge between his solution and ours:

Javascript:

  
var width="800";
var height="600";
var jnlp_href="http://www.gemserk.com/prototipos/zombierockers-webstart-release/launch-applet.jnlp";
var screenshotUrl="http://blog.gemserk.com/wp-content/uploads/2010/12/zombierockers-screenshot01.jpg";
var appletTag;

var requiredVersion = '1.6.0_10+'
var attributes = { code:'com.gemserk.games.appletverifier.AppletVerifier',  width:width, height:height} ; 
var parameters = {jnlp_href: jnlp_href}; 

hideApplet(); 

function hideApplet(){
	var appletbox=document.getElementById('applet');
		appletTag = appletbox.innerHTML;

	if (navigator.appName == 'Microsoft Internet Explorer') {
		var params = "";
		var p = appletbox.getElementsByTagName("PARAM");
		for(var i=0; i < p.length; i++) {
			params += p[i].outerHTML;
		}
		appletTag = appletTag.replace("</APPLET>", params+"</APPLET>");
	}

	var isRequiredVersion = deployJava.versionCheck(requiredVersion);
	var text = ""
	var callback = ""

	if (isRequiredVersion) {
		text = "Click to play"
		callback = "showApplet()"
	} else {
		text = "You don't have java plugin enabled, click to install"
		callback = "installJava(\'" + requiredVersion + "\')"
	}

	// adds the screenshot inside the applet div
	var screenshotDivHtml = "<div id=\"screenshot\" class=\"play\" onclick=\""+callback+"\" style=\"width:"+width+"px; height:"+height+"px;\">";
	screenshotDivHtml += "<span>"+text+"</span>";
	screenshotDivHtml += "<img id=\"screenshotImage\" src=\""+screenshotUrl+"\" alt=\""+text+"\" width=\""+width+"px\" height=\""+height+"px\">"+"</img>";
	screenshotDivHtml += "</div>";

	appletbox.innerHTML=screenshotDivHtml;
}

function showApplet(){
	var appletbox=document.getElementById('applet');
	appletbox.innerHTML = appletTag;
}

function installJava(version) { 
	deployJava.installJRE(version);
}

You can see a working example here.

Thats all.

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

Ludum Dare 19 Results

Well, Ludum Dare 19 is finished, obviously Discover the Way didn't won any category, but at least we have some feedback.

The game made position 58 of 133, this is its rating:

Inn Fun The Gra Aud Hum Ove Com
3 3 3 4 2 - 3 -
2 3 2 3 2 2 3 5
4 3 2 3 2 2 3 3
3 3 2 3 3 - 3 3
2 1 1 3 1 1 2 -
3 4 5 3 - 2 4 5
2 2 2 3 2 1 2 -
2 3 2 4 2 1 3 4
3 3 1 3 3 - 3 3
4 5 3 4 3 1 4 3
2 2 1 3 3 - 3 3
3 3 2 3 2 2 3 2
3 3 2 3 3 - 3 3
3 1 1 3 2 - 2 2
3 3 3 3 2 - 3 4
4 2 4 4 4 - 3 4
2.88 2.75 2.25 3.25 2.40 1.50 2.94 3.38

Follow the link to the game page at the contest if you want to see users comments, remember though that people rated the first version which was not polished nor balanced enough.

Here you can see all Ludum Dare 19 results.

Some final thoughts:

First of all, I really liked the idea of the game, but on the other hand I knew it wasn't going to win. However, I believe I made some mistakes that made the game have a worse rating.

The first mistake was the name, I named the game Discover the Name because I had no game by that moment, I was deciding what to do and though it was a funny name. After realizing the main objective was to discover a safe path between two points, then I thought to change the name to Discover the Way or Discover the Path, to give the player an idea of what he has to do, but I didn't. That caused confusion to the players because they were expecting they have to discover a hidden name, not a hidden path.

Another mistake was to be to lazy to make some balance to the game before the contest ends, I finished the game about 2hs before but I was tired so I entered that version. The day after, I took less than 1hr to balance it a bit, and the game changed a lot, it became more playable and it gave more importance to the main objective because the player couldn't take shortcuts to the targets any more, he has to discover a safe path, that is the real relation to the contest Theme (Discovery).

The third mistake, less important than the others was to remove the gameplay video from the game's page. The game's entry allow contestants to put only 5 links. At fist I put a link to the game, to the source code, a link to our blog, a link to the a gameplay video and a link to the jam version of the game, but after I uploaded the timelapse video to youtube I had to remove one of the links and the gameplay video seemed to be the best choice because I had a link to it inside our blog. That was a mistake because new players watched the gameplay video to see what they have to do in the game, it was some kind of tutorial, without it players felt disoriented.

I made a short postmortem at Ludum Dare's blog, follow the link if you want to read it.

That's all, thanks for reading.

UPDATE: added game position and updated link to Ludum Dare 19 results in order.

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

Games as Applets

As you may know, we are publishing our games in two formats, Applets and Webstart. Applets works in a similar fashion as a Unity or Flash applications does, you open the web page and the game loads inside it. Webstart applications starts as a desktop application, outside the browser.

In this post we will explain how we deal with Java Applets. One thing we didn't like about applets is that they starts as soon as you visit the page, sometimes you want to visit a game page only to see some information or read comments, etc.

We created a workaround for that, it consists in showing a game's screenshot with a text "click to play" and whenever a player clicks on it, the game is started.

Implementation

Our solution consist in a css with the styles to show the screenshot with the text and a javascript with the logic to change the screenshot with the Java Applet.

First we have styles to show the text over the screenshot and highlight it whenever the user moves the mouse over it.

Style:

  
.play {
	display:block;
	position:relative;
	-moz-opacity:0.80;
	opacity:0.80;
}

.play span {
	-moz-opacity:0.60;
	opacity:0.60;
	display:block;
	position:absolute;
	top:225px;
	z-index:100;
	width:100%;
	color: white;
	font-size: 80px;
	text-align: center;
}

.play:hover span {
	-moz-opacity:1;
	opacity:1;
	display:block;
	position:absolute;
	top:225px;
	z-index:100;
	width:100%;
	color: white;
	text-align: center;
}

Then, we have some javascript to create the screenshot div dynamically, and to replace it with the applet tag when the user clicks on it, or send the user to install the needed version of Java if he hasn't installed yet.

Javascript:

  
	var requiredVersion = '1.6.0_10+'
	var width = "640"
	var height = "480"
	var screenshotUrl = "floatingislands03.jpg"

	var url = "launch-applet.jnlp";
	var attributes = { code:'org.newdawn.slick.AppletGameContainer',  width:width, height:height} ; 
	var parameters = {jnlp_href: url}; 

	var isRequiredVersion = deployJava.versionCheck(requiredVersion);
	var text = ""
	var callback = ""

	if (isRequiredVersion) {
		text = "Click to play"
		callback = "startGame()"
	} else {
		text = "Click to install Java"
		callback = "installJava()"
	}

	var screenshotDivHtml = "
"; screenshotDivHtml += ""+text+""; screenshotDivHtml += "\""+text+"\""+""; screenshotDivHtml += "
"; var appletElement = document.getElementById('applet'); appletElement.innerHTML += screenshotDivHtml; function startGame() { var screenshotElement = document.getElementById('screenshot'); var appletElement = document.getElementById('applet'); appletElement.removeChild(screenshotElement); var oldwrite = document.write; var newHtml = ''; document.write = function (str) { newHtml += str; } deployJava.writeAppletTag(attributes, parameters); document.write = oldwrite; var realAppletElement = document.getElementById('realApplet') realAppletElement.innerHTML = newHtml } function installJava() { deployJava.installJRE(requiredVersion); }

Also, we will need to add two divs to the html to make the javascript to work.

Html:

  

That's all, if you want to take a look at a working example, click here.

VN:F [1.9.22_1171]
Rating: 5.0/5 (2 votes cast)

Ludum Dare 19

Again, as we did for Ludum Dare 17 and Ludum Dare 18 Jam, we decided to participate in Ludum Dare 19 (and possibly to the Jam too). The theme for this Ludum Dare was Discovery.

In this case, only one game was made in time for the compo, the name is Discover the Name, follow the link to see a description, play the game, watch a gameplay video or make comments if you want. Development time lapse and source code will be available soon.

There is also a page dedicated for the game here.

Hope you enjoy the game.

VN:F [1.9.22_1171]
Rating: 5.0/5 (1 vote cast)

Humble Indie Bundle #2

The second Humble Indie Bundle is released, this time containing: Braid, Cortex Command, Machinarium, Osmos and Revenge of the Titans, all DRM free and for Windows, Mac and Linux.

As well as the first HIB, you can pay as you want. The money you pay goes for the developers, for charity (Electronic Frontier Foundation and/or the Child's Play Charity) and for the HIB itself, you decide how much for each one.

By the time this post was written, they had a revenue of $470,446.62 made in only one day. They have 6 days left to keep making money.

Here is the HIB promo video:

Go and buy it!

VN:F [1.9.22_1171]
Rating: 5.0/5 (2 votes cast)

Enter the contest - JSnakes

Today was the date limit for the contest we talked about some posts ago, and we can say JSnakes one of the contestants.

Sadly, we are not satisfied with the current state of the game, there are a lot of mechanics we wanted to try but we could not implement them because of serveral reasons. However, one of our main objectives was to at least enter the contest, so that we could establish contact with other developers.

The game version for the contest is on this link, you can try it if you want. That version is not going to change if we keep working on the game.

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

Android development

We have been wanting to try the Android platform for some time and just recently bought an HTC Desire phone (It rocks, not so much the multitouch implementation).

Right now we are:

  • Investigating the platform, going through the API and Best Practices, to see what kind of games we can do, and how easy it is.
  • Decoupling our engine from some libraries like Slick2d and Groovy in order to test if we can reuse it for Android development.

One huge issue with Android right now is that the market has support for selling apps from a little list of countries. Of course Uruguay which is where we are from is not one of those. So we have to see if we can make things that can be supported with ads, donations, other markets (not the main android market), or some other solution.

We will be making some update when we have more knlowledge about this interesting platform.

VN:F [1.9.22_1171]
Rating: 4.0/5 (1 vote cast)