Jump to content



0

Quick animation question


12 replies to this topic

#1 cvga OFFLINE  

cvga

    River Patroller

  • 2,596 posts
  • Location:Sector 36

Posted Thu Jan 24, 2008 11:44 PM

I've been through the batari Basic tutorial and I know how to position my player and move them. However, all of the examples I've seen move a player by incrementing the player0x and/or player0y by integer amounts. I want to calculate the slope of the line between two players and move one of the players (say player0) toward the other. Here's what I'm thinking.

Suppose player0 is located at 40,20 and player1 is located at 50,45
dim slope = a

The slope of the line between these players would be (45-20)/(50-40) = 25/10 = 2.5

If I wanted to move player0 to player1's position, why can't I do the following?

for player0x = 40 to 50
player0y = player0y + slope
drawscreen
next

My slope seems to be ignored.

Thanks!

#2 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Fri Jan 25, 2008 1:17 AM

View Postcvga, on Fri Jan 25, 2008 12:44 AM, said:

I want to calculate the slope of the line between two players and move one of the players (say player0) toward the other.
To move a sprite by a fractional amount, you need to use fixed-point variables.

There are at least two useful applications-- to move a sprite along a path that has a particular slope, as you're trying to do; or to move a sprite by a number of pixels that can change due to the sprite accelerating or decelerating (i.e., variations in its velocity).

batari Basic supports two types of fixed-point variables-- 4.4, and 8.8. "4.4" means 4 bits in front of the decimal, and 4 bits after the decimal, so it takes a total of 8 bits or 1 byte. Likewise, "8.8" means 8 bits in front of the decimal, and 8 bits after the decimal, so it takes a total of 16 bits or 2 bytes.

To declare a fixed-point variable, you can do something like "dim my_var_1 = a.a" for a 4.4 variable (where "my_var_1" is whatever name you want to use), or "dim my_var_2 = b.c" for an 8.8 variable. Note that in the 4.4 variable, the same user variable is given on both sides of the decimal, like "a.a," or "f.f," or "z.z." In the 8.8 variable, two different user variables are given on the two sides of the decimal, like "a.b," or "g.s," or "x.y."

A 4.4 variable is always considered to be signed-- i.e., it can have a negative value. The leftmost or highest bit (bit 7) is used as the sign, so the integer portion (or high nybble) can go up to only +7. The low nybble represents a fraction with a divisor of 16, such as 0/16, 1/16, 2/16, 3/16, etc., up to 15/16. For example, %0111.1111 would be the largest positive value, and would be +7.9375 (positive 7 plus 15/16). The lowest negative value would be %1000.0000 or -8.0 (negative 8 plus 0/16). Decoding the negative numbers can be a little bit tricky, so I might be mistaken, but I believe that %1111.1111 would be -0.0625 (negative 1 plus 15/16, or -1.0000 + 0.9375 = -0.0625). Thus, %1000.0001 might look like -8.0625 at first glance, but it's really "minus 8 *AND* 1/16," or -8.0000 + 0.0625 = -7.9375.

An 8.8 variable works much the same way, except (I think) it can be either signed or unsigned. If it's unsigned, then the integer portion (or high byte) can range from 0 to 255, and the fractional portion (or low byte) can range from 0/256 to 255/256-- i.e., from 0.00000000 to 255.99609375. If it's signed, then it works similar to a 4.4 variable, except the integer portion ranges from -128 to +127, and the fractional portion ranges from 0/256 to 255/256. So %11111111.11111111 as a signed value would be -1 + 255/256 = -0.00390625.

Since an 8.8 variable can go up to 255.99609375, and the integer portion is the entire first byte, you can use 8.8 variables for calculating screen coordinates when doing fractional movements along a sloped line. That is, you can calculate the value of the slope with an 8.8 variable, and then set the sprite's y position or x position equal to the first byte of the 8.8 variable.

On the other hand, 4.4 variables aren't suitable for calculating screen coordinates, but they *are* useful for velocities.

Refer to the section on "Fixed Point Variables" in the batari Basic Command Reference for more information.

Michael

#3 cvga OFFLINE  

cvga

    River Patroller

  • 2,596 posts
  • Location:Sector 36

Posted Fri Jan 25, 2008 9:14 PM

Thanks (again). I think I see what is happening in my code. I've read through the batari Basic information a couple of times (I'm trying to ask good questions) and changed my slope variable to a two-byte variable. When the ball is travelling in a downward slope, it appears correct. However, when the ball should travel upwards, it just jumps all around the screen. I think it's because an upward slope would should show up as a negative number but instead it getting used as a large (probably near 256) positive number. I can't find where/how I can declare my two-byte variable as a negative number.

#4 Fort Apocalypse OFFLINE  

Fort Apocalypse

    Stargunner

  • 1,593 posts

Posted Fri Jan 25, 2008 11:16 PM

View Postcvga, on Fri Jan 25, 2008 10:14 PM, said:

Thanks (again). I think I see what is happening in my code. I've read through the batari Basic information a couple of times (I'm trying to ask good questions) and changed my slope variable to a two-byte variable. When the ball is travelling in a downward slope, it appears correct. However, when the ball should travel upwards, it just jumps all around the screen. I think it's because an upward slope would should show up as a negative number but instead it getting used as a large (probably near 256) positive number. I can't find where/how I can declare my two-byte variable as a negative number.

How the math works is that when a number goes below zero it is 256- the remainder, so 2 - 6 = (256 - 4 =) 252. By the same token, 252 + 6 = 2. The other tricks with floating points in bB are that you compare to integers, not decimals in if statements, but you must add/subtract floating point/decimal numbers. So:
(for example)
if myfloat = 3 then myfloat = myfloat + 2.0

This can be tricky because it means if you are adding variables together or subtracting one from another, they must both be floating points. You can't really multiply/divide them I think.

In addition to using floating point (dim something = a.b) you could use a timer variable (a counter like a=a+1 on each loop) and then check a bit on the variable to see if is set or not to do something. (That effectively slows down things.)

#5 cvga OFFLINE  

cvga

    River Patroller

  • 2,596 posts
  • Location:Sector 36

Posted Sat Jan 26, 2008 4:41 PM

Thanks for the replies. I'm not quite all the way where I want to be with this yet so I've modified my example as follows.

rem move sprite on a slope

include div_mul16.asm

rem Light blue player
COLUP0 = 142
COLUP1 = 200
scorecolor = 142

player0:
%11111111
%10000001
%10000001
%10000001
%10000001
%10000001
%11111111
%00000000
end


player1:
%10000001
%01000010
%00100100
%00011000
%00100100
%01000010
%10000001
%00000000
end

dim slope = a.b
dim p0y = player0y.c
player0x = 40
player0y = 20

player1x = 104
player1y = 45

slope = (player1y - player0y)/(player1x - player0x)
rem the slope of this line should be (45-20)/(104-40) = 25/64 = 0.391

for player0x = 40 to 100
drawscreen
p0y = p0y + slope
next


Unfortunately this won't even compile for me. I get a div8 error. Any ideas as to what I'm doing wrong?

#6 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Sat Jan 26, 2008 10:24 PM

View Postcvga, on Sat Jan 26, 2008 5:41 PM, said:

include div_mul16.asm

View Postcvga, on Sat Jan 26, 2008 5:41 PM, said:

Unfortunately this won't even compile for me. I get a div8 error. Any ideas as to what I'm doing wrong?
The "div8" routine isn't part of the "div_mul16.asm" file; it's part of the "div_mul.asm" file. Take the "16" out of the include file name, and it will compile.

Michael

#7 cvga OFFLINE  

cvga

    River Patroller

  • 2,596 posts
  • Location:Sector 36

Posted Sat Jan 26, 2008 10:37 PM

View PostSeaGtGruff, on Sun Jan 27, 2008 4:24 AM, said:

View Postcvga, on Sat Jan 26, 2008 5:41 PM, said:

include div_mul16.asm

View Postcvga, on Sat Jan 26, 2008 5:41 PM, said:

Unfortunately this won't even compile for me. I get a div8 error. Any ideas as to what I'm doing wrong?
The "div8" routine isn't part of the "div_mul16.asm" file; it's part of the "div_mul.asm" file. Take the "16" out of the include file name, and it will compile.

Michael

Thanks! It compiles now but the square moves in a straight horizontal line instead of moving toward the "X". What do I need to do to have the y-coordinate recognize my 0.391 slope?

#8 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Sun Jan 27, 2008 2:41 AM

View Postcvga, on Sat Jan 26, 2008 11:37 PM, said:

Thanks! It compiles now but the square moves in a straight horizontal line instead of moving toward the "X". What do I need to do to have the y-coordinate recognize my 0.391 slope?
The bB compiler can't handle using complex math to assign a value to a fixed-point variable. But if you use "slope = 0.391" it will work.

Michael

#9 cvga OFFLINE  

cvga

    River Patroller

  • 2,596 posts
  • Location:Sector 36

Posted Sun Jan 27, 2008 9:15 AM

View PostSeaGtGruff, on Sun Jan 27, 2008 8:41 AM, said:

View Postcvga, on Sat Jan 26, 2008 11:37 PM, said:

Thanks! It compiles now but the square moves in a straight horizontal line instead of moving toward the "X". What do I need to do to have the y-coordinate recognize my 0.391 slope?
The bB compiler can't handle using complex math to assign a value to a fixed-point variable. But if you use "slope = 0.391" it will work.

Michael

I thought the problem was with the formula. I plugged in various constants for the slope and got the results I wanted. However, in reality I want player0 and player1 to able to move around while I calculate the slope on the fly. I'll quit banging my head against the wall trying to get the slope formula to work and instead concentrate on another way to accomplish what I want to do.

As always, thanks for your reply!

#10 cvga OFFLINE  

cvga

    River Patroller

  • 2,596 posts
  • Location:Sector 36

Posted Sun Jan 27, 2008 9:54 AM

I don't suppose there's a way to store fractional numbers in a data table is there?

#11 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Sun Jan 27, 2008 2:29 PM

View Postcvga, on Sun Jan 27, 2008 10:54 AM, said:

