Manual

From Fisix Engine Wiki

Jump to: navigation, search

Contents

Introduction

Welcome to the home of the official manual for the flash Fisix Engine. If you’re already here, you’re probably eager to get started with the engine, but before you dive into it, there are some things you need to know. That’s what this manual is all about—understanding the capabilities and limits of the Fisix Engine, how it’s built, and how you can put it to the best use possible. This manual, along with the API reference, included example files, and tutorials on the website include everything you need to start using and experimenting with physics in flash.

Note: This manual will help you mostly with understanding the basic logic behind the varying parts of the engine. Although some code examples will be provided, you should refer to the API reference, example files, and tutorials for specific implementations.

About the engine

  • The Fisix Engine has actually been around for a while… well on my hard drive at least. I kept it there because until recently, Actionscript wasn’t powerful enough to perform the computations needed for interesting physics simulations in real-time. Now, with AS3, the flash player can perform mathematical operations about 10 times faster than before! What does that mean? That instead of fighting 10 bad guys at once, you can now fight 100 with little or no performance loss.
  • In it’s core, the Fisix Engine is built with the Verlet technique of integration, and many of the concepts presented in Thomas Jakobsen’s paper entitled ‘Advanced Character Physics’. Although the concepts stayed the same, many things have been altered, added, and optimized to gain performance while straying away from physical accuracy. The main reason for this decision was to aim this engine towards use in real-time applications that require physics which look realistic, but are not necessarily physics-book-accurate. After all, though AS3 is faster than AS2, its not nearly as fast as C, or even Java, and is really not ideal for physically accurate simulations, as those require the abilities to perform calculations much faster than possible in Actionscript’s virtual machine.
  • If you’re looking for a way to simulate a relatively large number of objects with good looking, and most importantly stable results in Flash, then this engine is for you!

Verlet Integration

As mentioned before, this engine uses the Verlet method of integration. This is mainly because this method is quick, easy, and stable (to read more about verlet, try this Wikipedia link).

Engine structure

The Fisix engine’s library structure is completely Object Oriented, meaning that every part of the library acts as a single object with tasks specific to it, and all the objects come together to form the engine. This makes it simple to understand, and also to replace/upgrade parts of the engine, or even add your own!

The FisixEngine Class

  • This is the first object you need to create in order to use the Fisix Engine. The FisixEngine class is the root of the simulation, and holds all of the information pertaining to it. It allows you to run, stop, and step through the simulation, as well as add objects, forces, display attachers, etc… There is no real reason to have more than one instance of this class in your application.
  • If you look at the api docs for the FisixEngine class, you’ll notice that all of its methods fir adding/removing objects are actually inherited from its super class—the FisixObject class. The FisixObject is really the main class of the engine. It provides functionality for adding, removing, and manipulating primitives if the engine. The FisixObject will be described in more detail in the next section, but for now you should know that though the FisixObject class holds most of the functionality needed to create the simulation, it is not enough. The FisixEngine class wraps the FisixObject class to serve as the root node of the simulation and hold simulation global objects and variables.

Starting the simulation

  • There are 2 ways to run your simulation. The first involves timers, and is independent from the frame-rate of your movie, while the second uses the ENTER_FRAME event.
  • To begin your simulation with the engine’s built in timer, simply use the FisixEngine’s startEngine() method. To pause the simulation, use the stopEngine() method. Note that the simulation cannot be played backwards or rewound to the beginning (unless of course, some code is written which saves previous states). To set the desired frame-rate of your simulation, you may use the setFPS() method. Here is a small example of using startEngine/stopEngine:
Example here
  • The second way to run your simulation is through event listeners, in which case the simulation will depend on your movie’s framerate.
  • To move the simulation forward by a given amount of seconds, we use the FisixEngine’s mainLoop(dt) method (where dt stands for the amount og seconds to advance the simulation by, usually less than 1). So if, for example, out movie is running at 30 fps, and we call mainLoop() on every frame, we will be calling mainLoop() 30 times a second. Thhis means that in order to advance the simulation by one second for every second the movie plays, we’ll advance it by 1/30 of a second every frame. A more general formula would be to advance the simulation by 1/framerate. Here is some example code:
