March 20, 2010

Beware of JavaFX and null references

Yesterday I was trying to implement a simple Animation class, that could for example be used for animating sprites in a game. I wrote the following code:

public class Animation extends ImageView {
var index : Integer;
public-init var images : Image[] on replace {
timeline.start();
}

var timeline : Timeline = Timeline {
repeatCount : Timeline.INDEFINITE
keyFrames : [
KeyFrame {
time : 0.2s
action : function() {
if (index + 1 >= images.size()) index = 0 else index++
}
}
]
}

override var image = bind images[index];
}


Let's now create an Animation object as follows:

var animation : Animation = Animation {
images : drillingWell
}


You might expect that this would work just fine and that the program would display an animation of a drilling well. Since we are assigning the sequence drillingWell to Animation.images, this would call the on replace trigger. Which it does. However, during object instantiation the timeline variable is still null. This means that calling timeline.play() won't have any effect because JavaFX quietly ignores null references. Throwing a NullPointerException here would have saved me quite some time and work ;-).

To fix the code I had to assign the timeline in the on replace trigger itself, like this:

public class Animation extends ImageView {
public-init var images : Image[] on replace {
Timeline {
repeatCount : Timeline.INDEFINITE
keyFrames : [
KeyFrame {
time : 0.2s
action : function() {
if (index + 1 >= images.size()) index = 0 else index++
}
}
]
}.play();
}

var index : Integer;
override var image = bind images[index];
}