Author Topic: 8 Directional movement help  (Read 3899 times)

0 Members and 1 Guest are viewing this topic.

Offline LemonDrop

  • LV2 Member (Next: 40)
  • **
  • Posts: 26
  • Rating: +4/-0
    • View Profile
    • tin.gy
8 Directional movement help
« 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.

Offline Hayleia

  • Programming Absol
  • Coder Of Tomorrow
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 3367
  • Rating: +393/-7
    • View Profile
Re: 8 Directional movement help
« Reply #1 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.
« Last Edit: November 01, 2013, 04:17:00 am by Hayleia »
I own: 83+ ; 84+SE ; 76.fr ; CX CAS ; Prizm ; 84+CSE
Sorry if I answer with something that seems unrelated, English is not my primary language and I might not have understood well. Sorry if I make English mistakes too.

click here to know where you got your last +1s

Offline LemonDrop

  • LV2 Member (Next: 40)
  • **
  • Posts: 26
  • Rating: +4/-0
    • View Profile
    • tin.gy
Re: 8 Directional movement help
« Reply #2 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.
« Last Edit: November 01, 2013, 11:42:41 am by LemonDrop »

Offline ben_g

  • Hey cool I can set a custom title now :)
  • LV9 Veteran (Next: 1337)
  • *********
  • Posts: 1002
  • Rating: +125/-4
  • Asm noob
    • View Profile
    • Our programmer's team: GameCommandoSquad
Re: 8 Directional movement help
« Reply #3 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.
My projects
 - The Lost Survivors (Unreal Engine) ACTIVE [GameCommandoSquad main project]
 - Oxo, with single-calc multiplayer and AI (axe) RELEASED (screenshot) (topic)
 - An android version of oxo (java)  ACTIVE
 - A 3D collision detection library (axe) RELEASED! (topic)(screenshot)(more recent screenshot)(screenshot of it being used in a tilemapper)
Spoiler For inactive:
- A first person shooter with a polygon-based 3d engine. (z80, will probably be recoded in axe using GLib) ON HOLD (screenshot)
 - A java MORPG. (pc) DEEP COMA(read more)(screenshot)
 - a minecraft game in axe DEAD (source code available)
 - a 3D racing game (axe) ON HOLD (outdated screenshot of asm version)

This signature was last updated on 20/04/2015 and may be outdated

Offline Runer112

  • Project Author
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2289
  • Rating: +639/-31
    • View Profile
Re: 8 Directional movement help
« Reply #4 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:

  • -4: Left+Up
  • -3: Up / Left+Right+Up
  • -2: Right+Up
  • -1: Left / Left+Up+Down
  • 0: None / Left+Right / Up+Down / Left+Right+Up+Down
  • 1: Right / Right+Up+Down
  • 2: Left+Down
  • 3: Down / Left+Right+Down
  • 4: Right+Down

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
« Last Edit: November 01, 2013, 04:28:28 pm by Runer112 »

Offline Streetwalrus

  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 3821
  • Rating: +80/-8
    • View Profile
Re: 8 Directional movement help
« Reply #5 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.