nesdev.comhttp://forums.nesdev.com/ Learning Action Game Basicshttp://forums.nesdev.com/viewtopic.php?f=10&t=16343 Page 1 of 3

 Author: Pokun [ Fri Aug 11, 2017 8:44 am ] Post subject: Learning Action Game Basics Learning Action Game Basics, Acceleration-based Movement, Variable Height Jumping and CollisionEdit: The following code is apparently fine. I figured out the problem elsewhere and it fixed it. My other question is still relevant though.So I decided to learn how to make an action game.In order to make physics smooth and flexible like I want them, I understand that I need to make: A fixed-point subpixel system so I can move slower than 1 pixel/frame, acceleration-based movement for both running and jumping, and variable height jumping.I already made subpixel coordinates using one byte for the fractional part and one for the integer part of the coordinate and they work fine.Now I'm trying to make acceleration-based movement. I started making the controller handling for rightward movement. I learned to do comparisons with signed numbers from this article.So to move rightwards, I'm using two bytes for velocity that are added to by a two-byte acceleration value every frame that the RIGHT d-pad button is pressed. Before updating the velocity I first compare (using 16-bit signed comparison from above link) the new velocity value with the max speed value and if it's more than the max speed, I set the velocity to the max speed value, else I proceed to update velocity with the new value.Velocity is then added to the 16-bit X-coordinate which updates the sprite position.My code works fine as long as my max speed isn't set to \$00.7F or more. As soon as my sprite comes up to this speed he will start slowing down to zero again, then accelerate again and so on as long as I hold the button. I suspect something about the comparison routine makes it think that the lower velocity byte is signed. Shouldn't the sign only be in the most significant byte so that the range becomes \$80.00 to \$7F.FF?Code:;Constants:MOB_ACCEL_L = 4  ;walking/running acceleration value fractional partMOB_ACCEL_H = 0  ;walking/running acceleration value integer partMOB_MSPD_L = 128 ;maximum walking/running speed fractional partMOB_MSPD_H = 0   ;maximum walking/running speed integer part;Variables:temp+0temp+1      ;temporary storagep1_x+0      ;horizontal coordinate fractional partp1_x+1      ;horizontal coordinate integer partp1_vx+0     ;horizontal velocity fractional partp1_vx+1     ;horizontal velocity integer part;Code:@right1:                  ;controller I input handler for RIGHT button  lda con_state+0  and #CON_RIGHT  beq @not_right1  lda p1_vx+1  bmi @not_right1         ;if velocity negative, not right  lda p1_vx+0  clc  adc #MOB_ACCEL_L        ;add acceleration value to velocity, low byte  sta temp+0  lda p1_vx+1  adc #MOB_ACCEL_H        ;add acceleration value to velocity, high byte  sta temp+1              ;store new velocity temporary for comparison    lda temp+0  cmp #MOB_MSPD_L  lda temp+1  sbc #MOB_MSPD_H  bvc @n_xor_v_vr  eor #\$80@n_xor_v_vr:              ;16-bit signed comparison with max speed  bmi @not_terminal_vr    ;if velocity < max speed, allow acceleration  lda #MOB_MSPD_L  ldx #MOB_MSPD_H  jmp @terminal_vr        ;else, velocity = max speed@not_terminal_vr:  lda temp+0  ldx temp+1@terminal_vr:  sta p1_vx+0  stx p1_vx+1             ;set velocity    jmp @a1                 ;exit@not_right1:              ;if !RIGHT, decelerate;......p1_move_x:                ;horizontal movement based on velocity  lda p1_x+0  clc  adc p1_vx+0  sta p1_x+0              ;add velocity to position to move, low byte  lda p1_x+1  adc p1_vx+1  sta p1_x+1              ;add high byte plus carryQuestions:1) What's wrong with my code?Edit: Of course soon after posting this, I found out the problem. It appears the code is fine, the problem was very simple and unrelated to this code. I guess the code can be used by others trying to do the same thing. My other question is still relevant though.2) What is the Overflow Flag normally used for? From what I understand it indicates overflow/underflow between \$7F and \$80 to indicate that the value didn't fit in the signed number, much like Carry indicates that a number doesn't fit in a byte. But unlike Carry it isn't used in additions and subtractions. The only use I know of it is for signed comparisons, as a simulation of a branch always instruction and used in a special feature of the BIT instruction.Any help is greatly appreciated!

 Author: lidnariq [ Fri Aug 11, 2017 10:55 am ] Post subject: Re: Learning Action Game Basics Pokun wrote:Code:  lda p1_vx+1  bmi @not_right1         ;if velocity negative, not rightHow is the user supposed to brake if they can't add acceleration against the current velocity vector?Quote:Code:  lda temp+0  cmp #MOB_MSPD_L  lda temp+1  sbc #MOB_MSPD_H  bvc @n_xor_v_vr  eor #\$80@n_xor_v_vr:              ;16-bit signed comparison with max speed  bmi @not_terminal_vr    ;if velocity < max speed, allow accelerationBecause I'm terrible at math in asm, I tried checking against the output from cc65... I think that's supposed to be bpl.Quote:2) What is the Overflow Flag normally used for? [...] The only use I know of it is for signed comparisons, as a simulation of a branch always instruction and used in a special feature of the BIT instruction.It's for any manual fixup of signed math. And I just found this article.In practice, it's so rarely used that the bare 6502 has an external SET OVERFLOW pin, and I remember seeing a minimalist 6502 devkit that used it as one of the two dedicated inputs.

 Author: rainwarrior [ Fri Aug 11, 2017 10:59 am ] Post subject: Re: Learning Action Game Basics I thought the BMI was correct. (reference)As far as the code, it looks okay to me, but as always, it's very helpful to use a debugger and step through it to make sure it's going wrong where you think it is. Problems are often hard to read just on the page.The overflow flag question... well you listed all the common uses, I think.

 Author: gauauu [ Fri Aug 11, 2017 11:08 am ] Post subject: Re: Learning Action Game Basics Pokun wrote:Learning Action Game Basics, Acceleration-based Movement, Variable Height Jumping and CollisionSo this doesn't address your original question, but I find this article about side-scrollers to be incredibly useful when learning and planning how your game movement and collisions will work.

 Author: Pokun [ Fri Aug 11, 2017 11:22 am ] Post subject: Re: Learning Action Game Basics I edited the post a bit too late. I think maybe there is no problem with the code. It appears an old stray routine was meddling with it. I added a jump over the stray routine and it fixed it. Thanks a lot everyone anyway!lidnariq wrote:Pokun wrote:Code:  lda p1_vx+1  bmi @not_right1         ;if velocity negative, not rightHow is the user supposed to brake if they can't add acceleration against the current velocity vector?You are right. I think I added that line after looking at other people's code to see if it would solve any problem, but it didn't. I left it in anyway because I wasn't sure if it was needed or not. I guess I'll need to remove it so the user can break faster by pressing the opposite direction.Quote:Quote:2) What is the Overflow Flag normally used for? [...] The only use I know of it is for signed comparisons, as a simulation of a branch always instruction and used in a special feature of the BIT instruction.It's for any manual fixup of signed math. And I just found this article.In practice, it's so rarely used that the bare 6502 has an external SET OVERFLOW pin, and I remember seeing a minimalist 6502 devkit that used it as one of the two dedicated inputs.Ah I see, that clears things up. I read that article too, but I thought maybe I misunderstood something and that maybe it was related to my problem messing with signed numbers. This experience has cleared up many question marks about 6502.Quote:As far as the code, it looks okay to me, but as always, it's very helpful to use a debugger and step through it to make sure it's going wrong where you think it is. Problems are often hard to read just on the page.Yeah thanks. I tried to use the debugger but I don't really understand how to use it properly, adding breakpoints and whatnot, so it didn't help me much. I should probably research how to use debuggers more.Quote:So this doesn't address your original question, but I find this article about side-scrollers to be incredibly useful when learning and planning how your game movement and collisions will work.Thanks for the link. Looks like it may be able to answer lots of questions I will have from now on making an action game.Now I'm going to add in moving left, then we have jumping and collisions. I might post again if I run into any more problems.

 Author: dougeff [ Fri Aug 11, 2017 12:23 pm ] Post subject: Re: Learning Action Game Basics Quote:debugger but I don't really understand how to use it If you can get your assembler to output a labels file, with all the addresses of the labels, you can set a breakpoint for execution from that address.Or, you can insert a 'inc \$ff' (assuming address ff is unused) just before the code you are looking at. Set a breakpoint for writes to \$ff.For movement code, you need correct input. Either set (with FCEUX) an auto-hold on a button press (I can't remember the default keys to do this)... or open the hex editor, locate your ram address for controller reads (probably also found on that label file)...press the direction on the controller, pause emulation, click on the ram address, and 'freeze' its value. Now set a breakpoint, and step through the code.

 Author: Pokun [ Sat Aug 12, 2017 2:55 am ] Post subject: Re: Learning Action Game Basics Ah yeah Asm6 outputs a listing file with all addresses, I got a break point to work. I guess I could also use the BRK instruction and break on IRQ, I'm just not sure how to return to the game after a BRK though as the return address seems not to be preserved.Can't find anything about using inputs in the debugger. I know Mesen recently added that feature though.Yeah I've been using the hex editor in FCEUX a lot. It's very useful for RAM viewing and writing, I wish more emulators had such a thing. One thing FCEUX is missing though is an OAM viewer.I added left movement by copying the right movement and changing to subtracting acceleration value instead of adding, and limiting velocity to the negated max speed.The player sprite moves faster to the right than to the left however. It's strange because I can confirm that the velocity values in RAM goes up to the same max speed in both directions, just that the left max speed is negated.I also started implementing gravity and jumping (basically copied left and right movement with some modifications). I haven't limited jump height or jump button presses so jumping works more like a jet-pack at the moment. Googling for variable height jumping it appears that jump height is often limited by a jump time counter.

 Author: Sour [ Sat Aug 12, 2017 5:14 am ] Post subject: Re: Learning Action Game Basics Pokun wrote:I guess I could also use the BRK instruction and break on IRQ, I'm just not sure how to return to the game after a BRK though as the return address seems not to be preserved.Mesen has a "Break on BRK" option you can enable. Once the debugger breaks on a BRK instruction, you should be able to right-click and do "Set Next Statement" on the instruction below the BRK to skip executing the BRK instruction completely (so doing this means the BRK instruction will have no actual impact on the execution). "Set Next Statement" essentially changes the program counter and allows you to change the execution flow as you need (e.g force the code to skip a branch, etc.)dougeff's idea of using write-specific breakpoints & writing to a specific address that you don't normally is probably simpler to use, though. If you're not using save/work ram, you can just write to the \$6000-\$7FFF range with no side effects and break on those writes.I need to take a look at ASM6's listing output (couldn't find any example of them online) - might be something I can import into the debugger like I did for CC65's DBG files.Also, out of sheer curiosity, is there anything FCEUX's hex editor does that you need that Mesen's doesn't?

 Author: rainwarrior [ Sat Aug 12, 2017 9:31 am ] Post subject: Re: Learning Action Game Basics Pokun wrote:Ah yeah Asm6 outputs a listing file with all addresses, I got a break point to work. I guess I could also use the BRK instruction and break on IRQ, I'm just not sure how to return to the game after a BRK though as the return address seems not to be preserved.An RTI instruction in your IRQ handler would do the job. The BRK would take you to the IRQ handler, and one "step" should take you back to the instruction after the BRK (by executing the RTI).BRK does preserve a return value, there's just an extra byte on the stack compared to a JSR (P/flags).

 Author: tepples [ Sat Aug 12, 2017 9:46 am ] Post subject: Re: Learning Action Game Basics If you're using a breakpoint on an empty IRQ handler (that is, one that immediately executes RTI), make sure your assembler emits two bytes for BRK. Some emit one.

 Author: thefox [ Sat Aug 12, 2017 9:46 am ] Post subject: Re: Learning Action Game Basics rainwarrior wrote:Pokun wrote:Ah yeah Asm6 outputs a listing file with all addresses, I got a break point to work. I guess I could also use the BRK instruction and break on IRQ, I'm just not sure how to return to the game after a BRK though as the return address seems not to be preserved.An RTI instruction in your IRQ handler would do the job. The BRK would take you to the IRQ handler, and one "step" should take you back to the instruction after the BRK (by executing the RTI).BRK does preserve a return value, there's just an extra byte on the stack compared to a JSR (P/flags).Also note that the return address pushed by BRK takes you one byte past the byte following the BRK opcode, i.e.:Code:brk ; branches to irqnopnop ; rti returns hereirq:rti(In some assemblers BRK supports "immediate addressing", that is, you can write brk #\$69. In ca65 an operand is not supported.)

 Author: Pokun [ Sat Aug 12, 2017 4:12 pm ] Post subject: Re: Learning Action Game Basics Ah yes it seems ASM6 assembles "BRK" as \$00, and "BRK #\$DB" becomes \$00 \$DB ("BRK \$DB" also works). Passing a dummy argument like this works as the dummy byte, and now my IRQ handler returns properly on BRK. I could even detect the BRK IRQ by pulling P from the stack and checking the B flag.Sour wrote:Pokun wrote:I need to take a look at ASM6's listing output (couldn't find any example of them online) - might be something I can import into the debugger like I did for CC65's DBG files.Also, out of sheer curiosity, is there anything FCEUX's hex editor does that you need that Mesen's doesn't?That would be helpful, asm6 is one of the most popular assemblers after all.Not anything I can think about, Mesen's hex editor seems to have about everything that the FCEUX one have, plus more. Only thing might be that Mesen has a slow interface on my laptop I'm currently programming on, and things like hex editor and PPU viewers requires first opening the debugger (which also opens slowly). But maybe that can't be helped.FCEUX opens up lighting fast and has quick menus, which makes it ideal for quick testing.

