Omnimaga

Calculator Community => TI Calculators => Axe => Topic started by: LemonDrop on November 01, 2013, 03:00:53 am

Title: 8 Directional movement help
Post by: LemonDrop on November 01, 2013, 03:00:53 am
So I got some code that allows the user to move around on the screen with 8 directions (holding down multiple buttons), but mapping sprites to that is something I am challenged with. For 4 directional movement, you can just have some sort of directional value and store the key pressed (or some sort of state value) to there, and multiply it by 8 to get an offset in a spritesheet. Problem with 8 directional is you can have a lot of key combos (even weird ones like all 4 at once). I thought of doing the same thing and just adding the directional values together to get the offsets but its kind of silly and it skips a whole sprite at the end (number 10):

1-d
2-l
3-d+l
4-r
5-d+r
6-l+r
7-u
8-u+d
9-u+l
11-u+r

I was wondering if anyone had a better system than this because its been annoying me for a bit. Thanks.
Title: Re: 8 Directional movement help
Post by: Hayleia on November 01, 2013, 03:29:19 am
Maybe try to assimilate a key to a power of two (since one key has two states (pressed or not), binary seems the way to go). The problem I see with that is that the player will never press up and down at the same time, so there is a bit of waste.

Anyway, I give you an example with orders I chose, but you are free to choose your orders after all.
1-down
2-left
4-right
8-up
So if you press down and left, you have 1+2=3.

Now draw your eight sprites and put them in a specific order (that you can choose too), for example this (random) one :
    []->°Sprites
    [ no key pressed ]
    [ up ]
    [ up-left ]
    [ up-right ]
    [ left ]
    [ right ]
    [ down ]
    [ down-left ]
    [ down-right ]


Now we need to bind the keypresses to the sprites. Remember that there are keypresses that "never" happen, like up+down, so you might want to choose a specific sprite for them or say that up+down gives down for example.
So you need to make this kind of data : You get 0 when presseing nothing, so the first sprite is the sprite "no key pressed", which is the 0th (I started counting at zero of course). You get one when you only press down (according to what I said). So the second sprite is the sprite facing down, which is the 6th one in my list. You get two when pressing left, so the next sprite is the sprite facing left, which is the 4th one. You get three with down+left, so the next sprite is 7th one. Etc. So your data will look like this :
     Data(0,6,4,7,...)->°Corr
Remember that you get nine when pressing up+down for example, so you don't necessarily have a sprite for that case but you still need to assign one. And I was too lazy to do the 16 cases here, but you actually have 16 bytes to put in this data.

Now, how do we actually get one when pressing down, two when pressing left, etc ? with that calculation :
     getKey(4)*2+getKey(3)*2+getKey(2)*2+getKey(1)->D

Now you guess what you just have to do to get the right pointer :
     {D+°Corr}*8+°Sprites

Note, all of that is untested, I am under Linux right now and don't have Wabbitemu on it.

edit messed up with the counting, please read again if you felt like it meant nothing.

edit 2 I made a complete program. Here is the source, in attachement and in spoiler.

Spoiler For Spoiler:
.AA

[]->°Sprites
[FFC3A59999A5C3FF].none 0
[FF00000000000000].up 1
[FF80808080808080].upleft 2
[FF01010101010101].upright 3
[8080808080808080].left 4
[0101010101010101].right 5
[00000000000000FF].down 6
[80808080808080FF].downleft 7
[01010101010101FF].downright 8

Data(0,6,4,7,5,8,0,6,1,0,2,4,3,5,1,0)->°Corr

ClrDraw
While 1
 getKey(4)*2+getKey(3)*2+getKey(2)*2+getKey(1)->D
 Pt-Off(0,,{D+°Corr}*8+°Sprites)
 DispGraph
EndIf getKey(15)
Optimizers would tell me that D is useless. Yes it is, but it improves readability, thing that I don't care about in my progs but that I care about when explaining.
Title: Re: 8 Directional movement help
Post by: LemonDrop on November 01, 2013, 11:40:22 am
Thats a pretty good idea of refrencing them with another set of data, I'll have to try that later.
I was wondering also why you use ° when you store the data, because ° returns the memory location of the variable apparently but I don't see why you would want to store it to that or something. Also Is a while loop with a conditional end more efficient than a repeat or are you just doing that so the code is executed before it checks if it exited.
Title: Re: 8 Directional movement help
Post by: ben_g on November 01, 2013, 11:45:13 am
I'd suggest to just go with 4 sprites, and make the sprite point in the direction of the key you held down last, or just make it default to values (for example point left when left is pressed, even when the up or down key is held at the same time). It might not look as good than with full 8-directional sprites, but for a calc game, it is fine. Many gbc and gba games even did it like this.
Title: Re: 8 Directional movement help
Post by: Runer112 on November 01, 2013, 01:47:23 pm
Hayleia's idea of combining all four arrow key states into one number is definitely the way to go. However, may I propose a combination function that returns values without the need of a lookup table?

getKey(1)-getKey(4)*3+getKey(3)-getKey(2)

If my logic is correct, this should return the following values:


You could then store and access your sprite data like this:

Code: [Select]
.Sprite data
[FF80808080808080] .Left+Up
[FF00000000000000] .Up
[FF01010101010101] .Right+Up
[8080808080808080] .Left
[0000001818000000]→°DirNone
[0101010101010101] .Right
[80808080808080FF] .Left+Down
[00000000000000FF] .Down
[01010101010101FF] .Right+Down


.Later in the program...

.To get a pointer to a directional sprite
getKey(1)-getKey(4)*3+getKey(3)-getKey(2)*8+°DirNone



If you didn't actually want there to be a "no direction" sprite and have the sprite remain facing the way it was from the last keys pressed, I'd try coding in some logic like this:

Code: [Select]
.Initialize some direction
3→D .Down


.Later in the program...

.If the current arrow key state is an actual direction (≠0)
If getKey(1)-getKey(4)*3+getKey(3)-getKey(2)
.Store the new direction
→D
End

.Somewhere later, the sprite is displayed
Pt-Something(some_x,some_y,D*8+°DirNone)

In this case, the no direction sprite (0) should never be displayed, so the °DirNone sprite is a bit of a waste of space. However, if you want to be a crazy optimizer (I do), you can put some other sprite you need in your program in that spot. :P
Title: Re: 8 Directional movement help
Post by: Streetwalrus on November 01, 2013, 02:37:05 pm
Thats a pretty good idea of refrencing them with another set of data, I'll have to try that later.
I was wondering also why you use ° when you store the data, because ° returns the memory location of the variable apparently but I don't see why you would want to store it to that or something. Also Is a while loop with a conditional end more efficient than a repeat or are you just doing that so the code is executed before it checks if it exited.
- ° returns the pointer to data but you can also use it for custom pointers and even constants, which is pretty awesome.
- While and Repeat in Axe both check the condition first. The difference is essentially the same as If vs !If. While continues if the condition is non-zero whereas Repeat continues if it's zero. Now While 1/Repeat 0 are automatically optimized to a mere jump in the output ASM code. Checking the condition first requires to go back to the beginning of the loop and then appropriately skipping it. Using While 1/Repeat 0 and a conditional End is both faster and smaller. See it as a Do ... While in C.