Jump to content
IGNORED

Introduction: 2600 Programming for Newbies


Recommended Posts

  • 1 year later...

Trust me, I have. I have also tried simpler variants (without all the code, wrote a new program with just 2 banks and a few nops).

I just couldn't get it to work.

Curiously, some examples I found on this board didn't work either.

There is barely any proper example source out there.

I'd be very grateful if you could point out or edit my source. I really need some guidance.

 

This drives me crazy.

Link to comment
Share on other sites

  • 1 month later...

Hey SpiceWare,

I checked out your blog on collect. I really learned a lot from it (newbie) and I am just getting started programming for the Atari and understanding how to display a playfield properly. I used some of your code and stripped it down to just show a basic tank playfield like you have and it keeps chopping off the top of the screen. I have tried for several days to figure out what I am doing wrong, but I just keep going in circles. If I were to post my code and a screen shot, is there any way you could point to where I am going wrong? Any help would be greatly appreciated. Thanks.

Link to comment
Share on other sites

If I were to post my code and a screen shot, is there any way you could point to where I am going wrong? Any help would be greatly appreciated. Thanks.

Sure, though I have a lot going on for the rest of this week and all of next, so it's likely I won't be able to look at it until after the 16th.

 

Go ahead and post it now though, somebody else might spot the issue before I'm able to take a look.

Link to comment
Share on other sites

Sounds like an indexing problem. Some of the pitfalls I ran into when I began coding that might be your problem:

 

- Changing BNE to BPL on a kernel loop that is large. If you have values 128-255 it is a negative value, and BPL is not taken. A kernel might have 192+ lines, so you have to use BNE to loop or do a compare. The compare eats up extra cycles though, and when you get a busy kernel you might not have that.

 

- Loading the counter with a different value accidentally during the kernel. Or not loading it with the correct value in the first place. Doh!!

Link to comment
Share on other sites

I attached my code and a screenshot of what I am getting. I don't think that I am running out of clock cycles, since I'm not really doing any other logic, but I obviously have my timing off somewhere. I have played around with the settings for a few days, trying different combinations to try and get it right, but I am simply not having any success and am becoming discouraged, so I thought that I would try reaching out to you guys.

playfield_test.asm

post-44145-0-43552000-1446826361_thumb.jpg

Link to comment
Share on other sites

Ok, It looks like I finally got my timing right, I used the value 49 in my vertical blank instead of 44, and I used 87 for my Y loop instead of 97. I am guessing that I have to use 87 based on the height of my bitmap image, is that correct??? If I wanted to use a larger bit map image, then what would I adjust my Y loop iterations to? I am not sure about how the two correlate.

Link to comment
Share on other sites

I increased the bitmap image by 1 additional line, or byte for p0,1,2, and it appears that I had to increase the Y loop by 4. I am guessing that this is due to the 2lk loop that we are using. I don't fully understand that loop other that it is allowing you to code accross two scan lines, so why am I having to increase the Y loop by 4 instead of just 2? Also, something I don't understand is that if we are coding across two scanlines, then whay are we not getting an image with a blank space in between each line. I know these are pretty basic questions, but I feel like I can't forward without having a full understanding of how these things work and why we are doing them. Thanks guys!

Link to comment
Share on other sites

I have one other question for whoever can help, in the code that I attached in the previous posts, I am doing a wsync immediately after my playfield is written for the scanline, before the bne to ArenaLoop. And then another wsync at the very beginning of the arenaLoop function. Why am I having to do this? If I don't, then the playfield is half the size of the screen. I can't make sense of it.

Link to comment
Share on other sites

I have one other question for whoever can help, in the code that I attached in the previous posts, I am doing a wsync immediately after my playfield is written for the scanline, before the bne to ArenaLoop. And then another wsync at the very beginning of the arenaLoop function. Why am I having to do this? If I don't, then the playfield is half the size of the screen. I can't make sense of it.

Keep in mind that once you set a PF register it retains that value until you set it again. The second STA WSYNC causes a second scanline to be drawn with the same PF values as the first. Hence the name 2 Line Kernel (2LK). By using the same PF graphics for 2 lines it frees up more cycles to update player graphics and whatever else you may want to do.

 

When you removed the second WSYNC it cut the number of scanlines in half and thus your image appeared to have been shrunk vertically.

Link to comment
Share on other sites

I took a look at your code. First, the top bar is missing on the screen. This is because X gets loaded with 0, but the first time through the code increases X before it is used. To correct it I changed:

   ldx #0
   LDY #96

to:

   ldx #-1
   LDY #96

That way X gets incremented from -1 to 0 the first time through, and the top bar gets drawn.

 

 

