Best method for circular motion?

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: Best method for circular motion?

Post by Drew Sebastino »

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
User avatar
tokumaru
Posts: 12254
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Best method for circular motion?

Post by tokumaru »

Nobody calculates these at run time, everyone uses look-up tables.
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: Best method for circular motion?

Post by Drew Sebastino »

I can tell...
User avatar
rainwarrior
Posts: 8475
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Best method for circular motion?

Post by rainwarrior »

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.
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: Best method for circular motion?

Post by Drew Sebastino »

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.
User avatar
rainwarrior
Posts: 8475
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Best method for circular motion?

Post by rainwarrior »

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.).
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: Best method for circular motion?

Post by Drew Sebastino »

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: Select all

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.
tepples
Posts: 22414
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Best method for circular motion?

Post by tepples »

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.
User avatar
rainwarrior
Posts: 8475
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Best method for circular motion?

Post by rainwarrior »

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/Mult ... nt_integer
http://wiki.nesdev.com/w/index.php/Divi ... nt_integer

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

Omegamatrix wrote a series of routines for dividing by specific integers:
viewtopic.php?f=2&t=11336
Post Reply