Jump to content
IGNORED

Bike Night Game - Programming questions


toad

Recommended Posts

Rather than open a thread each time I had a question, I thought I might just open a thread and consolidate all my questions here.

 

Basically I'm developing a game, called Bike Night. It's a horizontal scroller, with a motorcycle going up and down on a track.

In that sense its similar to Excitebike. But unlike Excitebike the goal is not to win a race against other bikes but to do tricks.

 

I am learning assembler - I've written games - for the Ti-99, Colecovision, Palm Pilot and iOS devices. Ti-99 was a extended basic game back in the day - Colecovision & Palm Pilot in C, and for iOS I use the titanium framework to write in javascript.

 

The reason I'm giving you my background so you can understand I've always been a high level programmer. I don't understand how the hardware works - and never had to, but now I want to know.

 

I've decided to split my screen into 3 parts. There will be a top level area which is primarily just there to add color to the screen. It'll horizontal scroll, and you'll see flags, colors, bright lights, etc.

Then the 2nd part of the screen is the track area. and the 3rd area of the screen at the bottom will display the score and messages like "Wheelie jump" or "Big Air" - it's a bike trick game, so you get the immediate feedback when completing a trick.

 

OK, so today's question, I am getting started on some coding, and I have made a character set for the track area.

 

I've read some old articles about Atari fine scrolling. My understanding (please correct if wrong) is the hardware can do fine scrolling for a character or two. But the way you got it to scroll over several screens is you combined fine scrolling with coarse scrolling. After you fine scrolled say 8 pixels, then you did a coarse scroll by a character (which involved just changing the pointer to where the screen memory began)

 

OK question take a look at this source from the book "Atari Roots"

 

10 ;

20 ; THE VISITOR

30 ;

35 TXTBUF=$5041

40 OPNSCR=$5003

50 PRNTLN=$5031

70 ;

80 *=$600

90 ;

0100 TEXT .BYTE $54,$41,$4B,$45,$20,$4D,$45,$20

0110 .BYTE $54,$4F,$20,$59,$4F,$55,$52,$20

0120 .BYTE $4C,$45,$41,$44,$45,$52,$21

0130 ;

0140 VIZTOR

0150 ;

0160 LDX #0

0170 LOOP LDA TEXT,X

0180 STA TXTBUF,X

0190 INX

0200 CPX #23

0210 BNE LOOP

0220 JSR OPNSCR

0230 JSR PRNTLN

0240 INFIN JMP INFIN

 

OK, now, you have the assembler pseudo op ".BYTE"

 

And apparently one is looping through and using the data stored there - how to use it, I get.

 

lets say I have all this data for screens and I put it in .BYTE directives in my source.

And I loop through and I place the screen data into memory.

 

What I don't get - this may sound like a ludicrous question, but what I don't get is am I doubling the amount of memory being used???

 

By that I mean - how does an executable itself work.

 

Lets say my executable is called bnight.exe - when I run that, does the entire game load into memory?

If so, do I have the entire screen data loaded into memory and when I copy it to the screen area, I've essentially just doubled the amount of memory being used for this data?

 

Would it make more sense, if trying to save bytes, to leave the screen data in a separate file on disk, and then programatically retrieve it and then load it into the appropriate area, rather than using a byte directive and having that data part of code?

 

Am I completely confused? Thanks!

  • Like 3
Link to comment
Share on other sites

p.s. sorry for the long post, I was just basically looking for a sanity check.

 

0100 TEXT .BYTE $54,$41,$4B,$45,$20,$4D,$45,$20

0170 LOOP LDA TEXT,X

0180 STA TXTBUF,X

0190 INX

0200 CPX #23

0210 BNE LOOP

 

Basically I know of no way that this program can work unless the values in the .BYTE directive are part of the executable and in memory somewhere. And therefore if you copy from one place in memory to another - you've doubled the amount of memory being used.

 

Sane reasoning or insane? And to avoid this? One idea I have is to load screen data from the disk. Basically I was wondering if I'm missing something obvious - or I've managed to grasp the obvious? LOL...its hard to have confidence when starting out...