addEventListener(Event.ENTER_FRAME,onEnterFrame);
var deltaTime:Number = 1/Stage.frameRate;

function onEnterFrame(e:Event){
	myEngine.mainLoop(deltaTime);
}

Which method should I use?

  • Although using startEngine/stopEngine is a little easier than event listeners, flash’s timers tend to be a bit choppy, which would make your simulation seem awkward. As a rule of thumb, use the event listeners for anything more than a quick physics experiment.

The FisixObject Class

In the Fisix Engine, a FisixObject is an object which holds a group of other objects together. A FisixObject can hold primitives like particles, constraints, and surfaces, as well as other FisixObjects.

Every object in the simulation has a parent FisixObject (or node) except for the root node, which will be an instance of the FisixEngine class.

It’s important to note that the positions of all primitives in your simulation are global, no matter how many nodes they are away from the root node.

Why use it? Of course, you could just add all the objects in your simulation to the root node without using any of the grouping techniques provided by the FisixObject, so why should you group things together? Well, I can think of 4 reasons:

  1. It allows you to logically separate groups of physical objects with different instance names, and manipulate them independently with ease. For example, you could have a class called Car which will extend FisixObject and contain all the code to create a car encapsulated within it. You can also have another class Tree which will follow the same principles. In your main simulation, you’d just be dealing with instance of Car and Tree, and not have to worry about the inner workings of each one, which makes your code more logical and intuitive.
  2. FisixObjects are used be the engine to optimize collision detection, which is the most demanding part of the simulation, by finding the smallest bounding box of closely related objects, as defined by each FisixObject.
  3. It allows you to activate/deactivate groups of objects with one line of code, as well as disable collision checking between all members of a group, and many other functions (see API reference for more on that)
  4. When it comes to simulation iterations (discussed a bit later), the importance of object grouping becomes apparent. To quickly explain, the amount of iterations (defined by the FisixObject.iterations property) a FisixObject is solved determines how rigid its constraints will be, and how accurately its inner collisions will be solved. If, for example, you want to make one group of of bodies very soft and jello-like, while keeping another rigid, you could easily do it by adding the objects to different FisixObjects, each with a different iterations value.

Here is some code to exemplify that:

Code for creating a rigid and soft body

Adding/Removing Objects

Iterations

  • The ‘iterations’ property is unique to the FisixObject class (and all those who inherit from it). It specifies how many times per frame to solve the constraints and collisions withing the FisixObject. The higher this value, the more times the collisions and constraints are solved, which means less penetration between bodies, and less stretched out constraints. More iterations also means more calculations, and more processing time. The trick is to find the right amount of iterations that will balance execution speed and how good the object’s behavior looks. A good general number should be between 3 – 5, while jello-type objects should probably be lower.
  • So what’s the difference between a constraint’s ‘stiffness’ value and its parent’s iterations? In theory, all constraints should be as rigid as their stiffness value, but when many objects pull on the same constraint, it tends to get more stretched out than its supposed to be, causing groups of objects to “wiggle” more than they need to. The higher the iterations value, the closest a constraint will behave like it’s supposed to with its stiffness value. So if you’re only connecting a small amount of objects together (around 3) you can keep the FisixObject’s iterations low, and use constraint’s stiffness values to control the stiffness of the object (since more iterations == more cpu, while more stiffness = =same cpu). If you have a bunch of objects connected to each other, increase the FisixObject’s iterations if you don’t want the constraints to stretch out.
  • Quick note: A quick and efficient trick to making soft bodies is to give the group a low amount of iterations. If the group is still too rigid, then start tweaking the springs’ stiffness values.
  • Also remember, that the ‘iterations’ value can be changed at any point during the simulation, allowing you to switch between accuracy and speed for different situations. For example, if there are many objects on the screen, you can decrease the iterations value as the viewer’s eye probably won’t notice the inconsistencies as well as when there are only a few items moving around.

