-
Content Count
415 -
Joined
-
Last visited
Content Type
Profiles
Member Map
Forums
Blogs
Gallery
Calendar
Store
Everything posted by ScumSoft
-
It would be rather lengthy to explain the Slot implementation I came up with, so I'll try and explain it as concise as I can. My 96-pixel playfield is segmented to a 6-byte buffer which is updated every frame, numbered 0 through 5. All sprite data is updated into this buffer each scanline ready to be drawn on the next scanline. It is an interlaced kernal with black Logic scanlines where this is performed. As such I translate the 96-pixel positions to a virtual 12-byte buffer (used abstractly in code) to determine which slot the player resides in. Say the player is in slot 0. If we shift right 3 pixels he will now be 3 pixels into slot 1. However slot 1 is drawn on Frame 2, and is really slot 0. So if I number the slots 0 through 11 instead, and then do a - lda P0slot ;Divide slot by 2 lsr ;- sta P0slot ;Save result afterwards, then I get slots 0 through 5 each frame. But I get to address the slots 0 through 11 when working on them. I'm pretty sure I overcomplicated things by nature, but this is how my brain saw it working so I implemented it to the best of my current skill set. I needed to determine which slot gets the overflowed sprite data, I didn't write any notes as to why I had to increase the slot number, but I am pretty sure it had to do with making sure the slot used during drawing frame 2 would alway match the correct overflow slot and vice versa. You can ignore the need for that routine right now if it is cumbersome to work with, I'll get it reimplemented in an elegant way later on if need be.
-
Are you 100% sure? You are checking bit 3 and not bit 1. Why? That reply I made then quickly fixed would be the typo I should proof before I hit reply. Sorry to confuse! It should be anded with decimal 10 or HEX (A).
-
Shifting the Players each scanline takes too much time and I don't have any cycles left over to update the playfield. It would certainly look better but shifting 8 pixels is a compromise with little more flicker I've made for now. I was unaware that DEC modified the flags, so that is why I overlooked its operation. I've since updated my code where I've been using DCP thank you. [edit]You've posted while I was typing this out. If something looks really dumb then just ask me since it most likely is, I am still very new to programming and trying new things just for the sake of doing them. I was using two mask tables before and when I rewrote the Mask routines I switched to EOR #$FF for some reason, I'll switch back to the second table then. Since my 4 frame kernal flicks quite a bit I probably won't use it, but that is what FrameNum handles. It counts 0,2,4,6 which is used to index the JumpTable for which kernal to use, then in the overscan I determine what the frame was by AND #$0A (I typed AND #10 which is the same), as it returns 0 if I am on Frames 1 or 3. That way I know which order to mask the bytes in. FrameNum is incremented twice before each frame, sorry I forgot to mention this. MaskR2 is indeed superfluous, but I just couldn't think of a method to fit INC P0slot into the normal routines without a bunch of checks. So just to get things working for now I threw the extra code in till a better method is found. Which is where you come in to guide me in my ways. I'll meet anyone half way if you think the answers are so simple I should already know them, just lead the way and I'll understand.
-
I use (AND #10) since my frame counter counts only even values, so I check if I am on frames 2 or 4 for the odds. I use it as an offset to a frame jump table, so I need it to increment twice for convenience later. Otherwise I would just do a LSR to see if bit one is set for odd frames. SAX will AND the Acc with the X register and Store in memory.
-
I like the suggestions given so thanks for your time. I'll be working on my level generation code this weekend, after that I will fully implement these new sprite rotation ideas. Thanks for the help. Since this thread is about me posting code and getting feedback, I might as well get some feedback on my display output kernal and masking routine. I no doubt overcomplicated the design of it, so refinement is always welcome! The basic idea(implemented already and works well) I had was split the screen into 2 48-pixel sprites that are updated in sections each frame, visually like this: Then on the next frame, reposition to the right 8-pixels So in order to move a sprite, we rotate/mask an 8/16-byte buffer for each sprite we want to draw. Each strip of pixel data on the screen is indexed 0 through 5, but treated as a 12-byte index. Since both frames share a 6-byte buffer for display output I initially index 0 to 11, then translate down to which of the 6-bytes were really talking to for the next frame data. I ran into an issue with mid-byte positioning, but eventually got that figured out with the masking routine here: (Variable names changed for clarity and to address only one sprite for example purposes) ;******************************** ; [MASKING ROUTINES] ;******************************** MaskData: lda #15 ;[]+2 16 byte sprite sta Counter ;[]+3 Byte index counter lda P0slot ;[]+3 Check slot number, even or odd (indexed 0 to 11) Frame1 is even slots, 2 is odds ;- so if the player origin is in an Odd slot, then moving to the right would place him in an Even slot, and vice versa lsr ;[]+2 Odd values always have bit 1 set bcs OddSlots ;[]+2/3 Branch if carry set EvenSlots: ;Slots 0,2,4,6,8,10 in GFXoutput ;This was tricky, since I have to know which frame I am on for correct masking order lda FrameNum ;[]+3 Load current frame number and #10 ;[]+2 Frame counts 0,2[,4,6 in my 4 frame kernal], so AND with #10 to determine even/odd frames beq .MaskR ;[]+2/3 CHANGE PLACES! Mask in reverse order .MaskN ;Mask Normal order ;Data used in Frame1 ldy P0shift ;[]+3 Sprite shift amount ldx MaskTable,Y ;[]+4 Get proper bit masking by shift amount ldy Counter ;[]+3 Fetch sprite index 15 to 0 lda P0buffer,Y ;[]+4 Get sprite data to work on sax P0buffer,Y ;[]+4 Apply mask and save new data lda #$FF ;[]+2 Compare value, needed for addressing a 0 index? dcp Counter ;[]+5 Decrement and compare bne .MaskN ;[]+2/3 More sprite data to work on? rts ;[]+6 Done, return .MaskR ;Mask Reverse order ;Data will be used in Frame2 ldy P0shift ;[]+3 Sprite shift amount lda MaskTable,Y ;[]+4 Get proper bit masking by shift amount eor #$FF ;[]+2 Reverse mask tax ;[]+2 Used for SAX instruction ldy Counter ;[]+3 Fetch sprite index 15 to 0 lda P0buffer,Y ;[]+4 Get sprite data to work on sax P0buffer,Y ;[]+4 Apply mask and save new data lda #$FF ;[]+2 Compare value, needed for addressing a 0 index? dcp Counter ;[]+5 Decrement and compare bne .MaskR ;[]+2/3 More sprite data to work on? rts ;[]+6 Done, return OddSlots: ;Slots 1,3,5,7,9,11 in GFXoutput lda FrameNum ;[]+3 Load current frame number and #10 ;[]+2 Frame counts 0,2[,4,6 in my 4 frame kernal], so AND with #10 to determine even/odd frames beq .MaskN ;[]+2/3 CHANGE PLACES! Mask Normally here instead of reverse .MaskR2 ;Mask Reverse 2 ;Data will be used in Frame2 but in next slot number ldy P0shift ;[]+3 Sprite shift amount lda MaskTable,Y ;[]+4 Get proper bit masking by shift amount eor #$FF ;[]+2 Reverse mask tax ;[]+2 Used for SAX instruction ldy Counter ;[]+3 Fetch sprite index 15 to 0 lda P0buffer,Y ;[]+4 Get sprite data to work on sax P0buffer,Y ;[]+4 Apply mask and save new data lda #$FF ;[]+2 Compare value, needed for addressing a 0 index? dcp Counter ;[]+5 Decrement and compare bne .MaskR2 ;[]+2/3 More sprite data to work on? inc P0slot ;[]+5 Adjust for mid byte roll over rts ;[]+6 Done, return MaskTable: ;ShiftAMT ;$00,$01,$02,$03,$04,$05,$06,$07 .byte $FF,$7F,$3F,$1F,$0F,$07,$03,$01 It would be nice to eliminate MaskR2 as the only difference vs MaskR is that I need to increase the sprites GFXoutput slot number, as determined by being on the Oddslot set and reverse masking. I will spend more time looking at how other people manage such things and will definitely learn from them. So all the assistance I get is VERY much appreciated
-
Vblanks time is entirely used for working on the remaining sprites, level construction, sounds and game logic, and masking the buffers to get them ready for drawing. Only the player and monsters are 8x16 sprites and therefore take the most time to work on, so I do them in the overscan first, everything else are 8x8 sprites and not an issue. I'll probably rearrange the workload as need be later on, I just need the entire games functionality in place first. But I wanted to see if there was a way to optimize this routine now as it dictates how large of a sprite I can toss in my game and still have time left over for other things. If 8x8 is the largest feesable sprite to work on then I have to design the game around this accordingly see? But I am sure I can get some 8x16 ones in here.
-
Require some dumbed down definitions
ScumSoft replied to Random Terrain's topic in 2600 Programming For Newbies
So operands dictate what the operation instruction does, and so nop acts as operand only when passed a value. Otherwise it does nothing but waste cycles and bytes. It does both nothing and something depending on how you talk to it, but it's purpose in life is to take up space and waste time -
Require some dumbed down definitions
ScumSoft replied to Random Terrain's topic in 2600 Programming For Newbies
NOP = do nothing, waste 2 cycles NOP #0 = do nothing, waste 2 cycles and an extra byte NOP VSYNC = do nothing, waste 3 cycles and an extra byte NOP.w = do nothing, waste 4 cycles and 2 extra bytes All of the above are the same as: X = X But vary in cycles used and space taken. So, "I yam what I yam" is the answer. -
I do appreciate the help, I'll see how much of an impact this new setup makes. What is most important is to get the entire routine to minimal cycles used, So I really like the hybrid shift + preshifted sprite idea, one thing I definitely didn't think of using before. I am over budget by 456 cycles in the overscan because I moved from 8x8 sprites to 8x16. 8x8 just didn't have the space to make the player look right, but this also added quite a bit of presprite overhead to the routines. I need preshifted data due to the way my software output buffers align to the 96x96 screen space I have setup right now. The player position registers aren't moving along with the sprite like your typical game does, instead they are stationary and split into 6 sections per frame, then aligned to form a 12x24 software settable block of pixels. Ok, off to test the code. Be back later on.
-
Require some dumbed down definitions
ScumSoft replied to Random Terrain's topic in 2600 Programming For Newbies
Like this! NOP #0 YAY! What do I win? -
Require some dumbed down definitions
ScumSoft replied to Random Terrain's topic in 2600 Programming For Newbies
Then I would suggest something along the lines of: Operand: "Instruction parameters also instructions themselves" -
I need to optimize what this routine does, even tho I wrote it myself I can't seem to find a way to make it faster. Or substitute a different method in it's place NOT preshifting every sprite sacrificing rom space for cycles, it's a much better learning experience to think of a way to do this faster. ;******************************** ; [ROTATE ROUTINES] ;******************************** ;I test RotateAMT before entering the routine, skipping when not needed. RotateBytes: lda #15 ;[]+2 Work on 16 bytes of data 0-15 sta Counter ;[]+3 Set counter lda RotateAMT ;[]+3 Fetch rotate amount cmp #5 ;[]+2 Faster to do ROL? bpl .doROL ;[]+2/3 Branch if yes ;Rotate values 1 through 4 .RORa ldx RotateAMT ;[]+3 Load amount to rotate ldy Counter ;[]+2 Use counter as byte index, Y is trashed so reload counter lda SPRITE,Y ;[]+4 Load Sprite byte to be rotated .RORloop ;8-bit rotate tay ;[]+2 Save byte being worked on ror ;[]+2 Rotate data into carry tya ;[]+2 Restore byte being worked on ror ;[]+2 Shift carry into byte dex ;[]+2 Countdown rotate amount, worst case cycles for single byte = 52, best = 12 bne .RORloop ;[]+2/3 Loop if more to rotate ldy Counter ;[]+3 General counter sta SPRITE,Y ;[]+4 Store Result into 16-byte SPRITE buffer lda #$FF ;[]+2 Compare value dcp Counter ;[]+5 Decrement counter, compare with #$FF bne .RORa ;[]+2/3 Branch if more bytes to rotate rts .doROL ;Rotate values 5 through 7 ;A holds RotateAMT right now eor #6 ;[]+2 Set value to 1,0, or 3 bne .ROLa ;[]+2/3 Does rotate value = 0 lda #2 ;[]+2 Yes then load corrected value .ROLa sta RotateAMT ;[]+3 Save new value .ROLb ldx RotateAMT ;[]+3 Load amount to rotate ldy Counter ;[]+2 Use counter as byte index, Y is trashed so reload counter lda SPRITE,Y ;[]+4 Load Sprite byte to be rotated .ROLloop ;8-bit rotate tay ;[]+2 Save byte being worked on rol ;[]+2 Rotate data into carry tya ;[]+2 Restore byte being worked on rol ;[]+2 Shift carry into byte dex ;[]+2 Countdown rotate amount, worst case cycles for single byte = 52, best = 12 bne .ROLloop ;[]+2/3 Loop if more to rotate ldy Counter ;[]+3 General counter sta SPRITE,Y ;[]+4 Store Result into 16-byte SPRITE buffer lda #$FF ;[]+2 Compare value dcp Counter ;[]+5 Decrement counter, compare with #$FF bne .ROLb ;[]+2/3 Branch if more bytes to rotate rts
-
The Andrew Davie Sessions
ScumSoft replied to Random Terrain's topic in 2600 Programming For Newbies
Very nice, I don't see anything wrong on initial glance. Makes the tutorials much easier to follow along with. Oh wait just noticed this in "Session 7" under Reset Signal. It should say "VSYNC" minus the H. -
Require some dumbed down definitions
ScumSoft replied to Random Terrain's topic in 2600 Programming For Newbies
Wouldn't the very first line explain it all? If you believe this is too wordy read it out loud, you should take a breath at the comma and at no other time (except before reading it of course) Using "In other words" is a re-explanation and therefore redundant. -
>.< So, you only want to goto gamescreen if the fire button is pressed? what say, happens if you don't press the fire button.
-
Yeah I figured as much, the 2600 isn't controlling the TV so much as it is walking along with it. I became curious if sending a VSYNC signal would tell the TV to stop what it was doing and return the beam to the VBLANK period prematurely. If this was possible you could refresh the screen a second time much quicker thus hitting the phosphors again in a shorter period. Even if the refresh was off you wouldn't have any roll since you'd be controlling the beam the entire time. Now then, you can draw however many scanlines you wish, so long as the TV's timing is still sent the VBLANK signal once you're done. Case and point in the following demos where none of them have an Overscan period. As soon as the desired number of scanlines are drawn, we can hop back to the VBLANK and start drawing again. Although in order to avoid the roll, the required number of scanlines has to be drawn as seen in the case of the 170scanline demo, even though the scanline number is consistent, it still rolls. (I believe this can be avoided with careful timing) I was hoping we could force a non-standard refresh rate on the TV, as this would open up some really nice tricks. I've been plugging along with my game and desire to use a 4-frame flickerblind kernal without any flicker. If I could skip the overscan and refresh the screen once every other frame, this would eliminate the flicker. It works well in Stella, so I might make a version that uses this trick just for emulation play and use my other kernal for the real units. Well, it was worth a shot. [edit] Whoops forgot to add the 170scanline.bin 262Interlaced.bin 262Scanlines.bin 170Scanlines.bin
-
Is it possible to force a VSYNC instead of performing the Overscan? It seems to work on Stella, but on the real console the TV seems to always perform the Overscan. I would very much like to tell the TV to skip the Overscan and reset the frame to perform a fast redraw on the screen that would minimize/eliminate flicker on a 4 frame kernal. It would be nice if possible, as the turn around time would minimize the length of time between phosphor hits and thus offering brighter colors and minimize or eliminate the flicker seen. After 4 frames have been drawn, then we go to the Overscan and process the needed logic. Lather rinse repeat.
-
EPROM, Erasable Programmable Read Only Memory. EEPROM, Electrically Erasable Programmable Read Only Memory. EPROM's had to be erased with UV light. EEPROMS can be erased via software commands, like a flash drive or bios. Now you shall never forget
-
Of course they did, they just called it Berzerk instead I swear those things are cylons.
-
Is that by Imagic or Activision? Most people are scum. HEY! I resemble that comment.
-
Metal Max 2600, Final Version Released!
ScumSoft replied to Master_Programmer's topic in batari Basic
Don't know if it's intentional design, but start the game and walk left till you fall, nothing happens, so then walk right and jump. Now you've warped to a different part of the level. You can also walk into the walls and jump up over and over. The enemies if not defeated, as you move to the next screen will fall off the sides of the screen and continue shooting at you. Just a bit odd. By the way, the only real voting option is obviously the 6th choice Aside from that, pretty neat. Also I am not hearing any sound, is it me or is the game just silent? -
Oh yes I did, simple typo on my part. I've realized that there isn't a need to do any of this at all, I simply don't have to do the shifting during the draw phase and can preshift the data during Vsync and Overscan time then store the result in an 8byte buffer for each object to be displayed on screen. My game is using less than 1/3 of the 128 bytes of ram, so this isn't a problem as there is only ever 4 objects on the screen maximum. I'll look into using the DPC+ for future improvements to this kernal which provides much more ram space to work with