Edited by toad
Link to comment
Share on other sites

Basically I know of no way that this program can work unless the values in the .BYTE directive are part of the executable and in memory somewhere. And therefore if you copy from one place in memory to another - you've doubled the amount of memory being used.

 

Sane reasoning or insane? And to avoid this? One idea I have is to load screen data from the disk. Basically I was wondering if I'm missing something obvious - or I've managed to grasp the obvious? LOL...its hard to have confidence when starting out...

 

Totally sane.. have more confidence x)

 

There are a couple of posts about binary files near here that can explain better how to configure your program, to load different sections of the file in different areas of memory. So, you could made the .byte data load in the area that you need it.

You could also continue loading from disk the data that you need, or to put another example, if you want to write a line to screen you could point the display list to your data, instead of moving all those bytes.

 

But, you should stop worrying about these details for now.. is pretty common to have a lot of different data that you need to move to a specific area or buffer in memory, like with printing text to the screen using OS routines, or moving the data of a game level to a default buffer, etc.

 

Losing 20 or 30 bytes is nothing important for now :)

Link to comment
Share on other sites

one track is 20 screen lenghts long, it will be more than 30 bytes, that I could lose, I think.

 

But that said, if I end up doing 5 tracks, Ill have to use some compresson and then unpack to the screen area, probably between levels, so anyway that implies no direct "duplicating"

 

but thats later for now, Id just like to put up a track and as a learning experience, place the screen data directly in the place I want it. I will definately try to locate those other posts you mentioned. I have been googling around, but havent had much luck...

Link to comment
Share on other sites

oh I think I found it, that origin directive that is often at the start of an assembly program, can actually be used at anytime? So I could do an orofin directive, followed by the byte directive, and it would allocate the memory at that location?

Link to comment
Share on other sites

>Sane reasoning or insane? And to avoid this?

The reason why it's there in AtariRoot is perfectly sane. The Atari 8-bit family was shipped with an different amount of RAM per model (400 originally was planned to have 4k, shipped with 16K and could be extended to 48k, 800 could have up to 64k, 800XL always had 64k, etc.).

 

And the screen RAM is at the end of the physically available RAM. This is also a good idea because all the different graphics modes use between 1..8k and this way you leave as much space as possible between LOMEM and screen RAM start for the program.

 

Consequence 1: If you want to make your program run on different machine, you don't know where the screen RAM starts. Hence you have to put the data somewhere an store it dynamically to the right location (given by the screen RAM pointer $58/59).

 

Consequence 2:If you write an assembler program that anyway requires a 64k machine, you can ignore all of the of the above, put your DL and screen once at the appropriate memory location and your're done.

Link to comment
Share on other sites

one track is 20 screen lenghts long, it will be more than 30 bytes, that I could lose, I think.

 

But that said, if I end up doing 5 tracks, Ill have to use some compresson and then unpack to the screen area, probably between levels, so anyway that implies no direct "duplicating"

 

 

From what you've described there'll be a lot of repeating elements and, because i'm assuming it's going to look somewhere between Excitebike and the Kikstart series, i'll use a terrible mock-up of the latter for demonstration purposes. You build one block of map data containing all the possible elements for your level that ends up looking something like this (columns numbered in hex):

 

post-3086-0-20579900-1376557994_thumb.png

 

Now you can just store references to the map for the actual levels so a five column wide line of even ground will just be $00, $00, $00, $00, $00, a short plateau with a down ramp afterwards is $02, $02, $02, $02 followed by $11, $12, $13, $14 and an up ramp to jump over a row of TARDISes is $05, $06, $07, $08, $09, $1a, $1b, $1c for the ramp and $15, $16, $17 repeated three times for three police boxes (with $00 between them if they need to be spaced out a bit).

 

This is pretty much how my first real game on the C64 worked and i wrote all of the tools myself back then, but you can use Windows-based tools to build the map of elements and just work out the levels themselves straight into the assembler.

 

but thats later for now, Id just like to put up a track and as a learning experience, place the screen data directly in the place I want it. I will definately try to locate those other posts you mentioned. I have been googling around, but havent had much luck...

 

