Jump to content
IGNORED

Ballblazer Brainstorming


Thomas Jentzsch

Recommended Posts

I think Ballblazer only has two sprites that overlap the board (the other player, and the goalposts)?

It think it is ok to draw the goalpost outside the board. So only the other player is left. This should make the sprite code pretty simple.

 

Thinking about it, if we could get away with using the ball for the other player (might become ugly), we could use the sprites and missiles for drawing a really smooth board. And the background color changes for filling the gaps. :ponder:

Link to comment
Share on other sites

Further kernel brainstorming:

 

1. For the board, either use

a) PF graphics (slightly lower resolution, but easier to handle)

b) Repeated BK color writes (better resolution, but hard to handle)

2. Use all 5 or just 3 (BL, P1, M1) objects for smoothing the vertical lines. Use 3 in the vertical area where the other player's ship is visible. For the lines, you just have to calculate one vertical line. The other ones are moving at a fixed, relative speed.

3. Between the board rows, use a horizontal, "antialiasing" line with intermediate color. Since this one requires litte processing time, we could put some timeconsuming code (e.g. color switches) in here.

4. Use P0 (and maybe M0) for drawing the other players ship. EDIT: P0/M0 because they have priority over P1/M1.

5. Goalposts and the Plasmorb all drawn above the board so we don't have to care about them.

 

Here is a coarse example of point 2 (using 5 objects for smoothing, but even using just 3 objects should look still good). All 5 objects are 8 pixels wide. The 2nd picture gives a better impression after filling some gaps.

 

As you can see, most lines (except the most centered ones, which we will try to smooth) will become pretty much horizontally drawn, so a lower horizontal resolution should work well here.

post-45-1222155603_thumb.png

post-45-1222155610_thumb.png

Ballblazer001.bin

Edited by Thomas Jentzsch
Link to comment
Share on other sites

Some further brainstorming:

 

Original 5200 version: 168x47 pixel board, topmost square 16 pixels wide -> 11 squares horizontally, bottom square 16+(47-1)*2 = 108 pixel wide. 21 squares horizontally in total.

 

Converted into an Atari 2600 screen with 152 pixel (8 pixel lost due to HMOVE blanks), the topmost square would have to be ~15 pixel wide. Then we would get 11 squares horizonally too. And the bottom square would be maybe 101 pixel wide. And the screen would be 44 pixel tall.

 

Displaying 11 squares in the topmost row seems almost impossible now. So either we cheat there (so that nobody notices) or we increase the square size.

 

For cheating, we could split the kernel into 2 (or more) parts, which are drawn differently. E.g. at the very top (~25%), at the left and right corners, we "simulate" the pattern with a combination of repeated objects and PF graphics. And below we switch to a (more) correct representation. So that maybe 10% of the screen are cheated and the other 90% are correct.

 

Or, if we increase the square size to e.g. 24 pixel (7 squares) for the topmost row. To maintain the same scope from the total game area visible, we would reduce the 21 horizontal squares to e.g. 14 (21*16/24).

Link to comment
Share on other sites

Hi Thomas,

 

this was my last playfield experiment. It could generate a vector on the fly. Maybe it could be used to generate the playfield. Or calculate sprite positions.

 

Temp       = $80

playfield01 = $D3
playfield11 = $D4
playfield21 = $D5


lda #%00011111		; START WITH ONE DOT (BIT 4)  IN PF0.
sta playfield01		;  playfield01 .. 21 are buffers for the playfield.
lda #0
sta playfield11
sta playfield21

lda #10
sta Temp		;CALCULATE A VECTOR FROM 0,0 to 44,10

ldy #44			;NR OF SCANLINES
lda #50			;MAX WIDTH

KERNEL_LOOP

SBC Temp		;(2)
BPL NOMOVE		;2	;if plus, do nothing.   if minus, it's time to move one pixel to the right


SEC			;2	;set bit in carry
ROL playfield01		;5	;move playfield 1 pixel to the right.
ROR playfield11		;5
ROL playfield21		;5

ADC #50			;(2)	add 50 to make A positive again.
NOMOVE
TAX			;2	;draw the screen... usual stuff.
LDA playfield01		;3
STA PF0			;3
LDA playfield11		;3
STA PF1			;3
LDA playfield21		;3
STA PF2			;3
TXA			;2


sta WSYNC
dey 
bne KERNEL_LOOP

LDA #0			;clean up pf's
STA PF2
STA PF1
STA PF0

Link to comment
Share on other sites

this was my last playfield experiment. It could generate a vector on the fly. Maybe it could be used to generate the playfield.

You have to write the PF registers twice each row. So you also have to store and update 6 PF variables. Which won't work within 76 cycles.

 

Currently I prefer your solution with the timed COLUBK writes. Especially because it allows the brown borders. But it requires a hell lot of different kernels. :)

Edited by Thomas Jentzsch
Link to comment
Share on other sites

this was my last playfield experiment. It could generate a vector on the fly. Maybe it could be used to generate the playfield.

You have to write the PF registers twice each row. So you also have to store and update 6 PF variables. Which won't work within you 76 cycles.

That's right. At least it does things in realtime :) The idea behind it is that I make 1 buffer for the line and then make minor updates to it every scanline. if you study the checkerboard, It only changes a few pix every scanline.

Otherwise, the technique could be used to create a nice racing game, only one tile needed.

 

