I tried to solve this problem when I first saw this thread but failed. However, in working on my game last night I just found a solution. It's not too elegant, but it works.
I'll explain why it works and how to do it and mention a somewhat related issue that becomes more of a problem if you change scrolling the way I explain here.
The reason scrolling makes the sprites jitter is because of the way and order the variable camX is set and used.
I'm going to go into some detail about what's going on, if you don't care about why this is happening or my explanation doesn't make any sense, feel free to skip ahead.
The order it works in each frame is.
0. In the NMI routine camX is used to set the scroll value of the background
1. controller input tells the input routines do_simpleScrollLeft or right to set the scroll flags if player1_object is hitting the scroll pad.
2. Physics routine moves player object to a new location based on speed, etc. and saves new location to xHold_hi
3. after checking xHold_hi against tile collisions and Object collisions, doHandleObjectUpdate set's xHold_hi to Object_x_hi,x
4. The Tile Drawing routine uses Object_x_hi,x and camX to figure out where to draw the sprites, then it draws them
5. Then the Object update loop cycles through and moves and draws every other object the way it did with player object
6. after all objects are updated and drawn, doCamera (in MainGameLoop) uses player1_object's speed which was set way back in Physics routine to update camX
(if the controller input is activating the scroll byte)
0. then it cycles back to the NMI routine, and the background scroll is set.
TLDR, Sprites are being drawn using the camX offset before camX is set for the next frames Background scrolling location. This results in the objects locations lagging behind the background scroll by one frame every frame.
We can't just go to MainGameLoop and move "JSR doCamera" before "JSR doHandleObjects", because you need player1_object's updated speed variable to move camX properly.
So, my solution was to
In MainGameLoop.asm, comment out "JSR doCamera"
In doHandleObjects_withinCamera.asm, immediately after ".include SCR_HANDLE_PHYSICS" insert some stuff so it looks like this.
SwitchBank #$1C
TXA
PHA
.include SCR_HANDLE_PHYSICS
cpx player1_object
bne +
jsr doCamera
+
PLA
TAX
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;DEMO PHYSICS
ReturnBank
That fixes Object Jittering for every object except the player object, which has already been moved and the new location is saved in xHold_hi, waiting to be checked for collisions.
This is the part that I don't feel is very elegant. I keep thinking there must be some sweet spot maybe inside the physics routine, where doCamera could be plugged in and it would work for the player and everything else, but I haven't found it and I'm tired of trying for now.
So for now, I added two little bits to doUpdateCamera.asm to fix player jitter.
Because we moved doCamera to the middle of player1_Object's updating routine, the final x location for the player has not been set by the time camX is updated, so within doCamera we will just force the player's tentative x location to the scroll Pad.
It's easy to find the two places to modify. Just search (ctrl+f) " getCamSeam ". There are two results. The top one is at the end of the Left Scroll Stuff.
Right after getCamSeam add a bit so it looks like this.
STA camX_hi
JSR getCamSeam
lda #LEFT_SCROLL_PAD;kn- if scrolling, force player sprite to stick to scroll Pad
clc
adc camX
sta xHold_hi
LDA camX_hi
adc #$00
STA xHold_screen
JMP noHorizontalCameraUpdate
The next getCamSeam is at the end of the Right Scroll Stuff.
Add to become
STA camX_hi
JSR getCamSeam
lda #RIGHT_SCROLL_PAD ;kn- if scrolling, force player sprite to stick to scroll Pad
clc
adc camX
sta xHold_hi
LDA camX_hi
adc #$00
STA xHold_screen
noHorizontalCameraUpdate:
And That stops player character jitter when scrolling, but we've introduced a new problem.
Because scroll is activated any time you press left or right on the d-pad when your character is at or across one of the scroll pads, if you for example are in a room with a right scroll edge and you cross the scroll pad then stop, then press right again, you activate scroll again and your character is tossed back over to the scroll pad. Joe actually already solved for that problem in your scrolling input scripts, he just commented those lines out. Well, we need them now, so
uncomment the lines at the top of do_simpleScrollLeft.asm and do_simpleScrollRight.asm.
These lines deactivate scrolling if camX is in a room with a scroll edge. Scrolling Right works perfectly after you uncomment the lines, but do_simpleScrollLeft needs a little more work. Since camX represents the left edge of the gamescreen, when you scroll even one pixel to the left into a room that has the left edge bit ticked it stops scrolling. So we have to add a little check to make sure camX is on the far left side of that room before it deactivates scrolling.
It should look something like this:
LDA ScreenFlags00
AND #%00100000
BEQ +doActivateScrollByte
lda camX ;;kn-Added this check to let player actually see the room that is a left scroll edge
cmp #$03 ;; this is #$03 just because it suited me, you'll want to pick a number that is larger than your max speed, but small enough that it's not too noticeable that
bcs +doActivateScrollByte ;; you aren't seeing quite the whole screen
LDA scrollByte
AND #%00111111
STA scrollByte
RTS
+doActivateScrollByte:
However, the way scrolling is triggered causes some problems for us. If you're character has a gradual acceleration you will notice, (and maybe already have) that after scrolling your character slides a little bit but the camera doesn't move with them. Before implementing this scroll pad lock that I just told you to do, you could work your way to the edge of the screen because of the deceleration slide and break the game if you tried hard enough. That's because scrolling is only activated when you are pressing left or right on the controller, not when the player is moving to the left or right. After changing the code as I've shown you here, your character will still slide as it decelerates, but then if you continue in that direction they will pop back to the scroll pad when scroll is activated again.
This is the part where I was going to explain how to solve that problem but I'm out of time for the day and realized that my simple solution didn't work immediately. I modified my physics routine long ago to include activating scrolling by player movement instead of by controller input. I basically copied the input scripts into the end of isMovingRight and isMovingLeft and only triggered scrolls if x=player1_object. My physics code is completely different from the stock NESMaker Platformer physics now so I guess copy pasting doesn't work anymore. I'll see if I can come back and share the solution for that new, more obvious problem soon, but I'm out of time this afternoon.
Also, after coming back to address some issues
@9Panzer brought to my attention, I realized that some similar problems will now affect Scroll locks that allow scrolling again after all the monsters on a screen are destroyed. I didn't take the time to make a screen that uses scroll lock in my demo project but I bet if you kill the last monster while the player character is to the active side of the scroll pad it will automatically stick your player to the scroll pad again. So that's another thing to deal with.
Like I said, I don't think this is an elegant solution. I don't like the solution to need a bunch of other solutions to solve new problems the first fix made.
Good Luck!
I hope I made enough sense to help someone! If anyone figures out a better way to implement this kind of fix I'd love to hear it.