Speed that is not TWIP

ericlin@ms1.hinet.net


It is common to script movement of a movieClip by adding and/or subtracting the _x by a speed value. When we make it go forward, we increase _x by this speed. When we make it go backward, we reduce the _x by this speed value.

Usually it works fine. At least, we wont notice any obvious problems.

Let me try a simple question. What if we make a speed of 20/3 ? 

OK, we know Flash accept an accuracy of 0.05; What we say, the unit of TWIP. A pixel consists of 20 twip. So, we would expect Flash "round" the speed value to TWIP. The value 20/3 is  6.66666666666667, so I guess it will be round to 6.65; When it goes forward, the _x will increase by 6.65 and when it goes backward, _x will decrease by 6.65; Am I correct ?

Did you ever test it ?

The answer is , it is 6.65 for increase and 6.7 for decrease. There is a difference of 1 twip, that is 0.05 twip. 

If we make a movieClip onEnterFrame _x increase (20/3) and then decrease (20/3), it will not stay where it is. The movieClip will deviate toward the 0 point gradually. Please look the movie below, check the right upper corner. You might need to reload this page/movie if the yellow block is already encroaching the edge.

If we make a movieClip goes along an oblique line back and forth, the movieClip will go off the line 0.05 pixel for each back-and-forth. Below is the movie that demonstrates this. By repeatedly press up and down, the car at the left side will go off the line, while the car in the center remains good.

In what condtion will this "deviate to zero" phenomenon occurr ? It occurrs when the shift is not conform to twip unit. A shift of 1.00, 3,05 will be all right. Shift of 1.01, 3.02, 6.03, 12.4, 6.6, 8.7, 0.8, 3.9 do not conform to twip unit and will result in this "deviation to zero" side effect.

If your _x is not positive value, (for example  -20), then the increase is 6.7 and decrease is 6.65; Different from what I described above. It just deviates toward the zero. If your _x is 0, then increase value and decrease value will match.

It also occurrs to _y property.

What is the significance of the 1 twip deviation ?

Take a look at the movie below. Both of these balls contain the same script. The ball goes by _x+=v; If hitTest with the green wall, then bounce back by v*=-1; They have the same speed v value. Only the initial _x is slightly different.

You will see it works in one ball but stuck the other ball. Why ? 

Here is another demonstration. This happens even more common, because we usually modify speed by sin or cos function, and the resulting speed usually is not an integer of TWIP.

How do I do that ? The ball penetrates the green wall 6.7 and bounce back 6.65, that makes hitTest remain true, so v*=-1; It bounce again but to the interior of the green wall. 

If we make swf for web pages, this "deviation to zero" side effect may be not important. But if you are going to make a game, it is essential to understand this.

Isometric game is very popular. Every one wants to try it. Becareful for the shift. We are apt to use cos and sin function to create the y shift and x shift for our hero's move in isometric game. It would be ugly if after several moves, the hero stands out of the center of the tile.

But, we need sin and cos to create speed. It is impossible to make speed always in the poor precision of 0.05 only ! How to solve ?

In fact, _x is a function call that repaint the movieClip at the new position. It is a very big procedures. We should call it only for "repaint" the movie. Even " _x+=0; " is a CPU consumming process.

My habit is: setup an internal variable x for calculation and call _x for repaint.

onClipEvent (load) {
    x = _x;
    y = _y;
//setup x and y;
}
onClipEvent (enterFrame) {
    dx = 5*Math.cos(_rotation*Math.PI/180);
    dy = 5*Math.sin(_rotation*Math.PI/180);
    if (Key.isDown(Key.UP)) {
        x += dx;
        y += dy;
        //all manipulation is done by x,y not _x,_y;
    }
    if (Key.isDown(Key.DOWN)) {
        x -= dx;
        y -= dy;
    }
    _x = x;
    _y = y;
    //apply updated position to the movieClip 
}

download the zip file containing 3 source fla in this page

 


The underlying math:

Flash takes twip as the smallest unit. If we assign _x=1; it means we assign _x=20 twip. If we say x=1.6; _x=x twip, then what will happen ?

Surprisingly, it use int(x) rather than Math.round(x); So, x=1.6 but _x will be 1; Even in the case of "floating point bug", x=1.999999999, the result still _x=1; (Computer use 16 bit to represent interger part and 16 bit represent the decimal part).

Here we goes:

_x=1 twip, _x+0.6 twip==>should be 1.6 twip==> but it will be trim to integer, so the result is 1;

_x=1 twip, _x-0.6 twip==>should be 0.4 twip==> but it will be trim to integer, so the result is 0;

Now, if _x=1 twip; we add 0.6 it becomes 1, and then subtract 0.6 it turns to 0; Theoretically, adding and subtracting should be "counter-actioned" and cacel the effect of each other. But, in the condition of Flash, the answer is NO !

We add 0.6 and then subtract it by 0.6, the result is 1 twip less than the original one.

The reason is because flash calculate the twip by  int(x) not Math.round(x);