4.5.9 How To Make The Screen Shake: Improved Version

Bucket Mouse

Active member
I've finally souped up my Screen Shake script originally written for 4.1.5. The previous version relied on a subroutine called doWaitFrame to advance the shake to the next frame (without it, the entire computation would happen in one VBlank and you'd see nothing).

But I was informed using doWairFrame wasn't necessary. I was putting the script in doDrawSprites, and doDrawSprites actually runs on every single frame, so it's possible to enter instructions that take multiple frames to display without specifically commanding the NES to do so. Okay, good.

I started using that knowledge to revise the shake script. It was far trickier than I thought, because I had to rethink the entire logic of it. I could no longer do loops within the script itself. Instead I had to rig it so the game would read one part, leave the script, paint the screen, then on its second pass through doDrawSprites, read the next part, and on like that. It required FOUR variables to pull off:

shake1
shake2
shakeCycle
shakeOn

So your first step is to enter those into User Variables. Next you must open doDrawSprites and paste all this at the very end, right after ReturnBank:

Code:
        ;;;;; THIS MATERIAL ADDED TO SHAKE THE SCREEN ON COMMAND
    
    LDA shakeOn
    CMP #$01
    BNE shakeskipper
    
    shake:
    LDA #$04 ; this means it will shake four pixels...change the number to what you desire
    CMP shake1 ; the shake forward variable
    BEQ shakeBack
    INC camY ; move screen ahead by one pixel...change this to camX if you want a horizontal shake
    INC shake1 ; variable counting the current number of pixels away from the norm
    JMP shakeskipper

    shakeBack:
    LDA #$04
    CMP shake2 ; the shake backward variable
    BEQ shakeOver
        DEC camY ;move screen backwards by one pixel...change this to camX if you want a horizontal shake
    INC shake2
    JMP shakeskipper

    shakeOver:
    LDA shakeCycle
    CMP #$04 ; stops shaking after four vibrations...change the number to what you desire
    BEQ resets ; if it's the number, reset all variables...otherwise increase shakeCycle
    INC shakeCycle ; variable for number of vibrations in sequence
    LDA #$00 ; clear cam-counting variables
    STA shake1
    STA shake2
    JMP shakeskipper
    resets: ; resets all variables for next use
    LDA #$00
    STA shake1
    STA shake2
    STA shakeCycle
    STA shakeOn

shakeskipper:

HOW TO USE IT
I've made notes, but just to be clear....

The script as-is will shake the screen vertically by four pixels, four times in a row. You can change the number of shakes and/or the number of pixels by altering the numbers where noted. To shake the script horizontally instead of vertically, change the two mentions of camY to camX. It's fully customizable for your own game. Just remember that the shake forward and the shake back must be the same number.

WHERE TO PUT IT
The shake script turns on and off with a switch. You decide where that switch is. It's controlled by this handy little script:

Code:
    LDA #$01
    STA shakeOn

I use it as a monster AI. It enhances sprite-based cutscenes, and when a boss pounds the ground, you really feel it! Using it as a tile is trickier, since it'll just keep shaking until the sprite gets off. You'll have to write the tile to change on touch. Use this for tiles:

Code:
    TXA
    PHA
    
        ;;;;;;;;; First, let's turn the underlying tile into a normal walkable tile.
    LDY temp1
    LDA temp2
    BEQ +isEvenCt
        ;; is an odd ct, so looking in collisionTable2
        LDA #$00
        STA collisionTable2,y
        JMP +doneWithTileUpdate
    +isEvenCt
        LDA #$00
        STA collisionTable,y
        
    +doneWithTileUpdate

    LDA #$01
    STA shakeOn

    PLA
    TAX

HOW IT'S BETTER THAN MY PREVIOUS VERSION
The shakes are faster. The shake does not pause the action -- sprites will move while the shake is in progress, so you can use it anywhere. Most importantly, EVERYTHING shakes including the sprites, which was not the case in the previous version!
 

offparkway

Member
Awesome! I just tried to implement this in 4.5.9 but I don't see any results. I pasted the code at the end of doDrawSprites (you said after "ReturnBank", but I don't see ReturnBank anywhere. The script ends with RTS, so I put it after that).

Created the variables and everything, and set it as an enemy AI. The game compiles and runs just fine, but nothing happens. I tried attaching the shakeOn "switch" code to an input button for testing, but couldn't make it do anything there either. Am I missing something?
 

dale_coop

Moderator
Staff member
Maybe you added the code in the wrong script...?

check again your doDrawSprites script... (open the "Project Settings > Script Settings" and under "Subroutines" you should see the doDrawSprites script assigned to the "Handle drawing Sprites", used for your project. Select and click on the "Edit" button. The code needs to be added at the end of that script)
 

offparkway

Member
Maybe you added the code in the wrong script...?

check again your doDrawSprites script... (open the "Project Settings > Script Settings" and under "Subroutines" you should see the doDrawSprites script assigned to the "Handle drawing Sprites", used for your project. Select and click on the "Edit" button. The code needs to be added at the end of that script)
That’s what I’m editing, yes. Although I’m using the Platform version (in the brawler module). Would that make a difference? Does this script maybe not like scrolling games?

I don’t see “ReturnBank” in the standard doDrawSprites either, though.
 
Last edited:
Top Bottom