Author:  Pokun [ Mon Aug 14, 2017 3:26 pm ]
Post subject:  Re: Learning Action Game Basics

OK next problem.

I have got both moving sideways and jumping to work pretty well if given the right parameters, but there are two bugs that I can't figure out why they happen, and I'm not sure how the debugger could help me here either.

The first is that going left is a lot slower than going right. When going right, I come up to the speed \$01.E0 pixel/frame according to the value in RAM, and when going left, I come up in \$FF.20 pixel/frame. That's the negative of \$01.E0 no? Yet I come up in this speed faster and the player character moves clearly much slower to the left than to the right.

Here is my leftward acceleration code (the rightward one is the same as the one in the first post). It is almost identical to the rightward code, except that acceleration is subtracted instead of added and the max speed is negated:
Code:
Constants:
MOB_ACCEL_L = 8
MOB_ACCEL_H = 0         ;running acceleration value added to velocity each frame
MOB_DECEL_L = 12
MOB_DECEL_H = 0         ;breaking acceleration value subtracted from velocity each frame not pressing RIGHT/LEFT
MOB_MSPD_L  = 224
MOB_MSPD_H  = 1         ;maximum allowed running speed

@left1:
lda con_state+0
and #CON_LEFT
beq @not_left1

;lda p1_ground           ;if in mid-air, skip acceleration (disallows
;beq @right1             ;horizontal acceleration control in mid-air)