i'd advise compressing the maps from the get go, otherwise you're going to need to go back, rip out the work and replace it.

Link to comment
Share on other sites

Awesome guys! thanks for the advice.

 

This has turned my thinking for certain. I was thinking of the screen as tiles, with tiles repeating a lot, one could use run length encoding to represent the track.

The look of my track is more isometric - and track construction is a bit more limited in my game than in your example.

 

But now, in thinking in terms of a track construction utility - tile level is too granular. I was never going to allow someone to put any tile anywhere on the track.

 

So, if I think of it in terms of blocks, where you can put a track piece, or a ramp piece or a speedup piece, on the track. Then I have my compression right there...a screen is made of blocks, and you just need a few references, on some screens just very few references.

 

Well I told myself to put the artwork on drop box so I could sneak in working on this at lunch, but alas I forgot. Oh well, I guess it'll keep until tonight.

 

JAC - thanks for the reminder about atari OS and how the memory location for screen data can vary. Now I get it, I will probably just target 64K but, it makes a lot of sense now about the approach used in some assembly language tutorial examples.

Link to comment
Share on other sites

one track is 20 screen lenghts long, it will be more than 30 bytes, that I could lose, I think.

 

But that said, if I end up doing 5 tracks, Ill have to use some compresson and then unpack to the screen area, probably between levels, so anyway that implies no direct "duplicating"

 

but thats later for now, Id just like to put up a track and as a learning experience, place the screen data directly in the place I want it. I will definately try to locate those other posts you mentioned. I have been googling around, but havent had much luck...

 

I was thinking in this one:

http://atariage.com/...-file-segments/

 

Also for the future maybe you would like to read these ones:

http://atariage.com/...oss-assembling/

 

http://atariage.com/...best-practices/

 

Yep, for bigger levels any kind of compression could be useful, then you can depack all before starting a new level, or construct the level dinamically when you move through it.

Link to comment
Share on other sites

mockup



thanks I'll read that. The gallery picture is to show visually what I think will work. I'm going to attempt to create a display list that will allow for these sections:


sections
------------
top section is Antic 4 - expecting to get 5 colors, which I plan to use for 4 greys and blue.
flag section is Antic 4 - blue, green, yellow, purple, brown
track section is graphics 0 - light blue and dark blue
bottom section is graphics 0 - black and white

Motorcycle is all 4 players and one missile character.
colors are yellow and white, and where they overlap - black.

Shadow is made up of the remaining 3 missiles - color black.
Link to comment
Share on other sites

Thanks again!

 

Well I guess I'll have to double the size of the motorcycle. But that'll be OK. In some ways that'll be fun.

Then, I'll have to test about the black. Some books allude to this - like this one:

 

http://gury.atari8.info/card_pmg.htm the entry for GPRIOR mentions it. Well I guess I'll have to test.

 

Now would the clouds work? Can you pick the same color with different luminances, or do I need to rework the top area?

Link to comment
Share on other sites

Latest mockup; still pending verification of black actually displaying.

 

http://en.wikipedia....R_.24D01B_Write

 

Where Player pixels overlap the color values are OR'd together (when PRIOR bit value $20 is set). So, it's easy to make a LIGHTER color/shade from two Players, but not a darker color or black.

 

HOWEVER, when multiple priority bits are set resulting in a priority conflict where a PLAYER pixel overlaps a PLAYFIELD pixel, then a true black pixel is the result. ... say PRIOR bits $01 and $08 are both set which simultaneously directs that PM0 is higher than PF0 and PF0 is higher than PM0, then where Player 0 and Playfield 0 intersect, the result is black. (I think for this priority bit combination the conflict situation occurs for PF0 and PF1 vs all the Players 0 to 3.)

 

The total package requires blitting around a playfield shape in sync with two Player shapes, but in the end you get five object colors -- PM0, PM1, PM0+PM1 overlap, PF0, and PM0+PF0 overlap . More colors if you also use the overlaps of the other two Players, and playfeld colors.

 

 