InnerCollisions

  • A FisixObject’s innerCollision property specifies if the objects within the FisixObject should check collisions with each other. If you only want some of the objects to check collisions and some not to, you can subgroup the colliding and non-colliding objects (within 2 other FisixObjects) and place both in your original FisixObject.
  • It’s important to note that even if innerCollisions is set to false for a FisixObject, all of the objects within it will still collide with objects outside of it. For example, let's say you have a Blob FisixObject which is so jellowy that you have to let its particles intersect with each other. You set its innerCollisions to false, but the particles within the blob will still collide with objects outside the blob like walls, ground, other blobs, etc…

AxisAligned

When the axisAligned property of a FisixObject is turned on, the objects within it will become axis-aligned, or unable to rotate. Making your object axis aligned is as simple as FisixObject.axisAligned = true, and it’s very helpful when you want to make something where the objects within the group won’t move independently of each other. In other words, you'd use it if you need your object to be rigid. For example, let’s say you want to have a character walking on some terrain. You could use a lot of constraints to keep the character walking up-right the way you want it, but it’s a lot easier (and cheaper) to make it axis aligned so that all the particles within the character move as if they are part of a rigid body which never rotates (although the object won’t rotate from a collision, it can be rotated manually). So when axisAligned is set to true, the constraints in the FisixObject don’t really make a difference anymore because all the objects will always have the same distance from each other anyway.

MakeStatic

The CollisionObject

  • An instance of the CollisionObject class can’t be added to the simulation because it doesn’t represent any particular object or shape, but instead describes all of the general capabilities of a geometrical object. Each specific object inherits this class and adds properties and methods specific to itself.
  • The properties and methods of the CollisionObject apply to all those who inherit it. The most commonly used include material information, common to all collidable objects, and they are the material, friction, bounds, and traction. These affect the object’s reaction to a collision (check out the Materials section for more information)


Applying Forces and Thrusts

  • Every collision object has a collision body, which allows it to physically interact with the world. This means that it can exert forces on other objects, and forces can be applied to it. In our simulation, every CollisionObject can be manipulated through forces and thrusts. The two are very similar but have some subtle difference which should be noted:
  • A thrust moves the collision object by the given x and y pixel values as soon as it is called, which a force adds this value to the object’s acceleration which will only affect it in the next frame. Thrusting an object will get it where want it to be, but may cause penetration with other objects. Applying a force might have less of a direct affect it will help to avoid penetration. Experiment with both to see which works better in your given simulation.

thrustPoint and applyForcePoint

  • Applying a force to, or thrusting an object moves the object with uniform force. This is good for forces like wind or gravity, but what do you do when you need to apply a force at a specific point on the object? Use thrusePoint() and applyForcePoint()
  • These let you specify a force and a point at which to apply to the object. Applying a force or thrust at a specific point will yield different results than a uniform force, moving the object at an angle relative to the angle of the surface and the force.

The Vector Class

Primitives

  • Although FisixObjects are very usefull, they are really just the shell which holds the meat of the simulation—the primitives. Primitives are the actual physical obhects which populate the world, like Particles, Surfaces, containers, constraints, and magnets.
  • All of the primitives with a collision body (like particles and surfaces) are inherited from the CollisionObject class, and can be added to the simulation using the FisixObject.addObject() method.
  • The other primitives which have no colliding bodies (like magnets, constraints, etc…) can be added wihth adder methods specific to them such as addConstraint(), addMagnet()
  • Because of its unique nature, the FisixContainer also has its own adder method even though it has a colliding body. This is discussed in more detail in the containers section.

Adding/Removing Objects

  • All of the FisixObject’s adder classes take one argument which is the instance of the object you are trying to add. For example, to add a constraint to the simulation you would write:
Var c:StickConstraint = new StickConstraint(…)
myEngine.addConstaint(c)
  • In order to save some precious coding time, you can use the FisixObject’s ‘new’ methods to create and add an object in one line like so:
Var c:StickConstraints = myEngine.newStickConstraint(….)
  • These ‘new’ methods are available for every object that can be added to the simulation. Check out the API reference for the FisixObject for more information on those.