Next there is extra stuff at the bottom of the screen. What is happening is X goes 0,1,2,3 and so on to X=23. However, your data is less than that. This will make it clearer:

ArenaPF0:   ; PF0 is drawn in reverse order, and only the upper nybble
        .byte %11110000  ; X=0
        .byte %00010000  ; X=1
        .byte %00010000  ; X=2
        .byte %00010000  ; X=3
        .byte %00010000  ; X=4
        .byte %00010000  ; X=5
        .byte %00010000  ; X=6
        .byte %00010000  ; X=7
        .byte %00010000  ; X=8
        .byte %00010000  ; X=9
        .byte %00010000  ; X=10
        .byte %00010000  ; X=11
        .byte %00010000  ; X=12
        .byte %00010000  ; X=13
        .byte %00010000  ; X=14
        .byte %00010000  ; X=15
        .byte %00010000  ; X=16
        .byte %00010000  ; X=17
        .byte %00010000  ; X=18
        .byte %00010000  ; X=19
        .byte %00010000  ; X=20
        .byte %11110000  ; X=21     

ArenaPF1:   ; PF1 is drawn in expected order
        .byte %11111111  ; X=22     <---- Oh no, we are loading this by accident!
        .byte %00000000  ; X=23
        .byte %00000000
        .byte %00111000
        .byte %00000000

To fix this I just padded some extra zeros:

ArenaPF0:   ; PF0 is drawn in reverse order, and only the upper nybble
        .byte %11110000  ; X=0
        .byte %00010000  ; X=1
        .byte %00010000  ; X=2
        .byte %00010000  ; X=3
        .byte %00010000  ; X=4
        .byte %00010000  ; X=5
        .byte %00010000  ; X=6
        .byte %00010000  ; X=7
        .byte %00010000  ; X=8
        .byte %00010000  ; X=9
        .byte %00010000  ; X=10
        .byte %00010000  ; X=11
        .byte %00010000  ; X=12
        .byte %00010000  ; X=13
        .byte %00010000  ; X=14
        .byte %00010000  ; X=15
        .byte %00010000  ; X=16
        .byte %00010000  ; X=17
        .byte %00010000  ; X=18
        .byte %00010000  ; X=19
        .byte %00010000  ; X=20
        .byte %11110000  ; X=21  

        .byte 0  ; X=22
        .byte 0  ; X=23

ArenaPF1:   ; PF1 is drawn in expected order
        .byte %11111111
        .byte %00000000
        .byte %00000000
        .byte %00111000
        .byte %00000000

You need to do that for ArenaPF1 and ArenaPF2 as well.

 

 

Finally your values loaded into the TIM64T for Vblank and Overscan needed a little adjusting to bring it to 262 lines again. In the source code I changed this back to 49 (was 44 in your code):

VerticalBlank  ;*********************** VERTICAL BLANK HANDLER
        lda #2      ; LoaD Accumulator with 2 so D1=1
        ldx #49     ; LoaD X with 49
        sta WSYNC   ; Wait for SYNC (halts CPU until end of scanline)
        sta VSYNC   ; Accumulator D1=1, turns on Vertical Sync signal
        stx TIM64T  ; set timer to go off in 41 scanlines (49 * 64) / 76

And then I made one more adjustment to the this code for overscan:

   LDA #32-1
   STA TIM64T
  • Like 1
Link to comment
Share on other sites

Wow, that's great stuff. That really helps explain things better. Another question. Is it pretty standard practice to use a 2lk? When I am using a playfield painter app, is it expecting you to use a 2lk with the code that is generated?

I am now working on getting a sprite to appear on the screen at the same time my playfield is being displayed. Having some trouble there, but I'm still plugging away at it. Do you have any tips on that? Common rookie mistakes? It seems like I could just write to the player register right after I write to the playfield register in the arena loop, but I am having problems. If you have any tips that would be great, if not then I will just keep at it until I get it figured out.

Thanks guys!

Link to comment
Share on other sites

Wow, that's great stuff. That really helps explain things better. Another question. Is it pretty standard practice to use a 2lk? When I am using a playfield painter app, is it expecting you to use a 2lk with the code that is generated?

I am now working on getting a sprite to appear on the screen at the same time my playfield is being displayed. Having some trouble there, but I'm still plugging away at it. Do you have any tips on that? Common rookie mistakes? It seems like I could just write to the player register right after I write to the playfield register in the arena loop, but I am having problems. If you have any tips that would be great, if not then I will just keep at it until I get it figured out.

Thanks guys!

The kernel being 1, 2 or more lines really depends on the game. A lot of games use divide the screen into different sections with a kernel for each. An example is drawing a six digit score, and then drawing the rest of the screen.

 

