I am currently attempting to implement movement on a 3D plane in assembly. What is the most accurate way to do this? I am trying to basically create movement vectors. For example, let's say the vector data is 1,3,1. That means that for every cycle, you are moving by +1 on the x, +3 on the y, and +1 on the z.

My question is, how to implement this using the arrow keys where pressing say the left arrow causes the ship to veer to the left a bit? Any suggestions, or perhaps is there a routine for this already made somewhere I can check out?
If you describe the motion with a 3d column vector [x, y, z], you can apply a rotation matrix to the vector to generate a version rotated around the origin. For constant-speed you can simply start with a unit vector (say [1, 0, 0]) and rotate as desired. For non-constant speed, you can adjust the magnitude of the velocity vector with scalar multiplies.

In pseudocode:
Code:
velocity = [1, 0, 0]
position = [0, 0, 0]

loop:
    # 3x3 rotation matrix
    rot = RotationMatrixFromInput(keystate)
    # Take care, matrix multiplication is not commutative
    velocity = rot * velocity
   
    # Scalar value in range [0, inf)
    acceleration = AccelerationFromInput(keystate)
    velocity = acceleration * velocity

    position += velocity
Tari.. my speed is variable... Here's how its set up. Every time I call the update_my_position loop, I have the following presets:

Speed, 1 byte of data.
Position X, Y, and Z, each 2 bytes of data
sector X, Y, and Z...mainly used to allow basically a 4 bytes worth of position data, instead of 2, per axis.
Vector X, Y, and Z. This controls how much to move on each axis per cycle.

To get a total movement per cycle, its Positions + Speed(Vectors) = New Positions

