Views: 960,311,241Time: 2022-01-24 06:36:37 AM 7 users online: atm959, Darolac, Hayashi Neru, Infinity, Jacko, margot, SethOsDotEXE - Guests: 78 - Bots: 76 Users: 53,159 (2,259 active)Latest: jollyball77
 Tip: Unless you're making a Kaizo hack, don't make Mario die after cutting the goal tape. Not logged in.
Distance-based sprite speed issue (16 bit to 8 bit conversion problem?)
Forum Index - SMW Hacking - SMW Hacking Help - ASM & Related Topics - Distance-based sprite speed issue (16 bit to 8 bit conversion problem?)
Hello everyone,
today I tried to implement a sprite that follows Mario along the x axis, changing its horizontal speed based on the horizontal distance from him (i.e. a sprite that behaves similarly to Mario Maker's clouds).

Inside my asm file I created a simple subroutine called .move in which I calculate the horizontal distance between the sprite and the player, change sign to the number and call the \$018022 subroutine to update the sprite position. Here's the code that I came up with:

Code
```.move:
lda \$14E4,x      ;\
xba              ;| Load sprite x position in A
lda \$00E4,x      ;/
rep #\$20         ; Switch to 16 bit to calculate difference
sbc \$D1          ; A = x_sprite - x_mario

sep #\$20         ; Switch back to 8 bit mode
eor #\$FF         ; Change sign

sta \$B6,x        ; Set x speed
jsl \$018022      ; The subroutine that updates a sprite's X position without gravity
rts
```

Problem
The distance is calculated in 16 bit mode, and after the calculation the A high bits are never used, which means that this code breaks whenever the distance is greater than 0x007F or less than 0xFF80 (?).

To solve this problem I thought that clamping the distance value to that range could be the best strategy. Here's what I mean, in pseudocode:
Code
```distance = min(distance, 0x007F)
distance = max(distance, 0xFF80)
```

I tried to implement this in asm but the results I got are not working very well.
Code
```.move:
lda \$14E4,x      ;\
xba              ;| Load sprite x position in A
lda \$00E4,x      ;/
rep #\$20         ; Switch to 16 bit to calculate difference
sbc \$D1          ; A = x_sprite - x_mario

cmp #\$007F       ;\
bpl .clampLow    ;|
lda #\$007F       ;| clamp distance to (ff80, 007f)
.clampLow:           ;|
cmp #\$FF80       ;|
bmi .doneClamping;/
lda #\$FF80       ;
.doneClamping:       ;
sep #\$20         ; Switch back to 8 bit mode
eor #\$FF         ; Change sign

sta \$B6,x        ; Set x speed
jsl \$018022      ; The subroutine that updates a sprite's X position without gravity
rts
```

Now, of course there is a problem with my code or my assumptions. Here's the result:

I don't get why it's doing this, nor what is wrong with the code.

Thank you for reading this post to the end, I really appreciate it.
If you think you can give me a hand or even a suggestion I'd be glad.
Here's the full code of my sprite, in case you need it.
Welcome to the site! Your code looks really neat, and you've definitely got the right idea. There are only three issues I can spot, one of which might be the cause of your problem.

* To properly invert a value, increment it by one after doing EOR #\$FF. That shouldn't be making much of a difference in your case, though.
* The high byte of the sprite X position is \$14E0,x, not \$14E4,x. That's probably worth fixing.
* BPL and BMI aren't used for greater than/less than checks (as far as I know, they branch if a value is positive or negative respectively). Try BCS for "branch if greater than or equal", and BCC for "branch if less than".

The whole clamping thing may or may not be needed when you fix the X position address; not sure.

--------------------

WhiteYoshiEgg, thank you so much.

After fixing the first two problems you address, it still didn't work (without clamping).
The third one kind of did the trick. I was in fact incorrectly assuming the meaning of BPL and BMI, as you said.
However, simply changing the clamping part to
still doesn't work.

For some reason, the comparisons don't work when the values compared are different in sign (?).
However, as you may imagine, separating the two processes based on the sign of the number works perfectly.

Even though I don't completely understand why the first code is not working, I managed to solve my problem.
Thank you WhiteYoshiEgg, you really made my day.
That's because, from an unsigned perspective, "negative" numbers are bigger than "positive" numbers. In general, BCC and BCS are the general options for "branch if smaller" and "branch if equal or larger" but they involve the carry flag which makes these branch commands unsigned. Their signed equivalent are BMI and BPL and use the sign/negative flag instead. Replacing bcc in the above code with bmi makes the code work.