lda p1_vx+0
sec
sbc #MOB_ACCEL_L
sta temp+0
lda p1_vx+1
sbc #MOB_ACCEL_H        ;subtract acceleration value from velocity
sta temp+1              ;store new velocity temporarily for comparison

lda temp+0
cmp #(256-MOB_MSPD_L)
lda temp+1
sbc #(256-MOB_MSPD_H)
bvc @n_xor_v_vl
eor #\$80
@n_xor_v_vl:              ;16-bit signed comparison with (-max speed)
bpl @not_terminal_vl    ;if velocity < (-max speed), allow acceleration
lda #(256-MOB_MSPD_L)
ldx #(256-MOB_MSPD_H)
jmp @terminal_vl        ;else, velocity = (-max speed)
@not_terminal_vl:
lda temp+0
ldx temp+1
@terminal_vl:
sta p1_vx+0
stx p1_vx+1             ;set velocity
jmp @right1             ;exit

@not_left1:
lda p1_vx+1
bpl @right1             ;if velocity positive, no need to decelerate

;lda p1_ground           ;if in mid-air, skip acceleration (disallows
;beq @right1             ;horizontal acceleration control in mid-air)

lda p1_vx+0
clc
sta temp+0
lda p1_vx+1
sta temp+1              ;store new velocity temporarily for comparison