I don't suppose there's a way to store fractional numbers in a data table is there?
Yes, but you'll need to store each part as a separate byte-- either in one data table or two-- then you can set each part of the slope variable separately (i.e., whole part and fractional part), such as follows:

   dim slope = a.b

   data whole_part
   etc.
end

   data fractional_part
   etc.
end

   rem * c = index into data tables

   a = whole_part[c]
   b = fractional_part[c]
   rem * now slope is set
Michael

#12 cvga OFFLINE  

cvga

    River Patroller

  • 2,596 posts
  • Location:Sector 36

Posted Sun Jan 27, 2008 5:19 PM

Thanks! That worked for what I was trying to do! I appreciate the help!

#13 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Mon Jan 28, 2008 1:27 AM

I found a "divide 16 bits by 8 bits" routine that can be used to calculate the slope:

http://6502org.wikid...are-math-intdiv

Please note that the comments for the output are *backwards*-- the 8-bit quotient will be in the *accumulator*, and the remainder will be in TLQ, rather than vice versa as stated!

Anyway, I've created a user-defined batari Basic function using that code, as follows:

   function div16by8
   asm
   LDX #8
   ASL temp2
div16by8_1
   ROL
   BCS div16by8_2
   CMP temp3
   BCC div16by8_3
div16by8_2
   SBC temp3
   SEC
div16by8_3
   ROL temp2
   DEX
   BNE div16by8_1
   RTS
end
Just add the code for this function somewhere in your bB program, where your other subroutines are (i.e., somewhere that your program won't fall into by mistake).

To call the function, pass it three parameters, as in the following pseudocode:

   quotient = div16by8 (numerator_hi, numerator_lo, divisor)
   remainder = temp2
For calculating an 8.8 fixed-point slope, you want the remainder to be a fraction of 256, which is why bB's "//" operation won't work (since it returns a remainder that's a fraction of the *divisor*). So I used the following formula:

y / x = n / 256
256 * y = n * x
n = 256 * y / x

So let's say you have the following:

   dim slope = a.b
   dim p0y = player0y.c

   player0x = 40
   player0y = 20

   player1x = 104
   player1y = 45
You can pass a variable, constant, or numeric literal to a user-defined function, but not an arithmetic expression, so you need to calculate the x and y differences, store them in variables, and then pass the variables. Since this user-defined function is going to use temp1, temp2, and temp3 anyway, you can use them for the differences:

   temp1 = player1y - player0y
   temp2 = player1x - player0x
   slope = div16by8 (temp1, 0, temp2)
   b = temp2
Note that upon exiting the function, the accumulator will hold an 8-bit quotient, and the remainder will be in temp2, so you need to be sure to store temp2 in the fractional part of the 8.8 slope variable.

Here's the full code; I modified it slightly from your original program, and note that the div_mul.asm (or div_mul16.asm) include file is no longer needed:

   rem move sprite on a slope

   dim slope = a.b
   dim p0y = player0y.c

   scorecolor = 142

   player0:
   %11111111
   %10000001
   %10000001
   %10000001
   %10000001
   %10000001
   %11111111
   %00000000
end

   player1:
   %10000001
   %01000010
   %00100100
   %00011000
   %00100100
   %01000010
   %10000001
   %00000000
end

   player0x = 40
   player0y = 20

   player1x = 104
   player1y = 45

   temp1 = player1y - player0y
   temp2 = player1x - player0x
   slope = div16by8 (temp1, 0, temp2)
   b = temp2

loop

   p0y = 20.0
   for player0x = 40 to 104
	  drawscreen
	  p0y = p0y + slope
   next 
   goto loop

   function div16by8
   asm
   LDX #8
   ASL temp2
div16by8_1
   ROL
   BCS div16by8_2
   CMP temp3
   BCC div16by8_3
div16by8_2
   SBC temp3
   SEC
div16by8_3
   ROL temp2
   DEX
   BNE div16by8_1
   RTS
end
Also, note that if you're going to calculate a slope for moving a player like this, you'll probably want to check which is larger, the x difference or the y difference. Then you would divide the smaller by the larger, so the "slope" is always 1 or less than 1, and vary the appropriate coordinate (x or y) by 1, so the sprite doesn't jump too far each time. That is, let's say that xdiff is 5 and ydiff is 20, then if you divide ydiff by xdiff, the slope is 4, which would mean that for each time you add 1 to x, you'd be adding 4 to y, which would make the sprite seem to jump too quickly. On the other hand, if you divide xdiff by ydiff (smaller by larger), the "slope" (or inverse slope) is 0.25, so if you add 1 to *y* each time, and calculate x by adding the "slope" to it, the sprite would seem to move more smoothly.

Disclaimer: I haven't tried this with negative numbers yet, but I assume that you'd also want to be sure that xdiff and ydiff are always positive, which means you'd want to compare player0x with player1x, and player0y with player1y, so you can subtract in the appropriate order (e.g., player0x - player1x, or player1x - player0x), and then either add or *subtract* the slope depending on whether you need the player to move up, down, left, or right.

Michael

Edited by SeaGtGruff, Mon Jan 28, 2008 1:31 AM.





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users