Particles

  • Particles come in all sorts of shapes and sizes, but they all have a few core things in common. All particles have an explicit position and acceleration, and implicit velocity. Explicit position and acceleration in that they are values which are stored and updated for each object, and an implicit velocity in that its derived on each frame from the object’s old and current positions. The velocities of our objects are implicit because this is the way Verlet integration works, and is what adds to the stability of the simulation.
  • Like the CollisionObject, you can’t add an instance of the Particle class to your simulation, instead it is inherited by the circle particle, WheelParticle, and PolygonParticle classes which can (and should) be added to the simulation.
  • The Particle class is used to describe the functionality and properties common to all ‘Particle’ type objects like:
    • Particle.pos – A vector representing the Particle’s current global position.
    • Particle.old – A vector which holds the Particle’s last global position.

CircleParticle

  • The CircleParticle represents a perfectly circular object, and inherits all of its functionality from the Particle class.
  • A Circle-Particle is axis-aligned, meaning it can never rotate. This is the simplest primitive in the engine, and should be used over all others whenever possible to preserve efficiency, as it is the simplest to solve.
  • For example, if you were to create a rigid body, it is probably most efficient to create a few overlapping CircleParticles which are constrained to each other. Although each particle doesn’t rotate independently, the resulting body will rotate realistically.
  • Note: Although creating a rigid body from overlapping circles doesn’t always cover the shape you need completely, the shape differences are almost always unnoticeable and allow for better performance.

WheelParticle

  • The WheelParticle inherits all of the functionality of the CircleParticle, except it has the added ability to rotate. This type of particle is a bit more expensive to compute than a CircleParticle so you should try to use CircleParticles whenever you don’t need the rotation feature to preserve efficiency.
  • Note than in order to apply an angular force on a WheelParticle, you must use the WheelParticle.rotateWheel() method.

GuideParticle

Surfaces

  • A surface is built of two points, both of which are vectors. If a vector provided is the ‘pos’ property of a particle, the surface will stretch between that particle to the other vector, and move where ever that particle does. A regular Surface (of the Surface class) has the ability to move if its particles move, but does not react to any collisions. This means that a regular Surface build of dynamic particles will act as a moving wall of infinite mass. If you’d like your wall to act as a dynamic object, use the DynamicSurface class instead. Surfaces don’t have a set length (and you won’t find a ‘length’ property in there either) because their length depends on the position between their two vectors. If you would like to keep a DynamicSurface at a certain length, just StickConstraint both of its particles
  • When should I use Surface over DynamicSurface?
    • Whenever you are creating a surface that never moves. You’ll notice that Surface requires 2 vectors as its constructor arguments, while Dynamic surface requires 2 particles… this is because regular surfaces are built to stretch out over many points (like a terrain), without having to have these points be particles (which take up more space than vectors). In addition to that, whenever you create a static surface, it’s good practice to make it static (see makeStatic() command below), in the case that it’ll never move.

Constraints

  • There are two main types of constraints in the FisixEngine—Distance-based and Angle-based. In the Distance based category we have the SpringConstraint and StickConstraint(which is a spring constraint with stiffness set to 1). For angular constraints, use the AngularConstraint class. Every constraint in the engine extends the Constraint class, and every constraint type in the engine has the following properties/features:
    • stiffness – a value between 0 – 1 where 1 is completely stiff
    • restLength – A value representing the target value of the constraint at all times. (For distance constraints, this is their desired distance, and for angulars it is the desired angle)
    • min/max Values – If you come across a situation where you need the distance/angle of your constraint to range between two values other than a single restLength, set the constraint’s min/max properties for lower/upper bounds respectively. Once you set the min or max property of a constraint, its restLength is automatically set to -1. If you’d like your constraint to only be bound on one end, set the respective min/max value to -1.

SpringConstraint

This is a distance-based constraint, and is used to keep two particles at a fixed distance from each other. Depending on the stiffness of the spring constraint and forces applied to them, the distance between the particles may vary.

StickConstraint

Simply a spring constraint with a constant stiffness of 1

AngularConstraint

  • Like all angles in the engine, angular constraints use degree values (over radian). A valid value for a degree of an AngularConstraint is between 0 – 360. you’ll never get a negative value there

