•
As part of the Lost Garden prototype challenge for Fishing Girl, we’ve started some work on the behavior of the game’s fish. According to the specification, the fish in this game are defined by the following properties…
Fish are objects in the sea that move back and forth in predictable patterns. Fish come in different sizes, rarity and movement patterns.
- Movement: Back and forth. There are others patterns such as circles or swarms, but that would be extra.
- Size: Small, Medium, Large, Extra large.
- Rarity: Common, uncommon, Rare, Very Rare. This is used during “Scoring the Fish”
Fish are spread throughout the water with more valuable fish located further from shore. Try to have a good mix of big fish and small fish. You can start testing with one fish, but ultimately, you should have 10 to 20 or else the game won’t be very interesting.
All three of the bullet items have been implemented. We’ve also implemented the “attraction” behavior when the fish approaches a lure. However, the integration with the scoring system will come when the fish are added to the actual game. We decided to create a new Fish Tank application as a playground of sorts to experiment with ideas outside the scope of the other game mechanics. We did this for a couple of reasons.

- Isolation of the fish behaviors makes debugging a lot easier and faster.
- It provides a nice way to spotlight this single element of the game and rapidly iterate based on feedback. We can also experiment with some of the “hooking” elements of the game in an easily controlled environment.
- The power of sharing means it doesn’t matter where we create the fish. Once we’re happy with their behavior we can simply share them back to the community and re-use them in any other application! All we need to do is drag and drop them into our game.
Go check out the fish tank and send us your feedback!
Next up…. implementing the lunge.
•
I’ve always advocated for Sharendipity as a great platform for rapid prototyping of games. Now, I’m going to try to put my money where my mouth is and create a game based on someone else’s design.
Daniel Cook over at Lost Garden does some really fun game prototyping challenges. In providing all of the artwork, he really allows the game designer to focus on the actual design rather than the implementation. The most recent challenge is for a game called Fishing Girl. My interpretation of the game can be found here: http://beta.sharendipity.com/assets/1900/.
As of the writing of this post, only the casting mechanic is finished. In creating the early prototype, i just love how easy it is to adjust game play in real time. In continuing work on our port to flash, I’m constantly annoyed by how often i’m making small changes in the application that require a complete re-compile and re-launch of the project. When creating something in Sharendipity, there isn’t any of this. I get to play around with the gameplay, moving around images and tweaking parameters, seeing them take effect immediately.
If you’re interested, I invite you to create your own prototype in Sharendipity. We’d love to hear what your experiences are as we continue to improve the editing tools.
•
This is part 5 in a series of posts that address the issues involved in porting a large Java RIA to Flash. I recommend reading the previous posts as well:
Part 1: We’re Moving to Flash. Here’s Why
Part 2: Important Differences Between Java and ActionScript 3
Part 3: Beginning the Actual Port
Part 4: Anonymous Classes and the Adapter Pattern
Another main difference between Java and ActionScript is in how data is communicated to and from the server. In just about any Rich Internet Application this is going to be an important part of your architecture, so it’s important that it is handled correctly.
Synchronous vs. Asynchronous Communication
In Java it is possible to make a blocking call when requesting data from the server. Typically this will happen on a background thread and the programmer handles the returned data in the same thread. In ActionScript, it is not possible to block while data is being requested from the server. This can cause some challenges if you’re trying to port a project to ActionScript.
Java Threads
Fundamentally, the only real difference here is where the threading happens. This exact same functionality could be implemented in Java as well, you just need to manage the data yourself. In Java however, there is no guarantee when the remote call will return. The thread on which the request occurs will continue processing in parallel with your main event thread, so you may want to implement a task queue that guarantees that the handling of returned data happens at a particular time. If you don’t do something like this, you will probably have to handle synchronization issues because you will now have two threads running simultaneously. This will be covered in a bit more detail later in the post.
Because of these issues, if you’re using a programming language that has a threading model similar to Java’s, you may want to rework a few things before starting into the port, but it isn’t necessary. We did it afterward so it’s clearly possible.
ActionScript Data Requests
In ActionScript, data can be requested using many different methods. With all of them, you handle returned data by adding event listeners to the object. For example:
public function executeRequest(tHandler:Function, tErrorHandler:Function) {
// Create the URL loader which will perform the actual communication with the server.
var tURLLoader:URLLoader = new URLLoader();
// Register an event listener that will respond to the completion event
// and notify the response handler.
tURLLoader.addEventListener(Event.COMPLETE, function completeHandler(tEvent:Event):void {
// Instantiate a new response object which makes retrieving data
// from the response simple.
var tResponse:ServerResponse = new ServerResponse(tURLLoader.data);
// Pass the response to the handler.
tHandler(tResponse);
});
try {
// Execute the load. A successful callback will be passed to the
// handler, and any Error will be passed to the error handler.
tURLLoader.load(tURLRequest);
} catch (tEx:Error) {
if (tErrorHandler != null)
tErrorHandler(tEx);
}
}
This little piece of code actually has a lot going on, and is indicative of the model we’re using for communicating the server response back to the client. Let’s look at the completeHandler() function first.
When the data is returned to the client, completeHandler() creates a ServerResponse wrapper around the data and passes that off to the handler that was passed in. The URLLoader’s data property holds the byte array that was returned from the server. The ServerResponse is what is used to unwrap that data. It contains functions such as nextInt(), nextString(), etc. that will pull the values out of the array and return them to the caller.
There are also two different anonymous functions passed in to the executeRequest() function. I’ll note that there are much safer ways to do this. In my last post, I described a DynamicImplementation class that would be perfect for passing in data handlers to this method. The handlers are currently very simple only because we know that there is a single parameter to each one.
The important point here is that we are providing the data handler to the exceuteRequest() function so that we can process the returned data when it is returned. In Java, the model was that the ServerResponse itself would be returned as a result of the executeRequest().
Using a Task Manager
I’ve also mentioned in previous posts that you may want to use Runnables for posting tasks to a global task manager. One problem with moving from a multi-threaded to a single-threaded environment is in determining when exactly the data is being processed. If your communication was happening on a separate thread in Java and you were using the above model, then you may need to perform synchronization in your response handler. However, if you guaranteed that data manipulation never happened on any thread other than the event queue you could forget about this.
Using a task manager would allow you to pass in a Runnable to the executeRequest() function which can be posted to the task manager to be processed during the start of your main event thread. This is very similar to the model that Flash uses for when the events are processed as the result of the remote call.
Conclusion
Now that we have our communication architecture in place, we’re pretty much finished. This series of posts describes just about everything that we needed to do in order to get a working prototype up and running and it only took two weeks, including learning ActionScript. There are a few things that I didn’t mention in this series, such as the differences in drawing objects in Java and Flash and our underlying physics engine. If there’s interest, maybe we’ll post some information about this in the future.
We’ve described the big pain points that we’ve encountered along the way and the solutions that we’ve come across. It’s been a very interesting process and really makes me appreciate the work that we did up front to enable this port. If you’re thinking of moving to Flash, hopefully some of these posts will help you save some time yourself.
Tags:
ActionScript,
communication,
Flash,
Java,
network,
port
•
This is the fourth in a series of posts describing our port from Java to Flash. For the previous posts, see:
Part 1: We’re Moving to Flash. Here’s Why
Part 2: Important Differences Between Java and ActionScript 3
Part 3: Beginning the Actual Port
This post describes an implementation that allows you to get around the lack of anonymous classes in ActionScript. My biggest complaint about this solution is that it moves compile time errors to runtime. It does, however, hide these issues from the consumers of the implementation.
Adapters
One of the reasons that we were able to perform the port so quickly was because we have a generic asset description. All of our data is passed from the server via XML, so we just needed to figure out how to handle that data in ActionScript. We rely heavily on the adapter pattern to do this. In Java, we used anonymous classes to implement these adapters.
Anonymous classes are nice because using them allows you to define functionality through a particular interface. Here’s an example of an implementation of our XmlStringAdapter:
addAdapter(ATTRIBUTE_NAME, new XmlStringAdapter() {
public void setString(String sValue) {
// handle setting
}
public String getString() {
return [object's local value];
}
}
Ignoring the actual implementation of the getter and setter, it’s easy to see that we have provided an adapter that allows us to set and get values through a specific interface. Pretty handy, but impossible in ActionScript, at least in this manner.
In order to do this in ActionScript, we rely on flash.utils.Proxy. This is actually based off of the Decorator pattern in the book Object-Oriented ActionScript 3.0. We have our own class called DynamicImplementation:
package com.sharendipity.util {
import com.fived.error.RuntimeException;
import flash.utils.Proxy;
import flash.utils.flash_proxy;
public dynamic class DynamicImplementation extends Proxy {
private var mtProperties:Object = new Object();
public function DynamicImplementation() { }
/**
* Add a function to the dynamic implementation.
*/
protected function addFunction(sName:String, tFunction:Function):void {
if (mtProperties[sName] == null) {
mtProperties[sName] = tFunction;
}
else {
throw new RuntimeException("Duplicate function: " + sName + " in object: " + this);
}
}
/**
* Execute the dynamically added functions.
*/
override flash_proxy function callProperty(name:*, ...rest):* {
var tReturn:Object = null;
var tFunction:Function = mtProperties[name];
if (tFunction != null) {
try {
tReturn = tFunction.apply(mtProperties, rest);
}
catch (tError:ArgumentError) {
throw new RuntimeException("Incorrect number of parameters to function: " + name);
}
}
else {
throw new RuntimeException("Function [" + name + "] is not initialized for object: " + this);
}
return tReturn;
}
}
}
That’s a lot to digest. In essence, this class allows you to add dynamic, named functions to an object in a controlled manner. Note that there are no publicly visible functions. The idea is that your own objects can extend DynamicImplementation in order to provide their own interface. Let’s look at an example of how the above XmlStringAdapter might be implemented:
public dynamic class XmlStringAdapter extends DynamicImplementation implements IXmlStringAdapter {
private static const GETTER:String = "getter";
private static const SETTER:String = "setter";
private static const GET_VALUE_TYPE:String = "get_value_type";
private static const COMPARE_TO:String = "compare_to";
public function XmlStringAdapter() { }
/**
* Add the setter implementation to this adapter.
*/
public function addSetString(tFunction:Function):void {
addFunction(SETTER, tFunction);
}
/**
* Add the getter implementation to this adapter.
*/
public function addGetString(tFunction:Function):void {
addFunction(GETTER, tFunction);
}
public function getString():String {
return this.getter();
}
public function setString(sValue:String):void {
this.setter(sValue);
}
}
This implementation shows that we have four publicly available functions. It is expected that the IXmlStringAdapter exposes only the getString() and setString() functions and this is the interface that will be passed around, so most people will not see the addSetString() and addGetString() functions. Those functions are designed to be available only to the creator in order to define the dynamic functionality.
The new XmlStringAdapter class achieves a lot of what we’re looking for from anonymous classes. Mainly, external consumers of the class access it through a specific interface which is unchanged from the previous implementation. Furthermore, this interface is compile-time checked. As we’ll see later, however, the internals of the adapter are not.
If you look a little closer at the implementation, you’ll also notice that the underlying function names that the adapter is using are “getter” and “setter.” It is important that these names are different than the externally visible names of the functions in the class. If not, they can never get called. The names are also arbitrary, they are simply internal names that the object uses to call the functions being defined.
Let’s look at the corresponding ActionScript example that will implement the same functionality that we showed in Java in the beginning of this post:
var tAdapter:XmlStringAdapter = new XmlStringAdapter();
tAdapter.addSetString(
function setString(sValue:String):void {
// perform setter
}
);
tAdapter.addGetString(
function getString():String {
return [object's local value];
}
);
addAdapter(ATTRIBUTE_NAME, tAdapter);
As you can see, this is very similar to the original Java implementation. The main difference is that functionality is added through the addGetString() and addSetString() functions, rather than defining the implementation of the class itself.
The important underlying difference, however, is that several problems are not checked at compile time. This can create some frustrating results. First, it’s possible that you switched the getString() and setString() functions and passed the setter into addGetString(), and the getter into addSetString(). Second, you need to look into the XmlStringAdapter class to determine what the correct parameters are to the function that you’re implementing. If the types or number of parameters differ, you’ll get a runtime error.
Runnables
I mentioned in the previous post that the Runnable object can be implemented differently as well. In fact, it can use the same underlying DynamicImplementation:
package com.sharendipity.util {
import com.fived.error.ExceptionHandler;
import flash.utils.flash_proxy;
public dynamic class Runnable extends DynamicImplementation implements IRunnable {
public static const RUN:String = "perform_run";
public function Runnable() { }
public function addRunnable(tFunction:Function):void {
addFunction(RUN, tFunction);
}
public function run() {
this.perform_run();
}
}
}
Note that we will also have the Runnable class implement an IRunnable interface so as to hide the addRunnable() function from the consumers.
While ActionScript is inherently single-threaded, Runnables can be used to define tasks that run at specified intervals as managed by a global task manager. This can be nice for a lot of different reasons. As one example, which we’ll see in the next post, using Runnables may better facilitate the move from a multi-threaded environment to a single-threaded one when performing communication with the server.
Conclusion
You can get pretty close to the implementation of anonymous classes in ActionScript, but it’s certainly not fool proof. You’ll have to do more debugging at run time so be sure to check over your code with a fine-toothed comb when you come across these issues.
The next post will address issues of porting your communication code in a multi-threaded environment to a single-threaded one.
Tags:
ActionScript,
adapter,
anonymous classes,
decorator,
Flash,
Java,
porting
•
In the past few posts, I’ve mentioned why we’re moving to Flash and some of the things you should know before you try to do so yourself. I recommend reading up on it:
Part 1: We’re Moving to Flash. Here’s Why
Part 2: Important Differences Between Java and ActionScript 3
In this post I’ll talk about starting the actual port and addressing some of the things that are much harder to do beforehand because they would cause compile time errors. Many of these are syntactic changes but there are some other important points about data structure usage. The following posts will address some more advanced topics.
J2AS3
This little project helped us out immensely. It allows you to translate Java code to ActionScript 3. I modified the project slightly to take a directory and recurse through it to write out every Java file but other than that we pretty much used it as-is.
J2AS3 will get you most of the way there although there is still a lot of work to do. There are a few bugs in the project but nothing you can’t get through. The simpler issues that you will still have to fix will be highlighted in the post. The following post will describe some of the core logic changes that you’ll have to perform.
Getting Started with ActionScript
Now that you have a bunch of ActionScript files to work with, you need something to edit them. The Flex Builder IDE is decent for working with ActionScript files, but not great. There is also a 60 day trial so you can at least try it out. One suggestion: if you’re doing a lot of syntax changes then you probably want to turn off Build Automatically. The compiler is pretty slow and will try to recompile an entire project every time you make a change. Is is also missing a few other features such as simple code formatting. For syntax changes, you might want to find another editor.
String Equality
We work a lot with XML so we do a lot of string comparisons to determine what particular node you are dealing with. Java’s string equality uses the equals() method. ActionScript uses the == operator. So a simple line such as:
sString1.equals(sString2)
becomes
sString1 == sString2
This is significant only because it takes time to do the manual translation. I used the Find/Replace functionality to go through files one by one to ensure that we are only replacing string comparisons with this method and not other object comparison.
Exceptions
ActionScript does not have an Exception class, everything is derived from Error. It’s easy enough to change your custom exceptions to extend Error, but what about the stock Java exceptions, such as NumberFormatException, RuntimeException, etc.
In a lot of cases, I created our own exceptions that mirrored those of Java. This is easy as well, but the actual logic can be difficult to handle. Take NumberFormatException, for example. Java’s Integer.parseInt(java.lang.String) will throw a NumberFormatExcpetion if it can’t parse the string. If you’re using that code and relying on the exception, then you probably have statements like this:
int iValue = -1;
try {
iValue = Integer.parseInt(sValue);
}
catch (NumberFormatException tEx) {
// handle exception
} |
In ActionScript, a port of your code would change to:
var iValue:int = -1;
try {
iValue = parseInt(sValue);
}
catch (tEx:NumberFormatException) {
// handle exception
} |
Obviously, ActionScript won’t throw the NumberFormatException because you just created that class, so what should you do? My suggestion is to use utility classes. Lets say you have a StringUtils class, then you could define the following function:
public static function getInt(sValue:String):int {
var tTest:* = sValue;
if (sValue == null || sValue.length == 0 || sValue.indexOf(".") >= 0 || isNaN(tTest))
throw new NumberFormatException("Value was not an integer: " + sValue);
return parseInt(sValue);
}
|
This will allow you to leave your exception handling intact while porting only the integer parsing, which you’ll have to do anyway. It’s kind of a pain but if you’re porting from Java you probably need to be able to replicate the same functionality that Integer.parseInt() has. Other exceptions such as IOException can be a little more straightforward because you might just need to catch something else (if ActionScript throws it).
Runnables
The fact that ActionScript is inherently single-threaded doesn’t mean that you can’t use runnables. In fact, in a later post, we’ll see that in addition to a task manager this might make porting some of your code easier.
The Runnable() class in Java provides a single method: run(). In ActionScript you can create your own Runnable class that has its own run function. One way to use your own runnables is to create new classes that extend your new Runnable class and override the run() function. There’s another way to do it without creating an additional class. That’s what we’ll take a look at next time.
Synchronization
You don’t need it. If you only synchronize methods, you should be able to do a global search and replace on the synchronized keyword. If, however, you use double-checked locking or synchronize on mutex objects you might just need to do it a little more manually. Eclipse’s Find/Replace functionality works well here.
Using instanceof
I’ll avoid my rant about using instanceof at all. Sometimes it’s necessary. However, ActionScript’s notion of instanceof is a little different than Java’s. It has the same functionality as the Object class’ isPrototypeOf() function. This does not return true if you are testing whether or not the object implements an interface. For this, you want to use the “is” operator. It should be alright to just do a global search and replace for this, but I always like to be safe and go through the changes one by one.
Similarly, casting will use the “as” operator. In some cases, the translation with J2AS3 will work fine, but not always. You’ll get a compile error and you’ll just have to go fix them.
Function overriding
If you’ve read my last post, you probably know that a lot of my complaints about ActionScript have to do with the class architecture. Function overriding is another case of that. Functions must use the override keyword to say that they override another function. No big deal, but the translation here is pretty manual.
Breaking out of finally statements
There is a nasty bug that has to do with having multiple exit points in a finally clause. The only reason I mention it here is because it came up more than once in our code. Something of the form:
for (var j:int = 0; j<10; ++j) {
try {
trace("j: " + j);
}
catch (tEx:Error) {
// handle error.
}
finally {
trace("finished.");
break;
}
}
|
will throw this error:
VerifyError: Error #1030: Stack depth is unbalanced. 0 != 1.
If you run across this, just keep a boolean outside your loop for whether or not you want to break and check that in your for-loop.
Array Creation
J2AS3 doesn’t quite get declarations for array creation correct, but it comes close. The problem is that you won’t get a compile error from the statement:
var tObject:Array = new Object[10];
Instead, you get this error during runtime:
TypeError: Error #1007: Instantiation attempted on a non-constructor.
I went through our code base searching for the expression “new*[*]” with Flex Builder and was able to find the places where this was an issue. I still find myself typing that in by habit as well.
hashCode()
Objects in ActionScript do not, by default, have a hashCode() function. Java does. In Java, you can override the hashCode() method so that two different objects can map to the same location in a Java HashMap. This is really handy, so how do you provide this functionality in ActionScript?
ActionScript has a Dictionary class which can be useful (and as a commenter named morgan pointed out in the last post, it also has some issues). In ActionScript, the object’s ID is used as the key for the Dictionary. If two objects have similar internal IDs, you need a way to map those objects to the same location in a HashMap.
I found a HashMap implementation here that was very useful as a starting point. It does not, however, allow for mapping of objects based on a hash code. In order to do that, I needed to make my own HashCodeHashMap.
What was really nice was ActionScript’s handling of functions. There is also a HashMapEntry class that came with the code that I used that made this easy. I created a new version of the HashMap that could be used for objects that defined a hashCode() function. Here’s my new put() function for the class to give you an example:
public function put(key:*, value:*) : void
if (key != null) {
var tHashMapEntry:HashMapEntry = new HashMapEntry(key, value);
var tNewKey:*;
if (key.hasOwnProperty("hashCode"))
tNewKey = key.hashCode();
else
tNewKey = key;
map[tNewKey] = tHashMapEntry;
}
}
|
This code assumes that the hashCode() function will return an integer, which is a pretty safe bet if you’re porting from Java to ActionScript. It should in fact work regardless of what hashCode returns however, because the Dictionary will use the object ID for mapping. This code will also work with objects that don’t implement hashCode() but I use the original HashMap for those for performance. However, I haven’t profiled the new class yet and I’m guessing that this is a bit slower than the original code.
Iterating over HashMap Entries
In the last post I talked about wrapping data structure usage with your own interfaces. The previously mentioned commenter talks about the lack of functionality in the Dictionary class. Using your own implementations allows you to address some of these problems. The commenter also points out the ActionScript 3 Data Structures (AS3DS) project, hosted on Google Code. The HashMap class is a good implementation to use for iteration, allowing you to loop over the keys or values without having to create an Array and copy all of the objects into it.
Conclusion
If you’re actually doing a port, you’re well on your way to having a functioning prototype at this point. There are a couple of other problems that you’re going to come across. I have at least two more posts planned for the series so check back, or better yet, go grab the RSS feed. We’ll certainly let everyone know when our prototype goes live.
Tags:
ActionScript,
Flash,
Java,
port
•
In my last post I mentioned that we are moving to Flash. The response has been crazy, just check out the comments there. In the next few posts I will highlight some of our experiences in doing the port. It’s been an interesting ride… stay tuned for more.
There are a couple of places you can go to see what the main differences are between ActionScript and Java. Most of those posts address syntactical differences in the languages. In this post I’ll highlight the things that were either really important or a big problem for us and what you might want to address before undertaking a port to Flash.
Data Structures
I’m putting this item at the top because I cannot stress how important it was that we used our own interfaces to data structures for arrays, stacks, maps, etc. rather than relying on Java’s implementations directly. ActionScript only supports Array and Dictionary; no stack, no linked list, no queue. If you performed a port to ActionScript and were relying on these Java classes, you would be in trouble. If, however, you used your own interfaces for all of the data structures, you will only need to re-implement the data structures that you are wrapping, saving you a ton of time.
Interfaces
I dislike ActionScript Interfaces for one reason: no data members. What does this mean? For every high level type of object that you have, you are probably going to need another class for the constants associated with that class. It isn’t a huge deal but it contributes to code bloat and is a pain in the butt when you’re porting all the references to data members in the interface. Other than that, they’re identical to Java.
Abstract Classes
The lack of true abstract classes in ActionScript means that you must implement every method in an interface in a class that provides limited functionality from that interface. This can be done via the “virtual” keyword, but as with the interface issue, it also adds to code clutter and doesn’t seem truly necessary. If you have a lot of abstract classes in the chain from an interface to the concrete class, this gets annoying and messy.
EDIT: It seems that functions are declared virtual by default, so using this keyword does not provide any shortcuts, and you still need to declare the function bodies. It is unclear what exactly the virtual keyword does.
Anonymous Inner Classes
I’ll be addressing this one in a later post as well because it can lead to a lot of problems depending on your architecture. Suffice it to say that ActionScript lacks anonymous inner classes. If you use the Decorator or Adapter patterns the actual implementation can be a burden. As you’ll see, it pushes errors from compile time to runtime which can make development much more difficult.
Anonymous Functions
Java doesn’t have anonymous functions. Anonymous functions are actually really cool, except for one problem: what appears to be the lack of a local activation stack. Take this ActionScript code:
var i:int = 1;
var tFunction:Function = function() {
trace(i);
}
i += 1;
tFunction();
|
You get a print out of “2.” This can be incredibly confusing if you’re debugging complex code. In Java, you would have had to declare your variable as final and you could use it to your hearts content inside a method, such as a Runnable. In Flash, you need to create an additional local copy of the variable that is only used inside the function and initialize it to the desired value.
Another important point: anonymous functions are not compile-time checked for the number and types of parameters that are passed in, pushing more debugging off to runtime.
Exception Handling
Exception handling is pretty similar in ActionScript and Java, except for one big thing: There is no “throws” declaration in ActionScript. These types of problems are along the same lines as my biggest complaints with ActionScript: it makes debugging the application so much harder.
The availability of a “throws” declaration requires the programmer to handle the exception or pass it up to the caller. In either case, the programmer is acutely aware that there is an exception that might get generated as the result of calling a method. Without this, exception handing can propagate up the call stack until it is finally handled, causing unexpected runtime issues.
Function Overloading and Default Parameters
ActionScript does not allow the programmer to overload functions. This isn’t a huge problem, as they do allow for default parameters. In java, I might write:
public void defaultSetter(int iValue) {
setter(iValue, false);
}
public void setter(int iValue, boolean bForce) {
// whatever
}
|
In ActionScript, I write
public function setter(iValue:int, bForce:Boolean = false):void {
// whatever
} |
I like it. What I don’t like: what if you have multiple setter methods that take different types? Well you end up with a lot of functions like setFromString() and setFromInt(), etc. Fine. But, what if your constructor is the one being overloaded with different parameter types? Now you need a factory for your objects (which maybe you should have anyway…), which means more code bloat. There may be other ways to get around this via setters but refactoring that functionality can be a pain.
Nested Classes
ActionScript also lacks nested classes. Again, for Decorator or Adapter patterns this can be troublesome. It means that you need package-private access to functions or data members, slightly breaking some of the object oriented rules.
Recommendations
If you know about these problems then you can act before hand. If you have a project you want to port to Flash, use your IDE to do address these some of these issues before you perform the actual port. Learn to use the refactoring tools. It will make your life so much easier. Here are some tips:
- Wrap references to language-specific data structures in your own interfaces, even if they’re just pass-through.
- Pull data members out of interfaces into their own constant classes.
- If possible, name your anonymous inner classes and put them in their own file. A later post will address often-used anonymous inner classes such as Adapters.
- Pull out nested classes into their own files.
- Create Factories for classes that have lots of different types of constructors.
- Refactor setters that take different types of parameters. You can address default parameters after the port.
I’ll be following up this post with some thoughts about beginning the actual port to ActionScript. Check back soon!
Tags:
ActionScript,
Flash,
Java,
porting
•
This post is the first in a series regarding a complete port of a very large Java project to ActionScript. Stay tuned for the intricacies that arise in doing so.
 |
Goodbye, indeed.
Image via
Wikipedia |
I’ve been developing in Java for about four years now. For four years, I’ve defended the Java language. I’m moving on.
Up front, I’ll say that the reason we are moving to Flash is because of Java’s adoption rates. It is not, in fact, because of the language itself but because of Java’s deployment model. We suspect that we lose somewhere between thirty and fifty percent of users due simply to the fact that we are in Java.
This isn’t pure speculation, but backed up by a significant amount of internal data. There are also other game companies that have experienced the same thing.
The Technology
I’d actually prefer that we remained in Java. My background is in high-end visualization so I love that we could use OpenGL. This also means that in the future we could do lots of really fancy special effects. The problem is that OpenGL ties you to the hardware, and anytime you do that you are opening yourself up to a world of support problems. We’ve already seen our fair share.
The hardware isn’t really the problem though. We could have avoided using OpenGL and just used SWT, AWT, or Swing. There are other open source projects that we were using that we’ll have to dump as well.
It’s unfortunate, really. The Java language is way better than ActionScript and Java compilers are much more advanced. There are also more possibilities with Java. Moreover, even though Flex Builder is built on Eclipse, the Eclipse development environment for Java is years ahead. I say that with no bias, having just finished porting about 800 classes and nearly 60,000 lines of Java code to ActionScript.
The Java Brand Is In Trouble
Java’s brand is failing. JavaFX has long been touted as the solution to Java’s woes, but it has been too long in getting released. In the meantime, Flash has continued to dominate. Silverlight has come on as a competitor, but it will be years before it has the kind of market penetration that Flash has.
The single biggest problem with Java right now is the name itself. If you see the Java applet loading, you click every visible link that you can to get off the page.
Why Java In the First Place
We got to where we are now faster because we were in Java. We even knew that we would probably port to something else eventually. Because of that, we built a flexible architecture that wasn’t tied to the language but abstracted in many ways. From the way we used data structures to the way we persist our asset data, we made sure we weren’t reliant on Java. In doing so, we were able to take advantage of the tools that we were familiar with in order to get to the point where we had a complete understanding of the architecture we were building.
That’s where we were two weeks ago. In that time, we ported our player architecture to ActionScript, and I still have 41 days on my trial version of Flex Builder.
In the upcoming week or so I’ll be following up this post with a lot of the lessons that we learned along the way. It’s been a very rewarding and, at times, frustrating process. I hope you stay tuned.
Tags:
ActionScript,
Flash,
Java,
porting