Also, IF the shadow always occurs below (on a lower scanline) than all parts of the bike, then you can re-use any previously used object (Player/Missile or Playfield) as the shadow by using a DLI to change the color. By using a dark grey instead of the black used on the bike, the shadow adds another color to the overall appearance. However, the difficulty here is that since the bike and shadow are also moving vertically on the screen based on jumps and terrain (bike) and terrain (shadow) this requires the DLI to vary the scanline for the color change.

 

 

Alternatively, rather than getting all fancy like this, just change the way you combine players....

Using color value $02 as "black" for PM0 (and PM2) and using color value $FC (light yellow) for the other Players.

Where PM0+PM1 or PM2+PM3 overlap the resulting color should be $FE, nearly white.

 

Or, using $04 as "black" (grey -- tires are never really all black) you can use a darker (more mid-range) color value for the bike (such as $FA), so the result of $04 OR $FA is again $FE

 

OR if you compromise what "black" is on the bike.... say dark blue ($92) then you can pick something else like red ($48) resulting in overlap color $DA, light green...

 

Experiment.

Link to comment
Share on other sites

I took your advice - I brought up two sprites and overlapped them - ugh. I didn't like.

 

Now one thing is interesting - I'm using an emulator right now, and if it goes into attract mode, that mode can change one of the players to black, leaving another player at a different color and the overlap and a 3rd color. But I don't have any clue if that particular observation could be used to force the atari to do something.

 

You are right, I don't need to use any of my precious players to do the shadow.. So here is what I'm going to do instead...PM0 will be left yellow. PM1 right yellow. PM2 will be left black(both tires and shadow), PME3 will be right black (tires and shadow)...and the missiles will be white. The white is decorative, I should be able to make it work - it'll mostly be in the middle of the cyclist.

 

Whew - what a mess on the sprite - I think I orginally wanted the shadow to be missiles so I could "collide" with them, but that's entirely unnecessary I will know when the bike hits the ground for the same reason that I'd have to know where to place the shadow.

 

 

click on the pic to see only 2 sprites, producing 3 colors (one of them black, but its in attract mode) - I used Atari800MacX and did a screen clip.

 

overlap

Edited by toad
Link to comment
Share on other sites

Missiles have two color options based on the value of PRIOR bit $10...

 

When $10 is OFF, then Missiles 0 to 3 are displayed using the color registers for Players 0 to 3.

 

When $10 is ON, then all missiles are displayed using the color register COLPF3 ($D019)/COLOR3 ($02C7) (or 711)

Link to comment
Share on other sites

I've read some old articles about Atari fine scrolling. My understanding (please correct if wrong) is the hardware can do fine scrolling for a character or two. But the way you got it to scroll over several screens is you combined fine scrolling with coarse scrolling. After you fine scrolled say 8 pixels, then you did a coarse scroll by a character (which involved just changing the pointer to where the screen memory began)

 

http://en.wikipedia.org/wiki/ANTIC#Scrolling

http://en.wikipedia.org/wiki/ANTIC#HSCROL_.24D404_Write

 

Yes, what you describe is essentially correct. It can fine scroll horizontally up to 16 color clocks. That's 4 characters in Antic modes 2, 3, 4, and 5. 2 characters for Antic modes 6 and 7. After reaching the scrolling limit then you reset the fine scroll value and do a coarse scroll ("changing the pointer to where screen memory began").

Link to comment
Share on other sites

No new questions at the moment, but I did combine all 5 players into one sprite and have it on my display...whew, theory is one thing but there were some complications in getting it going. Ultimately I have kept the 3 colors, black, yellow, white, but did slim the dude down to fit into 18 x 16.

Sprite

Link to comment
Share on other sites

I am learning assembly as I write this program.

So...I've seen some more efficient examples for clearing the PM area.

I've seen some better ways for drawing the sprite- I intend to study those later.

 

For now I have a couple questions, but the first one I want to know is what am I doing wrong - such that the OS feels free to write into my PM area.