The simplest way is to update the sprite graphics (GRP0 or GRP1) at the beginning of the line (after WSYNC). You have about ~ 21 cycles before anything shows up on the screen so you can update the graphics before it's being drawn. Doing the graphics update mid line is okay if you know you are updating while the sprite is not being drawn. Otherwise you will corrupt your grahics (it will be off by 1 line).

 

You should research skipdraw. I bet Darrell covers that in Collect.

Link to comment
Share on other sites

  • 4 weeks later...
Hey guys, thanks for your help so far. I am still struggling to put all of this together. I checed out SpiceWare's tutorial and it is very well done. However, I am trying to start small and simply get a sprite on the screen along with the playfield using a two line kernel and then later I will add code for joystick and collision. I took a look at the skipdraw routine that you recommended I look at and I incorporated it in to what I am doing. I am part of the way there, but my playfield is all jacked up. I am guessing that my playfield being duplicated has something to do with the 2lk, not sure. On second look, it appears that the height of the playfield is being affected by the starting position of my sprite. I just don't understand. Could someone steer me where I am going wrong before I give up? I will post code and pic.


Thanks.

post-44145-0-71460300-1449098101_thumb.jpg

playfield_test.asm

Link to comment
Share on other sites

Hello Everyone! I'm new to the forum.. It nice to be here. I've been trying to write my first program but ran into a seemingly simple issue that I cannot resolve. I have a playfield and two players that I can move but when I tried to add a ball, it never shows up. Here is the code:

 

;CheckBall
;CPY Ball
;BNE NoBall
LDA #1
STA ENABL

;NoBall

 

I put in the semicolons to rule out the other code as the issue. Shouldn't this code at least produce a vertical line? The Stella debugger does show the that it runs through the code. Elsewhere in the program I tried to get it to move as well:

 

LDA #1
STA CTRLPF
STA HMBL ;Ball Speed

 

and...

 

MainLoop
LDA #2
STA VSYNC
STA WSYNC
STA WSYNC
STA WSYNC
STA HMOVE ;Move Ball

 

Anyone know what I missed?

 

Thanks!

Link to comment
Share on other sites

I took a look at the skipdraw routine that you recommended I look at and I incorporated it in to what I am doing. I am part of the way there, but my playfield is all jacked up. I am guessing that my playfield being duplicated has something to do with the 2lk, not sure.

 

The X register is being used to keep track of which row of the Arena to draw. Your new sprite routine is trampling all over the value of the X register.

Link to comment
Share on other sites

Ug... Thank you- it works! Looks Like the Stella Programming Guide is wrong;

 

The ball graphics register works just like the missile registers. Writing a 1 to the enable ball register (ENABL) enables the ball graphics until the register is disabled.

 

Interesting, that doesn't look correct to me either. I always reference the Write & Read Address Summaries on pages 45 & 46 which clearly show which bits are used for each register.

 

I suspect ENABL, ENAM0 and ENAM1 were originally wired to use bit 0, but they were changed to bit 1 while working on Combat. If I recall correctly, Combat was one of the games developed along side of TIA, so it would have been easy to make design changes to TIA at that time.

 

From the advanced guide (found on the Docs page over at MiniDig):

==============================================================

==============================================================

Showing Missiles/Ball using PHP

==============================================================

==============================================================

 

This trick is originally from Combat and is probably the most efficient way to

display the missiles and/or ball. This trick just requires that you don't use

the stack during your kernal. Recall that:

 

ENABL = $1F

ENAM1 = $1E

ENAM0 = $1D

 

In this example I'll show how to use the trick for both missiles. You can

easily adapt it for the ball too. To set the trick up, before your kernal save

the stack pointer and set the top of the stack to ENAM1+1.

 

tsx ; Transfer stack pointer to X

stx SavedStackPointer ; Store it in RAM

ldx #ENAM1+1

txs ; Set the top of the stack to ENAM1+1

 

Now during the kernal you can compare your scanline counter to your missile

position register and this will set the zero flag in the processor. Then to

enable/disable the missile for that scanline, just push the processor flags onto

the stack. The ENAxx registers use bit 1 to enable/disable which corresponds

with the zero flag in the processor, so the enable/disable will be automatic.

It takes few cycles and doesn't vary the number of cycles depending on the

result like branching usually does.

 

; On each line of your the kernal...

cpy MissilePos1 ; Assumes Y is your kernal line counter

php

cpy MissilePos0

php

 

Then before you do it again, somewhere on each scanline you need to pull off the

stack again using two PLA's or PLP's, or you can manually reset the stack

pointer with ldx #ENAM1+1, txs.

 

After your kernal, restore the stack pointer:

 

ldx SavedStackPointer

txs

This is the method I used in Medieval Mayhem to draw the three fireballs.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...