Currently I prefer your solution with the timed COLUBK writes. Especially because it allows the brown borders. But it requires a hell lot of different kernels. :)

As long as it fits into 4KB, I'm happy.

Link to comment
Share on other sites

The idea behind it is that I make 1 buffer for the line and then make minor updates to it every scanline. if you study the checkerboard, It only changes a few pix every scanline.

Sure, but even this is probably too much within 76 cycles. Plus you NEED color writes for the brown borders.

 

Otherwise, the technique could be used to create a nice racing game, only one tile needed.

Don't get distracted! :)

 

As long as it fits into 4KB, I'm happy.

I really doubt that. Though it would make me happy too.

Link to comment
Share on other sites

Below a lower square resolution screenshot.

 

Biggest problem now, is waiting a well defined number of cylces as efficient and flexible as possible.

op_nop_imm	  = $80
op_nop_zp	   = $04
op_nop_abs	  = $0c
op_nop		  = $ea

jmp	 (.jmpWait)			 
.byte   op_nop_imm, op_nop_imm, op_nop_imm, op_nop_imm
.byte   op_nop_imm, op_nop_imm, op_nop_imm, op_nop_imm
.byte   op_nop_abs, op_nop_zp,  op_nop
;continue code here...

This works for 7 and more cycles and adjusting costs just 5 cycles. But how about wasting 1 to 6 cycles? Or better: 1 and more?

 

Else I would have to use a huge amount of kernels and I don't like that.

post-45-1222514445_thumb.png

Link to comment
Share on other sites

Could you explain what your code does?

 

For the sprites you would only need to use horizontal motion registers right?

 

for eating 1 cycle I used the following code, probably not what you are looking for:

	LDA lineScroll	;(3)
AND #%00000001		;(2)
BNE Skip0		;(2/3)
Skip0	
etc.

 

My experience is that every other (other then a big dumb kernel) method I tried, the overhead of extra cycles rendered the method unusable for the upper part of the checkerboard. And you have to deal with the following problems:

- Getting tiles with the right color. Like: brown at the sides, green in the middle

- Getting tiles with the right size.

- Scroll 1 full tile. to the right/left

 

issues for certain areas of the checkerboard:

upper tiles: Quick change of colors, solved with using ram, scrolling is easy because they don't scroll that far

middle tiles: More difficult to scroll, not enough ram to get data for tiles, so indexed table from rom is used but costs extra cycles.

lower tiles: changing colors is easy because they are big, scrolling is hard because the have to scroll a lot.

Link to comment
Share on other sites

What it does is it allows the kernal to waste a number of cycles from 7 upward (5 for the indirect jump, and 2 or more depending on where it leads). Going to the last byte wastes 2 cycles (a single NOP), going to the second-to-last byte wastes 3 cycles (NOP zp) because the last byte is now treated as an argument, and so on. This is taking advantage of the undocumented features of the 65xx cpu (some prefer to call them "illegal opcodes")...allowing the kernal to perform any subsequent writes at specific cycle times.

 

The table below shows what the processor will interpret the table values as for each of the destinations...

 

    .byte   op_nop_imm ;waste 12 cycles (NOP# & NOP# & NOP# & NOP# & NOPabs)
   .byte   op_nop_imm ;waste 11 cycles (NOP# & NOP# & NOP# & NOP# & NOPzp)
   .byte   op_nop_imm ;waste 10 cycles (NOP# & NOP# & NOP# & NOPabs)
   .byte   op_nop_imm ;waste 9 cycles (NOP# & NOP# & NOP# & NOPzp)
   .byte   op_nop_imm ;waste 8 cycles (NOP# & NOP# & NOPabs)
   .byte   op_nop_imm ;waste 7 cycles (NOP# & NOP# & NOPzp)
   .byte   op_nop_imm ;waste 6 cycles (NOP# & NOPabs)
   .byte   op_nop_imm ;waste 5 cycles (NOP# & NOPzp)
   .byte   op_nop_abs ;waste 4 cycles (NOPabs)
   .byte   op_nop_zp  ;waste 3 cycles (NOPzp)
   .byte   op_nop     ;waste 2 cycles (NOP)

 

It seems that the only way to do less is to involve a seperate sub-kernal that is decided upon beforehand, right?

Link to comment
Share on other sites

My experience is that every other (other then a big dumb kernel) method I tried, the overhead of extra cycles rendered the method unusable for the upper part of the checkerboard.

The upper part requires a lot of special kernels, that's for sure. But the lower part looks easy enough to be handled by a few, more general kernels.

 

And you have to deal with the following problems:

- Getting tiles with the right color. Like: brown at the sides, green in the middle

- Getting tiles with the right size.

- Scroll 1 full tile. to the right/left

Since I decided for color writes, all the problems melt into one problem: Writing to COLUBK at the right time. Though I have a 2 cycle tolerance here, at least in the middle and lower part, since the objects used for smoothing will hide such small errors.

 

issues for certain areas of the checkerboard:

upper tiles: Quick change of colors, solved with using ram, scrolling is easy because they don't scroll that far

middle tiles: More difficult to scroll, not enough ram to get data for tiles, so indexed table from rom is used but costs extra cycles.

lower tiles: changing colors is easy because they are big, scrolling is hard because the have to scroll a lot.

No scrolling for me at all. :)

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...