Something is causing it to write all over my stuff. Now, I arbitrarily picked the spot for the PM area - rather than ramtop -8. That was just because I was experimenting with different areas, seeing if I could find one that didn't get all this garbage on the display.

 

10 ;
20 ; PROOF OF CONCEPT - BIKE SPRITE
30 ;
40  *=$5000
50  JMP START
60 ;
70 ; Atari OS Locations
80 ;
100 P0SIZELOC=$D008
110 P0HPOSLOC=$D000
120 P0COLORLOC=$02C0
130 DMACTLLOC=$022F
140 PMBASELOC=$D407
150 GRACTLLOC=$D01D
160 GPRIOR=$026F
170 ;
500 ;
510 ; Sprite Data
520 ;
530 PLAY0 .BYTE 0,0,0,0,0,0,0,0,14,9,8,10,13
540  .BYTE 6,7,252,72,180, 180,149,72,48,0,0,0,0
550 PLAY1 .BYTE 0,0,0,0,0,0,128,0,0,0,0,96,32,32
560  .BYTE 192,188,50,41,45,41,18,12,0,0,0,0
570 PLAY2 .BYTE 0,0,0,0,7,8,1,15,1,6,7,1,0
580  .BYTE 0,248,0,0,0,0,0,0,0,0,0,0,0
590 PLAY3 .BYTE 0,0,0,0,128,192,0,192,192,0,192,128,64
600  .BYTE 156,56,64, 0,0,0,0,0,0,0,0,0,0
610 PLAY4 .BYTE 0,0,0,0,0,13,11,0,0,0,0,1,8
620  .BYTE 4,0,12,12,12,44,0,0,0,0,0,0,0
630 ;
640 ;
650 ;
1000 START
1010 ;
1020  JSR INIT
1030  JSR GAMELOOP
1040 ;
1050 INIT
1060  JSR INITCOLOR
1070  JSR INITLOCATIONS
1080  JSR INITPM
1090  JSR CLEARPLAYERS
1100  RTS
1110 ;
1120 ;
1130 INITCOLOR
1140 ; PM Colors and Size
1150  LDA #0
1160  STA P0COLORLOC
1170  STA P0COLORLOC+1
1180  STA P0SIZELOC
1190  STA P0SIZELOC+1
1200  STA P0SIZELOC+2
1210  STA P0SIZELOC+3
1220  STA P0SIZELOC+4
1230  LDA #220
1240  STA P0COLORLOC+2
1250  STA P0COLORLOC+3
1260  LDA #14
1270  STA P0COLORLOC+7 ; Missile color
1280  RTS
1290 ;
1300 INITLOCATIONS
1310 ; Player and Missile Locations
1320  LDA #90
1330  STA P0HPOSLOC ; players 0,2
1340  STA P0HPOSLOC+2
1350  LDA #94
1360  STA P0HPOSLOC+4 ;  missiles
1370  LDA #96
1380  STA P0HPOSLOC+5
1390  LDA #98
1400  STA P0HPOSLOC+6
1410  LDA #100
1420  STA P0HPOSLOC+7
1430  LDA #98
1440  STA P0HPOSLOC+1 ;players 1,3
1450  STA P0HPOSLOC+3
1460  RTS
1470 ;
1480 INITPM
1490 ; General Player Missile setup
1500  LDA #128 ; new location
1510  STA PMBASELOC
1520  LDA #46
1530  STA DMACTLLOC
1540  LDA #3
1550  STA GRACTLLOC
1560  LDA #17 ;
1570  STA GPRIOR
1580  RTS
1590 ;
1600 CLEARPLAYERS
1610 ; Fill player missile area with zeros
1620 ; clear missile area
1630  LDA #$00 ; always zero
1640  LDX #$00 ; start at zero
1650 MISSILECLEAR
1660  STA $8180, X ;
1670  INX
1680  CPX #$7F ;
1690  BNE MISSILECLEAR
1700 P3CLEAR
1710  STA $8380, X
1720  INX
1730  CPX #$7F
1740  BNE P3CLEAR
1750 P2CLEAR
1760  STA $8300, X
1770  INX
1780  CPX #$7F
1790  BNE P2CLEAR
1800 P1CLEAR
1810  STA $8280, X
1820  INX
1830  CPX #$7F
1840  BNE P1CLEAR
1900 P0CLEAR
1910  STA $8200, X 
1920  INX
1930  CPX #$7F
1940  BNE P0CLEAR
3010  RTS
4000 ;
4010 ;
4020 GAMELOOP
4030 ;
4040  JSR DRAWBIKE
4050 ;
4060 ; DO STUFF
4070 ; PROFIT
4080 ;
4090 ;
4100  JSR CHECKEND
5000  JMP GAMELOOP
6000 DRAWBIKE
6010 ;
6020  LDX #$00
6030 ;
6040 LOOP0
6050  LDA PLAY0, X
6060  STA $823C, X ; hard coded
6070  INX 
6080  CPX #$1A
6090  BNE LOOP0
6100 ;
6110 LOOP1
6120  LDA PLAY1, X
6130  STA $82BC, X ;
6140  INX 
6150  CPX #$1A
6160  BNE LOOP1
6170 LOOP2
6180  LDA PLAY2, X
6190  STA $833C, X ;
6200  INX 
6210  CPX #$1A
6220  BNE LOOP2
6230 LOOP3
6240  LDA PLAY3, X
6250  STA $83BC, X
6260  INX 
6270  CPX #$1A
6280  BNE LOOP3
6285  LDX #$00
6290 LOOP4
6300  LDA PLAY4, X
6310  STA $81BC, X ;
6320  INX 
6330  CPX #$1A
6340  BNE LOOP4
6350  RTS
6360 ;
6370 CHECKEND
6380 ; Always end for now
6390  JMP END
6400  RTS
6500 ;
9000 END
9010  .END

