Juten Tach,
since i
a) was working quite a lot with Box2D lately
b) am sitting next to Lars (aka nulldesign)
today we had the idea to combine the Box2D alchemy port with Lars’ ND2D graphics engine. The result involved lots of basketballs
Caution: You need the Flash Player incubator build for this to run:
[Update]: As commenters have already pointed out, the app below doesn’t work with the current flash player anymore. I would have to update Lars’ ND2D engine to make it work again, but i currently simply feel to lazy to do it
Juten tach,
i am currently involved in a fun project, where i am told to build a classical jump ‘n run game. Very nice. I am using the flash port of Box2d in its version 2.0.1. I know, that there is version 2.1, but it’s still alpha and i generally do not feel so comfortable using alpha software.
Like in most jump ‘n run games, we have moving obstacles, like little bricks, that move from left to right and back again and you have to jump on them to get over a giant abyss.
Now these moving bricks should move autonomously and indefinitely. Being a flash developer, first thing, that comes to mind is tweening them. But as we learn from many sources in the box2d community, this is actually a no-go, because we should rather use velocities and the real physics of Box2d to make things move. Makes sense to me.
So my first attempt was to reuse some of the smart scripts from Todd. And that worked quite well. Here is an excerpt of the script (actually with slight changes from my side), that will run in the usual world update method (box2d specific):
if(currentPosition.x >= initialPosition.x + movementDistance) { _direction = -1; }else if(currentPosition.x <= initialPosition.x) { _direction = 1; } var idealLocation:b2Vec2 = new b2Vec2(currentPosition.x + (_direction * (TRAVEL_SPEED / PhysiVals.RATIO)), initialPosition.y); var directionToTravel:b2Vec2 = idealLocation.Copy(); directionToTravel.Subtract(currentPosition); directionToTravel.Multiply(30); _body.SetLinearVelocity(directionToTravel);
So looking at this, after a while i thought, idealLocation is a point, that changes on every box2d world step and reflects the position, where the body should be. Isn’t that the same thing, that a tweener does? Of course, it is.
So changing this script to use a tweener like TweenLite or something is pretty easy. In my case, i am using TimelineMax, because i want to let my body to move back and forth infinitely (code simplified):
private var positionTracker:b2Vec2; private function initialize():void { positionTracker = initialPosition.Copy(); timeline = new TimelineMax({repeat:-1}); timeline.append(new TweenLite(positionTracker, 1, {x:initialPosition.x + movementDistance})); timeline.append(new TweenLite(positionTracker, 1, {x:initialPosition.x})); } private function onWorldUpdate():void { var currentPosition:b2Vec2 = myBody.GetXForm().position; var directionToTravel:b2Vec2 = positionTracker.Copy(); directionToTravel.Subtract(currentPosition); directionToTravel.Multiply(Environment.TIME_STEP); myBody.SetLinearVelocity(directionToTravel); }
So, what is happening here? Well, we keep a helper object, the positionTracker. This is our object, that gets modified by our tweener. It is a b2Vec2 instance, which has x and y attributes. We give the positionTracker our initialPosition of our box2d body. Then we create our tween, just the normal way we always use tweens. But we use our positionTracker with it.
Now, somewhere in our program we usually have a world update method, because that’s how Box2D works. And here we simply use the approach Todd uses in his tutorial, we take the current position of our body, calculate the difference from our desired location (which now is the location our tweener has calculated) and the current location and build a velocity vector from it, which we then set to our body.
The result is a crystal clear animation just the way we have defined it in our tween. But since we are setting a velocity, our body is still open for other forces, that have an impact on it. So in my case, when my character jumps on the brick, the brick eases off a bit, but quickly goes back on its path, which is a rather nice behavior, i think.
Juten Tach,
a commenter made me aware of a bug in the Process class of my CommandCollection library, thanks for that. During fixing the bug i also fixed a wrong reference assignment for ProcessEvent.currentCommand, so now this should work as expected.
CommandCollection is now at v.1.0.1.
Juten Tach,
a little quiz again. We have three classes:
The first one is the main class of our swf, InternalTest:
package { import flash.display.Sprite; import testPackage.PublicClass; public class InternalTest extends Sprite { public function InternalTest() { var publicClass:PublicClass = new PublicClass(); var ref:Object = publicClass.returnInternalClassRef(); ref.doSomething(); ref.doSomethingInternally(); } } }
Ok, in a package “testPackage” we have two other classes, PublicClass and InternalClass.
package testPackage { public class PublicClass { public function returnInternalClassRef():InternalClass { return new InternalClass(); } } }
package testPackage { internal class InternalClass { public function doSomething():void { trace("InternalClass did something!!"); } internal function doSomethingInternally():void { trace("InternalClass did something internally!!"); } } }
Now make a guess, what happens?
Well, it’s not too hard to figure out, right? But interesting to remember anyway. The call for doSomething() works, whereas the call for doSomethingInternally() ends up in an exception. So if you define an internal class, you can still pass its reference outside its package (loosing the type obviously). Any public methods can be called then, but internal methods not. Makes sense, does it? I was just thinking about it, because i asked myself, why one would declare a class internal, but still have public methods.
So it only makes sense, if you want to pass it around as either an untyped reference or as a casted interface implementation. Means, you could have an interface outside the package and the internal class implements it. Then within the package you could use the class by its direct class type and outside you would use it by its interface type.
Juten Tach,
today i release a little library i have been working on for quite a while. It contains three little class collections, i have used in the past and i thought, they might be useful for some.
CommandCollection is a little ActionScript 3 library around using commands. It includes three tools:
- Process
- BranchProcess
- StateMachine
Process is essentially a queue, in which you can put commands (synchronous or asynchronous), which will be executed sequentially.
BranchProcess is similar, but allows you to build a tree of commands with the ability of one commands result having an impact on which command comes next.
StateMachine is a classical finite state machine, that supports input commands for each state and is navigable. Means, you can aim for a state and the state machine will calculate a path to the target state and will try to reach it.
CommandCollection comes as .swc for integration into your project. Go check it out at http://code.google.com/p/command-collection/.