Also, how do I get the 3x3 rotation matrix? And, with speed, should speed be calculated into the initial matrix before or after rotation is applied?
Implicitly express the speed in the velocity vector. If you really don't want to do that for some reason, you can the velocity as a unit vector and multiply by speed to determine real change in position each frame, but that's wasteful (there's an unnecessary scalar multiply).
Ok, so. Can you give me an example to demonstrate. Let's say I am at an arbitrary position, X_start, y_start, and z_start, where speed is "speed" and movement is [x_mov, y_mov, z_mov] and you are initially moving at speed = 2, and only on the z axis, positive.

1. That makes your velocity vector [0,0,1], correct?
2. Does it then become [0,0,2], since we are moving at a speed of 2?
3. What happens if we then head to the left by 15 degrees? How do you calculate the new vectors? Would it need to become [-1, 0, 1] or something like that? I mean, assembly can only work with integers, so we can't move fractions of spaces.
There's still no point in maintaining a speed independent of the velocity vector unless there are range concerns. The speed is simply the magnitude of the velocity.

ACagliano wrote:
Let's say I am at an arbitrary position, X_start, y_start, and z_start, where speed is "speed" and movement is [x_mov, y_mov, z_mov] and you are initially moving at speed = 2, and only on the z axis, positive.

Code:
position = [x0, y0, z0]
velocity = [0, 0, 2]
(These are column vectors.)

ACagliano wrote:
3. What happens if we then head to the left by 15 degrees? How do you calculate the new vectors?
15 degrees left would be a rotation of 15 degrees CCW on the Y axis. Thus let a be the magnitude rotation on the y axis, and use the simplest form for a rotation matrix on the Y axis. (There's a general expression for computing these.)
Code:
rotator = [[ cos(a), 0, -sin(a) ],
           [ 0,      1, 0       ],
           [ sin(a), 0, cos(a)  ]]
velocity = rotator * velocity
The final velocity turns out to be approximately
Code:
velocity == [0.517638, 0., 1.93185]
(Note that the magnitude of the resultant velocity vector is the same as the original- the speed is unchanged.)

ACagliano wrote:
Would it need to become [-1, 0, 1] or something like that? I mean, assembly can only work with integers, so we can't move fractions of spaces.
Sure it can, it's just harder. 8.8 fixed-point should be enough precision for most applications, and isn't too bad. You either need to use very high integral values for velocity and scale back down later or use actual fractional values (though these approaches are basically the same thing in the end if your implementation of non-integral values is fixed-point).
Ok, my final two issues... how would I calculate the rotator matrix, in assembly? Are there routines for sin and cos I can use? Also, I checked out that link and it was complicated. I'm assuming 'theta' is the angle. Where is the axis?
bump.
There are sine and cosine system calls (here's the cosine one; WikiTI doesn't list the sine one, but it's there in TI's documentation). They're very slow, though-- as in hundreds of thousands of cycles to compute an answer.

If you can constrain the angles by which you rotate (not trying to rotate at arbitrary floating point intervals) or are willing to accept a little inaccuracy (interpolation), you'd probably be better off using a precomputed lookup table. Rotating in 5 degree increments would only require 18 entries in your table, or 36 bytes if you're doing 16-bit fixed point math. One degree increments probably wouldn't even be that bad (90 entries/180 bytes), assuming you're not already too memory constrained.

(Sorry, I don't have any code examples for you here; I haven't done much Z80 assembly.)
Ok, assuming I want to do a lookup table. Are there examples of that anywhere? Also, what do I do if my position data is integer only? Should I make position data 16.8? Because the 16 is essential.
bump on the above, and also this question is for Tari:

Where you say a velocity should not be maintained separately, and instead be in the velocity vector... I'm assuming if the initial velocity is applied, and then the rotation matrix applied, the new values would preserve that velocity, you'd just be moving at an angle. But, now...how would I apply a change in velocity? Could I multiply all values by the new value, or will I have to zero out the axes, apply the change, and then reapply the rotation?
bump
ACagliano wrote:
Could I multiply all values by the new value
Yes. That's the "scalar multiply" I referred to earlier. Degenerate example:
Code:
velocity = [1, 0, 0]
magnitude(velocity) == 1

##

velocity *= 0.9
velocity == [0.9, 0, 0]
magnitude(velocity) == 0.9
Where magnitude(v) is trivial. The math all holds up when the y and z components are nonzero, but it's more computation to deal with, which I can't be bothered to do right now.
Ok, so I guess what I need then is how to do a sin/cos lookup table, and then I'm all set. Any references on that?

And lastly, (I hope), what if my coordinates system is integers only. So a vector with a fractional part wouldn't work... unless I do 16.8.
bump @Tari. Last question, I hope.
If you're okay with speed resolution on the order of only sqrt(2) and can deal with outright skipping of spatial coordinates at high speeds, a pure-integral vector system could work. It's a mess though, and I wouldn't recommend trying to do so, particularly since you're basically already doing fixed-point if the world is contrived such that you can deal with the error inherent in such an approach.
You may need to explain what you mean by that last sentence, but what I'm gathering is... for the first part, you advise using some decimal part or ill end up skipping coords, unless the world is designed in a way that would be able to correct that (I'm assuming you mean the next time the calculation is done). Am I paraphrasing right?

How trivial would it be to implement a 16.8 fixed point coord system? Are there arithmetic routines for that?
ACagliano wrote:
You may need to explain what you mean by that last sentence, but what I'm gathering is... for the first part, you advise using some decimal part or ill end up skipping coords, unless the world is designed in a way that would be able to correct that (I'm assuming you mean the next time the calculation is done). Am I paraphrasing right?
More that the world needs to be designed that the error can be ignored (you can't generate correct data once you've thrown out the fractional parts), but generally speaking, yes.

Quote:
How trivial would it be to implement a 16.8 fixed point coord system? Are there arithmetic routines for that?
You obviously need 24-bit representations. Basic operations can probably all be done in registers (AHL + BDE or so), but it may be harder to do multiplies/divides with that resolution.
I don't know of any specific implementations, but there are probably at least a few assumptions you can make about values (and then enforce those invariants in your engine) to speed things up.
Ok. Thanks, and my last question to you. Going through a list of map objects, and figuring out what is in front of you is basically the same process as moving, correct?
bump: will this work for sin, cos?

http://www.andreadrian.de/oldcpu/sincos.z80
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 3
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement