It is currently Sun Dec 09, 2018 2:14 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 5 posts ] 
Author Message
PostPosted: Thu Sep 06, 2018 9:26 pm 
Offline

Joined: Tue Aug 28, 2018 8:54 am
Posts: 96
Location: Edmonton, Canada
So I am trying to make a Pong (because I don't know anything easier) and I am still wrapping my head around over the verbosity of the assembler.

From one side, I want to save RAM, from other side iterating through OAM with limitations of 6502 is quite painful and verbose.

My question is should it be? What is the common sense approach? Should I treat OAM as player/mob/item source and hardcode them or should I store x,y,type and oam index separately and assign the OAM sprite(s) "dynamically"? Obviously it does not matter for my Pong, but it does for almost any other dynamic game.

Code:
; Init above ^
; I put some comments for the post to explain what I am trying to achieve
@forever:
    lda ppu_nmi_done ; Execute main loop once per frame
                               ; Flag is set in the end of NMI
    beq @forever
    lda #0
    sta ppu_nmi_done ; And reset by the main loop
    ; The only thing NMI does is runs DMA on $200 ram address

   ; So here I check the pads and set the direction
    lda #0
   sta tmp1 ; reset the variable with direction verctor
    lda #PAD_DOWN
    bit controls_buttons
    beq :+
        lda #$01
        sta tmp1
    :
    lda #PAD_UP
    bit controls_buttons
    beq :+
        lda #$FF ; -1
        sta tmp1
    :

    lda tmp1 ; because we don't know if it was set above
    beq @endPlayerMove ; if vector is 0 loop around
    ; Collision check
   
   ; The following code is where I move player around and it
   ; is my main question
   
    lda OamData
   ; OamData is just label to $2000
   ; So I "reserved" spries 1 to 4 for my "paddle"
   
   ; Just checking Y from OAM ram of first sprite against the boundaries
    ldx tmp1 ; move direction
    cmp #0 ; up boundary
    bne :+
        cpx #$FF ; up
        beq @endPlayerMove ; boundary hit
    :
    cmp #208 ; down boundary
    bne :+
        cpx #$01 ; down
        beq @endPlayerMove
    :

   ; And now I just change the coordinates directly
    ldx #0
    :
        lda OamData, x
        clc
        ; Adding my vector here; 5 + 1 = 6 but 5 + $FF = 4
        adc tmp1
        sta OamData, x
        inx
        inx
        inx
        inx
        cpx #20 ; 4 * sizeof(OamSprite) I have 4 sprites for the paddle
        bne :-
@endPlayerMove:
    jmp @forever


Top
 Profile  
 
PostPosted: Thu Sep 06, 2018 9:38 pm 
Offline
User avatar

Joined: Tue Jun 24, 2008 8:38 pm
Posts: 2118
Location: Fukuoka, Japan
In your example with pong you may be able to keep it simple but in a more complex system, you will need to have a list of entity (player, enemy, bullet, whatever your system manage) that will contain information about the sprites they are using (usually a metasprite that contains a list of sprite about that specific animation frame).

On every frame, you will go trough the list of entity that requires to be shown. That list will contain the information regarding the metasprite to be shown and their world coordinate (the location on your currently displayed map). From that information, based on the current location of the camera, every sprite from that metasprite need to be either culled if outside the camera view or shown. The one shown will have to be converted to screen coordinate. The shown sprite will then be written at the OAM (commonly at $200).

If the current frame contains less sprite then the previous one, then the buffer (OAM) must be updated accordingly.

I simplified things a little bit but that is the basic of such a system. Every game will scrolling map will have to develop to manage such entities. A one screen game will have that too but won't have to worry about the camera since you are always on the same screen, making thing a little bit easier.

edit:

I explained about entity system but did not really answer you question. For this, I apologize.

If the system is simple then yes, you may be able to use the same buffer for managing your sprite then doing the DMA transfer to the PPU OAM. For a simple game, you don't have to worry that much about memory.

If it's your first game and learning from it, don't worry to much about how it must be "perfectly coded". You will make mistake and from those, learn what works or not ;)


Last edited by Banshaku on Thu Sep 06, 2018 9:46 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Thu Sep 06, 2018 9:46 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 7003
Location: Canada
In most games, the OAM is not used to store your game state variables directly. It's filled up each frame, copying/transforming from the game state elsewhere.

One big reason for this is the 8 sprite per scanline limit, once you have too many tiles on a scanline the others will drop out. Many games have some way to shuffle the order sprites are placed in the OAM, creating the "flicker" effect that's frequently seen in NES games; if you can't shuffle the list like this basically one character will go invisible, which is much worse than flickering.


Top
 Profile  
 
PostPosted: Thu Sep 06, 2018 9:54 pm 
Offline

Joined: Tue Aug 28, 2018 8:54 am
Posts: 96
Location: Edmonton, Canada
Thank you both. It makes sense now. So in the basic case in "non static" game just iterate through entities like below and fill sprites one by one when needed (no flickering trick), and fill the rest of OAM with $FF.

Code:
type: .res 10 ; (for 10 entities)
xlo: .res 10 ; 16bit X for horizontal scrolled
xhi: .res 10
animation: .res 10 ; to keep the frame
animationTicks: .res 10 ; to keep how long it took
data: .res 10 to keep the state


It is still hard to not be afraid to use the precious 1.5KB (- stack - oam) of RAM. After coming from enterprise programming with gigabytes or memory and GC.


Top
 Profile  
 
PostPosted: Thu Sep 06, 2018 11:03 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 7003
Location: Canada
yaros wrote:
...fill the rest of OAM with $FF.

You can save a bunch of cycles by just filling the Y coordinate with FF. Once it's offscreen the other 3 bytes don't matter.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group