lda temp+0
cmp #\$00
lda temp+1
sbc #\$00
bvc @n_xor_v_vls
eor #\$80
@n_xor_v_vls:             ;16-bit signed comparison with 0
bpl @positive_vls       ;if velocity >= 0, velocity = 0
lda temp+0
sta p1_vx+0
lda temp+1
sta p1_vx+1             ;else, allow deceleration
jmp @right1             ;exit
@positive_vls:
lda #\$00
sta p1_vx+0
sta p1_vx+1             ;stop

@right1:
;...

There are no meddling routines that run this time from what I can tell. Not anything that affects horizontal velocity or x-position anyway.
I attached the game to demonstrate the problem. That other problem is about jumping, but I'll get to that later.

 Attachments: File comment: Problems: 1) Leftward acceleration is slower than rightward. 2) When jumping, double jumping is possible if done really quickly on the way up. actiongame.zip [3.57 KiB] Downloaded 37 times

 Author: tepples [ Mon Aug 14, 2017 6:12 pm ] Post subject: Re: Learning Action Game Basics The two's complement of \$01E0 (+480) is \$FE20 (-480). \$FF20 is -224.

 Author: thefox [ Tue Aug 15, 2017 8:31 am ] Post subject: Re: Learning Action Game Basics It's best to replace MOB_MSPD_L and MOB_MSPD_H with MOB_MSPD = \$1E0, and use MOB_MSPD, <(-MOB_MSPD) and >(-MOB_MSPD) in the code.That kind of mistake is very common (at least I seemed to make them all the time when handling two's complement fixed point numbers, nowadays I try to be extra careful with them).

 Page 1 of 3 All times are UTC - 7 hours Powered by phpBB® Forum Software © phpBB Grouphttp://www.phpbb.com/