Link to comment
Share on other sites

oh lol. Well....now I get it, my newbie eyes couldnt see it. Thats hilarious, I thought the OS was at fault...now that I think about it, why would the OS be drawing my sprite....oh well, newbie mistake... whew, now I can move on to the display list...should be fun.

Link to comment
Share on other sites

oh lol. Well....now I get it, my newbie eyes couldnt see it. Thats hilarious, I thought the OS was at fault...now that I think about it, why would the OS be drawing my sprite....oh well, newbie mistake... whew, now I can move on to the display list...should be fun.

Link to comment
Share on other sites

question, so I've done a display list. It seems to work fine, but I'm just creating the display list (copying a display list into memory) and then telling the Atari where to find it. Is that all you do? I mean or was I supposed to time this in some way - turn something off, load the display list at a specific moment, turn something back on?

 

ok, now I'm looking ahead to putting my graphics on the screen. so "the plan" -> I create a 1024 byte long character set, tell the atari where to find that. I create the screen memory, tell the atari where to find that.

 

to simplify creating the character set, I've taken my screen mockup into Graph2Font program. At first I couldn't find where it was saving any fonts - but as I was writing this message I found the "Save As" and then you use filetype "ASM all data (*.asm)" - not to be confused with ASM Assembler file (*.asm) which does not product the desired results.

 

Whew, then I change the x-asm format into what Atari Assembler Editor needs - and I should have a screen background to go with my sprite :)

Edited by toad
Link to comment
Share on other sites

Yup. Just point ANTIC at the display list and it takes care of the rest. (provided the display list is a proper set of instructions.)

 

In most cases you can just use the shadow registers for DMACTL and DLIST to kill the display DMA, set the address of the display list , and then restart the screen DMA. Then if the vertical blank happens anywhere within this block, you don't get a garbled screen. At worst you'll get a blank screen for one frame.

 

LDA #0
STA SDMCTL; $022F
LDA #<DISPLAYLISTADDRESS ; low byte
STA SDLSTL; $0230
LDA #>DISPLAYLISTADDRESS ; high byte
STA SDLSTH; $0231
LDA #$2E; decimal 46
STA SDMCTL

 

Later if display management and timing become are a priority that requires you kill the VBI, then you would write directly to the hardware registers instead of using the OS shadow registers.

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