Setting min/max angles of an AngularConstraint. The min/max functionality of constraints is used often with AngularConstraints to bound 3 particles between 2 angles (ie. Making an arm rotate realistically instead if being able to rotate 360 degrees). Here is a little example of how you’d do that with Fisix:

Let’s say you have 3 Particles—Shoulder, Elbow, and Wrist (as in picture below) and you’d like to constraint them in such a way that the arm never rotates less than 30° or more than 180°. In your simulation you can simply say this:

var a:AngularConstraint = new AngularConstraint(Shoulder,Elbow,Wrist,30,180);

That’s all you have to do! Easy eh?

  • A quick word about angles in AngularConstraints: The angle on an angular constraint is measured as follows:
    • Let’s call the line formed between particleA and particleB lineAB and the line between particleB and particleC, lineBC.
    • When lineAB lies on lineBC, the angle of the constraint is 0/360 As lineBC rotates clockwise, the angle increases
    • Note: By their nature, angular constraints are less stable than springs, and should be used sparingly. Use a spring/stick over an angular constraint whenever possible.
    • I you find that angular constraints are making your object unstable, look into the GuideParticle

Containers

  • When your simulation is running, the Fisix Engine is hard at work, trying to do its best so the various objects it is responsible for don’t intersect or penetrate each other. A FisixContainer (or just Container for short) on the other hand, is there to do just the opposite. It always keeps its contained objects within its bounds, and they can never escape.
  • The FisixContainer class does not represent any one type of container, but instead describes the general characteristics common to all containers. Every container in the engine inherits this class and all of its functionality. Some examples of containers are the CircleContainer and WheelContainer (which can be found in the com.fileitup.fisixengine.containers package). Essentially all containers are the same:
  • The ‘shell’ of the container is a CollisionObject which interacts with its environment the same way it would if you just added it to the simulation. This object is stored in the collisionObject property of the Container and is different for every different Container type. A FisixContainer also has a child FisixObject which holds all of the objects within the container. This FisixObject is represented by the FisixContainer.objects property, and may be used to add/remove objects to the container like any other FisixObject.
  • Every FisixContainer also has a property called innerDynamics which specifies whether or not the movement of the objects within the container will affect the shell’s movement. This value can be turned on/off at any point during the simulation.

Magnets

A magnet attracts or repels objects within its parent FisixObject.

  • Magnets have a force property which controls strength and 'polarity'. Positive force values attract and negative values repel.
  • Magnet groups can be defined to control which objects are affected by a magnet.
  • A Magnet has no collision shape and is generally attached to another object.

Utilities

SceneQuery

The SceneQuery class provides static methods to help you get information about the scene. You can use it to check containment of objects within a rectangle or circle, ray collisions, individual objects collisions, etc.

Raycasting

Bounding Rectangles/Circles

objectsColliding()

MouseAttacher

The MouseAttacher object lets you easily connect a Fisix object to the mouse cursor.

var mAttach:MouseAttacher = myEngine.newMouseAttacher(ballParticle, this, 2);

Note that you can only add MouseAttachers to the FisixEngine class, and not individual FisixObjects

The first parameter is the particle to be attached to the mouse cursor. The second is the display object from which the mouse position value will be used, and the third value is the easing factor. Easing specifies the 'stretchiness' of the connection between the mouse and the object, with 1 being a rigid connection and higher values being progressively less rigid. It's a good idea to make your connection less rigid in order to prevent penetration when pulling objects quickly.

There are two ways to enable/disable MouseAttachers, much like every object in the engine. You can either set its active property to false, or remove it from the simulation and add it at a later time.

You can turn the MouseAttacher's 'active' property to true or false in order to activate/deactivate it. The default value it true

mAttach.active = false;

If you are done with the mouse attacher, you can remove it from the simulation like so:

myEngine.removeMouseAttacher(mAttach);

At this point, you can either dispose of the mouse attacher in order to free up memory or keep it in order to add it to the simulation at a later time.

to add it later, just use:

myEngine.addMouseAttacher(mAttach);

To dispose of the object, use:

mAttach.dispose()
mAttach=null
//if there are any more variables pointing to the mouse attacher, set them to null as well.

Resources

FractalTerrain

Bullet and Projectile

Conveyors

Rope

Personal tools