[4.5.9] Attaching DrawSprite to Player

pierski

New member
I am attempting to attach additional sprites to the player. I have it attaching correctly on load, but as the player moves there is some lag.

Here is a video example of what is happening. I recorded the video at 25% speed to make it easier to see. You might want to watch the video on YouTube to see it at a larger resolution.


Here is the code. I am including it right after the sprite pre draw (I apologize for my novice code. Never had a need to learn Assembly prior to this).

Code:
CPX player1_object
GetActionStep player1_object
CMP #$00 ;;; is player idle
BEQ +isPlayerIdle   
    JMP playerNotIdle
+isPlayerIdle:   
    LDX player1_object ;;; get player object
    TXA
    STA temp

    LDA Object_y_hi,x ;;; player y for both sides
    CLC
    SBC #$07
    STA tempy
    
    LDA Object_x_hi,x ;;; player x for left side
    CLC
    ADC #$00
    STA tempx

    LDA Object_x_hi,x ;;; player x for right side
    CLC
    ADC #$08
    STA tempA
    GetObjectDirection temp    ;;check player direction
    AND #%00000111
    CMP #%00000100            ;; 4 and above is face left, 3 and less is face right
    BCS +faceLeft
            ;;; left side of hat
            DrawSprite tempx,tempy, #$0c, #%00000001
            ;;; right side of hat
            DrawSprite tempA,tempy, #$0d, #%00000010
            JMP spriteDone

        +faceLeft 
            ;;; left side of hat
            DrawSprite tempx,tempy, #$0d, #%01000010
            ;;; right side of hat
            DrawSprite tempA,tempy, #$0c, #%01000001
            JMP spriteDone

playerNotIdle

CMP #$01
BEQ +isPlayerWalking ;;; is player walking   
    JMP playerNotWalking
+isPlayerWalking:   
    LDX player1_object ;;; get player object
    TXA
    STA temp

    LDA Object_y_hi,x ;;; player y for both sides
    CLC
    SBC #$07
    STA tempy
    
    LDA Object_x_hi,x ;;; player x for left side
    CLC
    ADC #$00
    STA tempx

    LDA Object_x_hi,x ;;; player x for right side
    CLC
    ADC #$08
    STA tempA

    GetObjectDirection temp    ;;check player direction
    AND #%00000111
    CMP #%00000100            ;; 4 and above is face left, 3 and less is face right
    BCS +faceLeft
    
            LDA tempA
            SEC
            ADC Object_h_speed_hi,x
            STA tempA

            LDA tempx
            SEC
            ADC Object_h_speed_hi,x
            STA tempx
            ;;; left side of hat
            DrawSprite tempx,tempy, #$0c, #%00000001
            ;;; right side of hat
            DrawSprite tempA,tempy, #$0d, #%00000010
            JMP spriteDone

        +faceLeft 
            LDA tempA
            SEC
            SBC Object_h_speed_hi,x
            STA tempA

            LDA tempx
            SEC
            SBC Object_h_speed_hi,x
            STA tempx
            ;;; left side of hat
            DrawSprite tempx,tempy, #$0d, #%01000010
            ;;; right side of hat
            DrawSprite tempA,tempy, #$0c, #%01000001
            JMP spriteDone
playerNotWalking
spriteDone:

Any help is greatly appreciated.
 

AllDarnDavey

Active member
I cannot say for sure, but it looks like it's 1 frame off. My random guess is that your draw sprite is being processed before the player is updated, so it's always getting the previous frames values.
 

pierski

New member
I cannot say for sure, but it looks like it's 1 frame off. My random guess is that your draw sprite is being processed before the player is updated, so it's always getting the previous frames values.
Currently, I have the code right after ".include SCR_DRAW_SPRITE_HUD" inside doSpritePreDraw.asm. I see player1_object been called in many places, not quite sure where to move this script to if not here.
 

AllDarnDavey

Active member
I'm a little rusty here, but I believe the player and other object positions are handled in doHandleObjects. There's even a comment in that file just before ".include SCR_DRAW_STATE" that says ";;; And additional object specific drawing stuff would go here."

I don't know if you could move it there without issues, but it seems like it might be the place to start.
 

Jonny

Well-known member
There's even a comment in that file just before ".include SCR_DRAW_STATE" that says ";;; And additional object specific drawing stuff would go here."

Noticed that recently too. Please let me know how you get on with it @pierski because its on my list of things to look into. It's not too bad for enemys especially if they're moving anyway but I wanted to use objects now and then to do something similar for effects (like torches) where you'd usually use bank switching. Like the layered sprites you're doing the lag is really obvious.
 

pierski

New member
I'm a little rusty here, but I believe the player and other object positions are handled in doHandleObjects. There's even a comment in that file just before ".include SCR_DRAW_STATE" that says ";;; And additional object specific drawing stuff would go here."

I don't know if you could move it there without issues, but it seems like it might be the place to start.

When I added it there, it did not render. I wound up adding it to doSpritePostDraw.asm (which is blank by default) and it works perfectly until the screen starts scrolling. Here's a video of what I am seeing:


I'm assuming the coordinates for player1_object change somehow when touching screen scroll. It might be as simple as an ignore or offset when that happens. Currently looking into it.

Here is where I currently am with the code (@Jonny update). Since I am no longer trying to compensate for the speed of the player1_object, I only will need a different state upon walking (though for testing purposes it is the same as every other state).

Code:
CPX player1_object
GetActionStep player1_object
CMP #$01
BEQ +isPlayerWalking ;;; is player walking   
    JMP playerNotWalking
+isPlayerWalking:   
    LDX player1_object ;;; get player object
    TXA
    STA temp

    LDA Object_y_hi,x ;;; player y for both sides
    CLC
    SBC #$07
    STA tempy
    
    LDA Object_x_hi,x ;;; player x for left side
    CLC
    ADC #$00
    STA tempx

    GetObjectDirection temp    ;;check player direction
    AND #%00000111
    CMP #%00000100            ;; 4 and above is face left, 3 and less is face right
    BCS +faceLeft
    
            ;;; left side of hat
            DrawSprite tempx,tempy, #$0c, #%00000001

            LDA tempx ;;; reuse tempx rather than create new variable
            CLC
            ADC #$08
            STA tempx
            ;;; right side of hat
            DrawSprite tempx,tempy, #$0d, #%00000010
            JMP spriteDone

        +faceLeft 
            ;;; left side of hat
            DrawSprite tempx,tempy, #$0d, #%01000010

            ;;; right side of hat
            LDA tempx ;;; reuse tempx rather than create new variable
            CLC
            ADC #$08
            STA tempx
            DrawSprite tempx,tempy, #$0c, #%01000001
            JMP spriteDone

playerNotWalking:
    LDX player1_object ;;; get player object
    TXA
    STA temp

    LDA Object_y_hi,x ;;; player y for both sides
    CLC
    SBC #$07
    STA tempy
    
    LDA Object_x_hi,x ;;; player x for left side
    CLC
    ADC #$00
    STA tempx

    GetObjectDirection temp    ;;check player direction
    AND #%00000111
    CMP #%00000100            ;; 4 and above is face left, 3 and less is face right
    BCS +faceLeft
    
            ;;; left side of hat
            DrawSprite tempx,tempy, #$0c, #%00000001

            LDA tempx ;;; reuse tempx rather than create new variable
            CLC
            ADC #$08
            STA tempx
            ;;; right side of hat
            DrawSprite tempx,tempy, #$0d, #%00000010
            JMP spriteDone

        +faceLeft 
            ;;; left side of hat
            DrawSprite tempx,tempy, #$0d, #%01000010

            ;;; right side of hat
            LDA tempx ;;; reuse tempx rather than create new variable
            CLC
            ADC #$08
            STA tempx
            DrawSprite tempx,tempy, #$0c, #%01000001
            JMP spriteDone
            
spriteDone:
 

pierski

New member
I wound up adding a check for screen scrolling. It is almost there. I just need to:

  • Have the drawsprites match the player during screen scrolling.
  • Offset the drawsprites to the current screen after moving from the first one.

Here is a video of the progress:


And here is my current code:

Code:
CPX player1_object
GetActionStep player1_object
CMP #$01
BEQ +isPlayerWalking ;;; is player walking   
    JMP playerNotWalking
+isPlayerWalking:   
    LDX player1_object ;;; get player object
    TXA
    STA temp

    LDA Object_y_hi,x ;;; player y
    CLC
    SBC #$07
    STA tempy
    
        LDA Object_x_hi,x ;;; player x
        CLC
        ADC #$00
        STA tempx

    LDA scrollByte
    AND #%01000000
    BCS +isScreenScrolling   
        CPX player1_object ;;; get player object


        +isScreenScrolling 

            LDA Object_x_hi,x ;;; player x
            CLC
            SBC camX
            ADC #$00
            STA tempx

    GetObjectDirection temp    ;;check player direction
    AND #%00000111
    CMP #%00000100            ;; 4 and above is face left, 3 and less is face right
    BCS +faceLeft
    
            ;;; left side of hat
            DrawSprite tempx,tempy, #$0c, #%00000001

            LDA tempx ;;; reuse tempx rather than create new variable
            CLC
            ADC #$08
            STA tempx
            ;;; right side of hat
            DrawSprite tempx,tempy, #$0d, #%00000010
            JMP spriteDone

        +faceLeft 
            ;;; left side of hat
            DrawSprite tempx,tempy, #$0d, #%01000010

            ;;; right side of hat
            LDA tempx ;;; reuse tempx rather than create new variable
            CLC
            ADC #$08
            STA tempx
            DrawSprite tempx,tempy, #$0c, #%01000001
            JMP spriteDone

playerNotWalking:
    LDX player1_object ;;; get player object
    TXA
    STA temp

    LDA Object_y_hi,x ;;; player y
    CLC
    SBC #$07
    STA tempy
    
          LDA Object_x_hi,x ;;; player x
        CLC
        ADC #$00
        STA tempx

    LDA scrollByte
    AND #%01000000
    BCS +isScreenScrolling   
        CPX player1_object ;;; get player object

 

        +isScreenScrolling 

            LDA Object_x_hi,x ;;; player x
            CLC
            SBC camX
            ADC #$00
            STA tempx

    GetObjectDirection temp    ;;check player direction
    AND #%00000111
    CMP #%00000100            ;; 4 and above is face left, 3 and less is face right
    BCS +faceLeft
    
            ;;; left side of hat
            DrawSprite tempx,tempy, #$0c, #%00000001

            LDA tempx ;;; reuse tempx rather than create new variable
            CLC
            ADC #$08
            STA tempx
            ;;; right side of hat
            DrawSprite tempx,tempy, #$0d, #%00000010
            JMP spriteDone

        +faceLeft 
            ;;; left side of hat
            DrawSprite tempx,tempy, #$0d, #%01000010

            ;;; right side of hat
            LDA tempx ;;; reuse tempx rather than create new variable
            CLC
            ADC #$08
            STA tempx
            DrawSprite tempx,tempy, #$0c, #%01000001
            JMP spriteDone
            
spriteDone:
 

pierski

New member
I am pretty close now. As far as I can tell, there are really only two issues left to tackle (any assistance is greatly appreciated):
  1. I need to be able to detect when the player1_object has gone beyond the left screen.
  2. I need to be able to detect when the player1_object is on the final screen and cannot scroll.
In the following video, there are a couple things to note:
  1. Different color palette for the backgrounds indicated a different screen.
  2. On the first screen, the small checker pattern on the ground is when the screen scrolling begins.
  3. Solid white lines on the ground indicate when player1_object is beyond the coordinates of the left screen and the right screen has yet to become the left screen.
  4. In the light colored floor, the player is still using bad coordinates from the left screen, while being on the right (once you cross into the dark colored floor, the right screen has become the left).

Here is where I am with the code. I noted the two sections I am having trouble with if anyone can suggest other conditions to check:

Code:
LDX player1_object ;;; get player object
TXA
STA temp

LDA Object_y_hi,x ;;; player y
CLC
SBC #$07 ;;; offsetting the sprite to the player left
STA tempy

LDA scrollByte
AND #%10000000
BNE doUpdateScrolling
    ;;; BETWEEN HERE ;;;
    LDA scrollByte
    AND #%11111101
    ;;; AND HERE is wrong, thus it is being ignored ;;;

    ;;; I am looking for a something to show that the
    ;;; player's X is beyond the width of the left screen, but
    ;;; right screen has yet to become the left
    BNE doAddExtraToScrolling
        LDA Object_x_hi,x ;;; player x
        CLC
        SBC camX
        ADC #$01
        STA tempx

    doAddExtraToScrolling:
        LDA Object_x_hi,x ;;; player x
        CLC
        SBC camX
        ADC #$00
        STA tempx
        JMP noScrollingCheck

doUpdateScrolling:
    ;;; BETWEEN HERE ;;;
    LDA xHold_screen
    AND #%00000001
    ;;; AND HERE is wrong, thus it is being ignored ;;;

    ;;; I am looking for a check that the player is
    ;;; on the last screen and cannot more forward
    BNE doNotAtStopScrolling
    LDA Object_x_hi,x ;;; player x
    CLC
    SBC camX
    ADC #$00
    STA tempx

    doNotAtStopScrolling:
        LDA Object_x_hi,x ;;; player x
        CLC
        SBC camX
        ADC #$02
        STA tempx

noScrollingCheck:

GetActionStep player1_object
CMP #$00
BEQ +isPlayerIdle ;;; is player idle  

    JMP playerNotIdle

+isPlayerIdle:
    GetObjectDirection temp    ;;check player direction
    AND #%00000111
    CMP #%00000100 ;;; check to see if player is facing left
    BCS +faceLeft
        ;;; player is facing right
        LDA tempx
        CLC
        ADC #$08
        STA tempz

        DrawSprite tempx,tempy, #$0c, #%00000001 ;;; left side of hat
        DrawSprite tempz,tempy, #$0d, #%00000010 ;;; right side of hat
        JMP spriteDone

    +faceLeft
        ;;; player is facing left
        LDA tempx
        CLC
        ADC #$08
        STA tempz

        DrawSprite tempx,tempy, #$0d, #%01000010 ;;; left side of hat
        DrawSprite tempz,tempy, #$0c, #%01000001 ;;; right side of hat
        JMP spriteDone

playerNotIdle

CMP #$01
BEQ +isPlayerWalking ;;; is player walking  
    JMP playerNotWalking
+isPlayerWalking:
    GetObjectDirection temp    ;;check player direction
    AND #%00000111
    CMP #%00000100 ;;; check to see if player is facing left
    BCS +faceLeft
        ;;; player is facing right
        LDA tempx
        CLC
        ADC #$08
        STA tempz

        DrawSprite tempx,tempy, #$0c, #%00000001 ;;; left side of hat
        DrawSprite tempz,tempy, #$0d, #%00000010 ;;; right side of hat
        JMP spriteDone

    +faceLeft
        ;;; player is facing left
        LDA tempx
        CLC
        ADC #$08
        STA tempz

        DrawSprite tempx,tempy, #$0d, #%01000010 ;;; left side of hat
        DrawSprite tempz,tempy, #$0c, #%01000001 ;;; right side of hat
        JMP spriteDone
playerNotWalking

spriteDone
 

Jonny

Well-known member
Not sure if this is realated much but this scrolling fix from 4.5.6 might give you some clues how to fix the screen bounds offsetting the sprite.

 

pierski

New member
Not sure if this is realated much but this scrolling fix from 4.5.6 might give you some clues how to fix the screen bounds offsetting the sprite.


Thanks, but no luck. I'm pretty much stuck at this point.

If anyone is doing a game without screen scrolling, this code will work fine. You just need to make the following change:

Code:
    doNotAtStopScrolling:
        LDA Object_x_hi,x ;;; player x
        CLC
        SBC camX
        ADC #$02 ;;; change this to #$00
        STA tempx

Unfortunately, I need the code for a side-scrolling platformer. Any further assistance is greatly appreciated. Thank you.
 

pierski

New member
Finally got to work. Joe mentioned that doSpritePostDraw.asm was too far along in the process and that I should add the drawSprites while the player oject was being created.

So, I added the code to doDrawSprites_PlatformBase.asm right before the "ACTUALLY DRAW THE SPRITES" section that resets variables used in doDrawSpritesLoop. I need those variables and it was better to not create additional Zero Page RAM variables, if I didn't need them.

For this example, I created three new variables with the default values: attX, attY, attZ

Here is a video of the attached sprites:


And here is the code that I added:

Code:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CPX player1_object  ;;; checking whether this is the player object
BEQ +isPlayer

JMP notPlayer

+isPlayer:
    LDA tempB ;;; player y
    CLC
    SBC #$07 ;;; offsetting the sprite to the player left
    STA attY

    LDA tempA ;;; player x
    STA attX

    LDA temp1  ;;; player step
    CMP #$00
    BEQ +isPlayerIdle ;;; is player idle  
        JMP playerNotIdle

    +isPlayerIdle:
        LDA temp2    ;; player direction
        AND #%00000111
        CMP #%00000100 ;;; check to see if player is facing left
        BCS +faceLeft
            ;;; player is facing right
            LDA attX
            CLC
            ADC #$08
            STA attZ

            DrawSprite attX,attY, #$0c, #%00000001 ;;; left side of hat
            DrawSprite attZ,attY, #$0d, #%00000010 ;;; right side of hat
            JMP spriteDone

        +faceLeft
            ;;; player is facing left
            LDA attX
            CLC
            ADC #$08
            STA attZ

            DrawSprite attX,attY, #$0d, #%01000010 ;;; left side of hat
            DrawSprite attZ,attY, #$0c, #%01000001 ;;; right side of hat
            JMP spriteDone

    playerNotIdle:
   
    CMP #$01
    BEQ +isPlayerWalking ;;; is player walking  
        JMP playerNotWalking
    +isPlayerWalking:
        LDA temp2    ;; player direction
        AND #%00000111
        CMP #%00000100 ;;; check to see if player is facing left
        BCS +faceLeft
            ;;; player is facing right
            LDA attX
            CLC
            ADC #$08
            STA attZ

            DrawSprite attX,attY, #$0c, #%00000001 ;;; left side of hat
            DrawSprite attZ,attY, #$0d, #%00000010 ;;; right side of hat
            JMP spriteDone

        +faceLeft
            ;;; player is facing left
            LDA attX
            CLC
            ADC #$08
            STA attZ

            DrawSprite attX,attY, #$0d, #%01000010 ;;; left side of hat
            DrawSprite attZ,attY, #$0c, #%01000001 ;;; right side of hat
            JMP spriteDone
    playerNotWalking

spriteDone
notPlayer
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 

PasseGaming

Active member
I am going to give this a try, I need to add a tiny bit of color to my player sprite. I'm hoping this does the job and I can actually pull it off following this.
 

Jonny

Well-known member
@pierski This is working great so far. The only problem I'm getting is that when I jump with sprites disappear. Still figuring that one out. I see in your example that doesn't happen so must be something in my project.

EDIT: Figured it out. What draws is based on player action step and jump isn't one of the action steps. I might even remove the action steps part as I don't think I need them to be different.
 
Last edited:

pierski

New member
@pierski This is working great so far. The only problem I'm getting is that when I jump with sprites disappear. Still figuring that one out. I see in your example that doesn't happen so must be something in my project.

EDIT: Figured it out. What draws is based on player action step and jump isn't one of the action steps. I might even remove the action steps part as I don't think I need them to be different.
Yeah, for my character I needed the sprites to be attached at different points depending on the animation state and frame. Glad you got the situation resolved.
 
Top Bottom