Best method for circular motion?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Best method for circular motion?
by on (#147865)
Trying to do some orbital motion type stuff. Was wondering what you guys have used as a best method. I've tried a Horizontal + Vertical velocity type approach...it's kinda neat but definitely isn't consistent around a moving centerpoint (like an object moving around a player). Also, tried some look up tables, but wasn't really happy with the results there either it seemed to cause lag (though I'd have to comb though to be absolutely sure that's where the lag was coming from, as I get the impression that should've been quite fast).

Was wondering if any of you had some approaches you could suggest. Thanks!
Re: Best method for circular motion?
by on (#147870)
If the radius of the circle is fixed, a lookup sine table usually works pretty well for me.

If it doesn't have to be a perfect circle, but just curved motion, you can just use an object with acceleration that flips direction, i.e.
1. Accelerate left+up for 1 second.
2. Accelerate right+up for 1 second.
3. Accelerate right+down for 1 second.
4. Accelerate left+down for 1 second.
5. Repeat.

Basically, if you look at it in one axis, the acceleration function looks like a square wave, but as it integrates into velocity, the velocity looks like a triangle wave, and as that integrates into position, the position looks nice and curvy, almost like a sine wave. A circle is just a sine wave in both axes at once (with a 90 degree phase difference). The starting velocity is important to achieve this phase difference, to get a circle instead of just a diagonal wobble.

You see this all the time in games for enemies that just need to bob up and down (e.g. castlevania medusa heads) using flip-flop acceleration you get something that's probably as good as a sine wave for this purpose. This 2D variation makes a faux-circle instead.

The speed and radius is a little bit tricky to adjust, because it's dependent on both the acceleration constant, and the interval time. Acceleration and interval are both directly related to speed and radius, but in different ways. You can write yourself a calculator that simulates a full circle and gives you the right values, or you can just play with them until you like how they look.
Re: Best method for circular motion?
by on (#147881)
The homebrew NES game Thwaite determines the approximate unit vector by taking an arctangent (some reflections, a division, a table lookup, and compensating reflections), followed by a sine and cosine (table lookups). Then it determines the distance by taking the dot product of the displacement with the unit vector (two multiplications and one addition). This unit vector also gives the direction along which you must accelerate

Wrecking Ball Boy, an unfinished NES-style game written in Python with essentially 8-bit physics, uses the dot product technique to keep the character at the correct distance along the rope.
Re: Best method for circular motion?
by on (#147902)
Rainwarrior - essentially, I've tried both of those methods but didn't really get the results I wanted. I think I'll end up using the organic movement sort of nature of messing with accelerations around a moving point for other things, but yeah...this particular usage should be pretty evidently a circular path.

With the LUT - do you essentially have a top-left corner point defined, and then the lookup table is used to add values to that point in the x direction and then in the y direction, run a variable offset to cycle through the table values?
Re: Best method for circular motion?
by on (#147910)
There are a thousand ways to create and apply a lookup table for circular motion. A few things you might try:

  • It could be a table of signed or unsigned offsets.
  • You might scale a fetched value with bit shifts to get circles of different sizes.
  • The table could be a sine specifying a fixed offset from a locus point.
  • The table could be a table of deltas specifying the distance to move each frame.
  • You could look up two successive sine positions, and subtract to procedurally calculate a motion delta.
  • You could use your sine table for velocity, rather than position.

There are other possibilities, too, but what I would do depends on the situation.
Re: Best method for circular motion?
by on (#147936)
Please be more specific about what kind of "circular motion" you're looking for. Is it static motion along an arc of a circle, or dynamic (you talked about orbital motion?).
Re: Best method for circular motion?
by on (#147939)
Also, kind of a funky way to do the other method, have a target point, and just always accelerate toward that point, i.e. if X > target X, accelerate left. This basically makes a spring out of the target point.

From there, to make it circle you just have to give it an appropriate starting velocity and position (or you can add some rules that adjust acceleration in anti-orbit cases to automatically establish a clockwise orbit). You can move the target around, and it will continue to orbit dynamically. Clamping to a maximum velocity would also keep it from ever springing too far.

Hmm. I'm going to put a creature like this in my game, now that I'm thinking about it. Ha ha. Thanks for inspiring the idea. ;)
Re: Best method for circular motion?
by on (#148111)
Yeah, the target point method is essentially what I'm working with. I can get oscillation in either axis just fine, I just can't get a dependable circular motion that way...or even close, no matter how i populate the starting values or starting velocities (LOTS of trial and error, too). I mean, it's a cool organic sort of movement, but certainly not orbiting 'around' the orbit object.

TheFox - just simple orbiting around an object. I wanted something a little more organic than strict table read (so if center point was moving, it would drift to it and continue its orbit). But I can't even make a dependable initial circle using an acceleration/target method.

Rainwarrior - any tips on better control over this?
Re: Best method for circular motion?
by on (#148120)
I think the only real convincing way of doing this would be to somehow calculate the distance from the center for every angle measure, like directly above the canter could be (0,6) and directly to the side would be (6,0). I don't know how you'd do this though.
Re: Best method for circular motion?
by on (#148122)
That's called sin(x) and cos(x) ...
Re: Best method for circular motion?
by on (#148124)
lidnariq wrote:
That's called sin(x) and cos(x) ...

Sorry I'm not a genius like you are. :roll: (Kidding!) All I know is that sin and cos can help you find the side measures of right triangles. (Would you believe that I'm in the advanced math class?)

This idea could work though, right?
Re: Best method for circular motion?
by on (#148126)
Right, lidnariq - it seems the quickest method would be to just do the sin/cos math computation externally and populate a data table with the values...but that makes it complete static. That was one of my approaches. The other one is similar to what Rainwarrior is describing with accerleating around a centerpoint, but that one is a little too wild and not quite predictable enough for this purpose. So I was just seeing if there were methods I hadn't thought of. :-)

This is a minor thing in the idea for the game anyway...I just hate getting stumped. haha
Re: Best method for circular motion?
by on (#148127)
Espozo wrote:
lidnariq wrote:
That's called sin(x) and cos(x) ...

Sorry I'm not a genius like you are. :roll: (Kidding!) All I know is that sin and cos can help you find the side measures of right triangles. (Would you believe that I'm in the advanced math class?)

This idea could work though, right?


This is the idea: http://www.helixsoft.nl/articles/circle/sincos.htm (See the section "Drawing a circle".)
Re: Best method for circular motion?
by on (#148128)
Espozo, don't go just using the formulas teachers give you without understanding what they do. As a programmer, you have the obligation to understand how you reach the results you do.

By definition, sine and cosine are the vertical and horizontal distances from the center to the edge of a circle of radius 1, which is pretty much what you described. This means that by multiplying the sine and the cosine by other values you can increase and decrease the radius of the circle.
Re: Best method for circular motion?
by on (#148131)
tokumaru wrote:
By definition, sine and cosine are the vertical and horizontal distances from the center to the edge of a circle of radius 1, which is pretty much what you described. This means that by multiplying the sine and the cosine by other values you can increase and decrease the radius of the circle.

So you can only find the length radius and not the distance relative to the center of the circle? E.g. (5,3) (Wait a minute, you said you find the coordinates. You have to know what the radius is to do anything...) How are the positions of multijointed objects calculated? I thought it would have been nice if you had it to where you plugged in what you want the radius to be and the angle measure and it gives you the x and y coordinates, assuming the center is 0 I guess. (These new numbers would be added to the position of the center of the circle for the final value.)

Edit: Never mind this. In theory though, you could just convert a formula into code and it would work just fine?

Yeah, it's making sense to me now. The teacher said nothing about its relationship to a circle strangely.

Image
Re: Best method for circular motion?
by on (#148133)
Jesus, is there any place that says the mathematical equation for sine and cosine? We just used our calculators, along with what seems to be the rest of the world, to figure it out.

Edit: Well, I found something, but I'm not sure how well the NES will do... http://math.stackexchange.com/questions ... t-a-number
Re: Best method for circular motion?
by on (#148139)
Nobody calculates these at run time, everyone uses look-up tables.
Re: Best method for circular motion?
by on (#148142)
I can tell...
Re: Best method for circular motion?
by on (#148157)
On the NES, few people would calculate a sine at runtime. There are lots of ways to calculate them, though, and lots of reasons why you might do this rather than a lookup. The naive way of calculating one is probably the Taylor Series definition of the sine, i.e. you have an infinite series with increasingly smaller terms, and you just evaluate enough terms to reach the accuracy you want. CORDIC is the name of a commonly used set of trigonometry calculations for CPUs without a hardware multiply, like the 6502.


JoeGtake2 wrote:
Yeah, the target point method is essentially what I'm working with. I can get oscillation in either axis just fine, I just can't get a dependable circular motion that way...or even close, no matter how i populate the starting values or starting velocities (LOTS of trial and error, too). I mean, it's a cool organic sort of movement, but certainly not orbiting 'around' the orbit object ... any tips on better control over this?


To calculate the starting velocity, know that X velocity is 0 at the two horizontal extremes, and Y is 0 at the vertical. So, starting from zero, the velocity at frame T is A*T. The position accumulates each frame, though, so it's a series, (A*1)+(A*2)+(A*3)+...(A*T) = A*(1+2+3+...T) which reduces to: A*T*(T+1)/2

So, now that you can easily calculate position and velocity in terms of frame, pick a number of frames for your object to travel from the extreme to the centre. For instance, if it takes 5 frames, and acceleration is +3 per frame:

radius = 3 * 5 * (5+1) / 2 = 3 * 5 * 6 / 2 = 45
starting velocity = 3 * 5 = 15

So, in this case, you can place your object on the Y extreme, at (0,45) relative to the target, and give it a starting velocity of (15,0), and it will create a perfect orbit, at least until the target moves. Once the target moves, the circle gets stretched, probably irreversibly without extra corrections.

Here are some ways to do corrections to recover a circle:

1. Clamp your maximum velocity to that calculated starting velocity value, this creates a maximum radius.

2. Encourage motion in one direction only, like a Coriolis effect. Discourage anti-clockwise movement by preventing out-of-phase acceleration, by using 4 quadrant rules for acceleration instead of just 2 axis rules, e.g.:
  • top right - always accelerate down, only accelerate left if X velocity is positive
  • bottom right - always accelerate left, only accelerate up if Y velocity is positive
  • bottom left - always accelerate up, only accelerate right if X velocity is negative
  • top left - always accelerate right, only accelerate down if Y velocity is negative

With rules like this, starting velocity/position doesn't really matter, as it should eventually seek an orbital equilibrium. Play with the acceleration and clamping velocity parameters until you find the right balance. You probably want to test based on a velocity threshold (not simply negative/positive) to be able to accelerate up to a minimum velocity, but there's a tradeoff between accurate phase and narrow velocity range. There's many other tweaks that can be done, but this is a start.
Re: Best method for circular motion?
by on (#148246)
I've just been thinking about the whole sine and cosine thing: About the table, would you have it to where you have it to where there are 2 separate 90 entry tables that are indexed by whatever degree? On the SNES at least, you could have it to where the values in the table are for a radius of 1 (there will be sub pixel precision) and say if you wanted the radius to be 5, you would get the numbers from the sine and cosine table and use the multiplication units to multiply them by 5.
Re: Best method for circular motion?
by on (#148257)
A sine and cosine table are the same thing starting at different offsets. You only need one. If instead of degrees you divide the circle into 256, you can just use the implicit modulo 256.

cos[x] = sin[(x+64) & 255]

As for scaling, that's its own problem. You can have different tables at different scales, or you can attempt to scale them in some manner (shifting, multiply, etc.).
Re: Best method for circular motion?
by on (#148259)
How would you multiply on a system that doesn't have any multiplication hardware? The only way I could think of is if you had it like this:

(I think this would work on the 6502? It would be slow as all hell though.)
Code:
start_multiplier:
lda  #$00
ldx  Multiplier

multiplier_loop:
beq  multiplier_done
clc
adc  Multiplicand
dex
bra multiplier_loop

multiplier_done:
sta  Product
rts

Would there be some sort of way to improve this with bit shifts? I really don't get how you'd do division.
Re: Best method for circular motion?
by on (#148264)
Multiplication on 6502 uses the peasant algorithm, and division uses long division algorithm in base 2. The source code for Thwaite has examples of both.
Re: Best method for circular motion?
by on (#148269)
There are a hundred different ways to implement a multiply or divide.

There's a few here: http://6502.org/source/

The wiki has a few:
http://wiki.nesdev.com/w/index.php/8-bit_Multiply
http://wiki.nesdev.com/w/index.php/Multiplication_by_a_constant_integer
http://wiki.nesdev.com/w/index.php/Division_by_a_constant_integer

One requiring large lookup tables:
http://codebase64.org/doku.php?id=base:seriously_fast_multiplication

Omegamatrix wrote a series of routines for dividing by specific integers:
http://forums.nesdev.com/viewtopic.php?f=2&t=11336