not to implementations…
It was one of those days where those six words made a little more sense. I’m working on a game project that uses a Wii remote for control. I got sick of always having to start the bluetooth, then start the Wii Flash server and then turn on the IR bar, all so I could check some code change. See, I turn off the sensor bar and wii mote when I’m working in order to save batteries, and it’s a bit aggravating turning it back on so often. I decided I should be able to use the mouse if I wanted, and not have to always rely on the wii remote when testing.
I had something like:
public class Engine extends Sprite { private var controller:WiiController; public function Engine() { controller = new WiiController(); } private function gameLoop(e:Event):void { controllerIcon.setPosition(controller.getPosition()); }
I have a controller variable, which is an instance of the WiiController class. I can get the current position by calling the getPosition method. Similarly, if I want to pass the controller instance to a new class I would use something like: intro.waitForInput(controller) and then in the intro class I’d do: public function waitForInput(con:WiiController). Great.
But what happens when I want to use an instance of MouseController instead of WiiController? If there’s a getPosition method in MouseController, I can keep the same call in gameLoop. But anywhere the variable is typed, like when being passed to intro, WiiController will need to be changed to MouseController. Making all these changes is both cumbersome and prone to error.
This is where interfaces come in handy. An interface is like a contract in that if a class implements it, then the class must contain those methods outlined by it. Any public access for the class, must be outlined by the interface. The interface itself contains only method signatures, it is up to the class using the interface to implement the methods. Additionally the interface, like any class, can also be used as a data type and this is where the juju happens.
Instead of declaring the controller as a WiiController type, or a MouseController type, it’s defined as the interfaces type: IController. By convention, interface names begin with a I. So, the code previously shown becomes:
public class Engine extends Sprite { private var controller:IController; public function Engine() { controller = new WiiController(); } private function gameLoop(e:Event):void { controllerIcon.setPosition(controller.getPosition()); }
Everything is the same, except the initial declaration of the controller variable. If you now decide to use the mouse you’d only change the one line in the constructor to:
controller = new MouseController();
and everything will still work. Because both WiiController and MouseController implement IController:
public class MouseController implements IController public class WiiController implements IController
IController itself being simply:
public interface IController { function getPosition():Point; function getTilt():Number; function get trigger():String; }
So back to the original point – if you program to an interface then it’s much easier to make modular code.
UPDATE: Since I started this post I stopped using WiiFlash and it’s server – as the server is still a little buggy. I got crashes quite ofteh when turning wii remote off while the server was running. Now, I’m using GlovePIE which works great – 3 lines of pie script and you can use a Wii remote for your mouse. In fact you can use a PS3 controller, a joystick, etc. and it’s not limited to the mouse you can use a joystick to do keyboard input… Cool shit.
