Jump to content
IGNORED

Writing a multisprite/multibank game is harder than I thought


jbs30000

Recommended Posts

Well, OK, in all fairness, part of the problem is that I keep wanting to write huge, somewhat complex games instead of simple 4k games. This works fine with the regular kernel, but for the multisprite kernel it doesn't take much code before you start running into "out of range" errors when you try to goto or gosub somewhere, or sometimes the drawscreen command gives it.

 

This time, I'm trying to make a 2600 Space Harrier (yeah, yeah, I know, you're all doing this :roll: aren't you?)

 

Part of the problem is that I have a LOT of sprites. If somebody knows how to share sprite data in a multisprite environment, it would help me cut down on the number of sprites I use. I know how to share sprite data in the standard kernel using playerxpointerlo, playerxpointerhi, and playerxheight, but setting those in the multisprite kernel doesn't seem to work. Looking at the memory map on Random Terrain's site, I'm guessing that maybe the spritesort, and spritesort2-5 variables need to be manually set too?

 

Anyway, here's what I have so far. The screen is animated; you can move Space Harrier around and fire the gun; and I put two enemy weapons on the screen. If they touch your player the game freezes (well, the collision routine isn't perfect and the "collision" might not register.) As you can see, the weapons are animated, and I use the NUSIZ register to enlarge them to make the appear as if they're coming towards you. There is no game to play yet because when I started writing the routines to display and move the enemy sprites, even though I didn't get an out of range error when jumping to them, the display got all screwed up, so I'll have to rewrite everything AGAIN :x !

Space_Harrier.bas.bin

  • Like 1
Link to comment
Share on other sites

I was guessing you posted the bin so that we could see what you've done so far. If we were supposed to see it for a split second, then a frozen screen, not sure what the point was. A screenshot would have accomplished that, without the need for a download. For future reference, if you want us to see a single screen, why not post a single screen.

 

As far as the game itself, it makes zero use of the playfield for anything but visuals, lame. This will end being like moving a cursor around on the screen and pushing a button, similar to the "learn to use your mouse" exercises that used to come with computers, only without variable velocity so even less fun.

Link to comment
Share on other sites

Part of the problem is that I have a LOT of sprites. If somebody knows how to share sprite data in a multisprite environment, it would help me cut down on the number of sprites I use. I know how to share sprite data in the standard kernel using playerxpointerlo, playerxpointerhi, and playerxheight, but setting those in the multisprite kernel doesn't seem to work. Looking at the memory map on Random Terrain's site, I'm guessing that maybe the spritesort, and spritesort2-5 variables need to be manually set too?

I didn't use more than one bank, but I did use shared sprite data using the multisprite kernel for Tone Toy 2008 (thanks to SeaGtGruff). It seems there is even more of a limit to how long a sprite can be when using the multisprite kernel and you have to break up the sprite data (look at the code for Tone Toy 2008 to see a working example). Below are parts of two PMs that SeaGtGruff sent me when I was working on Tone Toy 2008 and needed major help finding where the sprite data was. I don't think that SeaGtGruff would mind if I post it since it's just helpful info and not the pin number to his bank account:

 

The mulltisprite kernel handles sprites differently than the standard kernel does, which means the "long sprite table" trick must be handled differently, too. Personally, now that I've learned a few more things about how the multisprite kernel handles sprites, I think it's wasting ROM space-- but I'm not sure how to improve it.

 

Anyway, I've adjusted your code so the sprites work correctly now. I tried to make minimal changes -- I split the long sprite into two sections, and I added two data tables to store the lo and hi sprite pointer values.

I asked if there was a way I could figure out where those locations are on my own and this was his reply:

 

What I did was generate an assembly listing and then look for where it was setting the player pointers. I have my compile batch set up to generate an assembly listing automatically whenever I compile a bB program. To do this, you must edit your 2600bas.bat file and find the places where it calls the dasm assembler (there are two lines where it does this). Then you add the -l switch (that's a lowercase L, for "listing"), followed by %1.lst (don't put a space between them-- i.e., it's -l%1.lst). This is what my dasm command line looks like in my 2600bas.bat file:

 

dasm.exe %1.asm -f3 -I%bB%\Includes -l%1.lst -o%1.bin

 

There's a lot of other stuff after that, related to the sed.exe program, but you can leave it be. Your batch file might not have the .exe extensions on dasm and sed-- they aren't necessary, but I added them on anyway-- and I may have rearranged the command switches to put them in alphabetical order (in particular, I think I moved the -f switch to put it in front of the -I switch). If you want to add the -l switch, you can put it anywhere after the %1.asm, but before the part where it starts getting into the sed.exe program.

 

Anyway, after you compile your bB program and it generates a .lst listing, you open up the .lst file and search for your "player0:" statements. If you want, you can save time by looking for "set kernel multisprite," since the two "player0:" statements come right after that. This is what they look like in the .lst file:

 

   1175  f43f										 game
  1176  f43f						 .L00			;  set kernel multisprite
  1177  f43f
  1178  f43f						 .L01			;  player0:
  1179  f43f
  1180  f43f			   a9 5a			  LDA	#<playerL01_0
  1181  f441
  1182  f441			   85 a2			  STA	player0pointerlo
  1183  f443			   a9 fb			  LDA	#>playerL01_0
  1184  f445
  1185  f445			   85 a3			  STA	player0pointerhi
  1186  f447			   a9 a2			  LDA	#162
  1187  f449			   85 b0			  STA	player0height
  1188  f44b						 .L02			;  player0:
  1189  f44b
  1190  f44b			   a9 5a			  LDA	#<playerL02_0
  1191  f44d
  1192  f44d			   85 a2			  STA	player0pointerlo
  1193  f44f			   a9 fc			  LDA	#>playerL02_0
  1194  f451
  1195  f451			   85 a3			  STA	player0pointerhi
  1196  f453			   a9 1e			  LDA	#30
  1197  f455			   85 b0			  STA	player0height

 

Then you want to see what the program is setting player0pointerhi to. You actually need to look at the line immediately before that, where the program is loading the accumulator:

 

   1183  f443			   a9 fb			  LDA	#>playerL01_0
  1184  f445
  1185  f445			   85 a3			  STA	player0pointerhi

 

and

 

   1193  f44f			   a9 fc			  LDA	#>playerL02_0
  1194  f451
  1195  f451			   85 a3			  STA	player0pointerhi

 

The important part is where the machine code is, in the middle of the line. For the first LDA instruction, the machine code is "a9 fb," and for the second LDA instruction it's "a9 fc." The "a9" is the machine code that means "LDA #" (load the accumulator with a number), and the other part is the hi-byte (or page number) of the address where the sprite table starts-- in this case, "fb" for the first sprite table, and "fc" for the second sprite table. Then you have to convert those values to decimal so you'll know what to use in the "phi" data table, as follows:

 

a=10, b=11, c=12, d=13, e=14, f=15

 

fb = 16*f + b = 16*15 + 11 = 240 + 11 = 251

 

fc = 16*f + c = 16*15 + 12 = 240 + 12 = 252

 

data phi
251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251
251,251,251,251,251,251,251,251,251,251,251,252,252,252,252,252
end

 

Or you can use the hex values without converting them, as long as you put "$" in front of them:

 

data phi
$fb,$fb,$fb,$fb,$fb,$fb,$fb,$fb,$fb,$fb,$fb,$fb,$fb,$fb,$fb,$fb
$fb,$fb,$fb,$fb,$fb,$fb,$fb,$fb,$fb,$fb,$fb,$fc,$fc,$fc,$fc,$fc
end

Some or all of that may not apply to your program, but there it is in case it might be helpful.

Link to comment
Share on other sites

Sorry, I wasn't trying to be rude. The sprites look great but the animation is a little choppy.

Wow, somebody is really grouchy.

If you move the player away from the rotating objects, the game doesn't freeze. And yes, nothing really happens but I'm showing the animation that I have accomplished so far. I can't show animation in a still picture.

Link to comment
Share on other sites

Thank you Random Terrain, I'll give that a try. The 2600bas.bat I use already outputs assembly listings so I'll make a file with sprites only for player0, and look for the phi values.

ETA - I added the -l%1.lst to the .bat file. I think that this will help a lot since I won't have to do GOSUBs or GOTOs to set the sprites. In fact, I think I'll try and see if I can also set the playfield without having to use gosub or goto. I think that this will be a huge help. Thank you again.

 

MausGames, what's choppy? The sprite animations? It's really hard to get them just right.

Edited by jbs30000
Link to comment
Share on other sites

Hmmm, I thought I had it, but something isn't right. I first tried with multibank, then tried with only 1 bank.

For this test code, I only put in the values for the first sprite. The list file listing for the first sprite was this:

  1198  f443		       a9 a6		      LDA	#<playerL05_0
  1199  f445
  1200  f445		       85 a2		      STA	player0pointerlo
  1201  f447		       a9 f5		      LDA	#>playerL05_0
  1202  f449
  1203  f449		       85 a3		      STA	player0pointerhi
  1204  f44b		       a9 12		      LDA	#18
  1205  f44d		       85 b0		      STA	player0height

So I put this code to place sprite 4 on the screen and do an endless drawscreen loop. Only thing is, nothing shows on the screen.

data LoPointer
$a6
end
data HiPointer
$f5
end
data Height
$12
end

Test
player4pointerlo=LoPointer[0]: player4pointerhi=HiPointer[0]: player4height=Height[0]
player4x=70: player4y=70: COLUP4=10
el
drawscreen: goto el

And, here's the whole test program code if you need it:

rem includesfile multisprite_bankswitch.inc
set kernel multisprite
rem set romsize 16k
pfheight=1


Space_Harrier rem ****************************Player sprites***************************
rem COLUP0=170
player0:
 %01000100
 %10101010
 %10101010
 %10101010
 %10101010
 %01010100
 %00111100
 %01110110
 %10101001
 %10101001
 %10110110
 %10111101
 %11000011
 %01011010
 %00100100
 %00100100
 %00011000
end

Gun_Fire
rem COLUP0=62
player0:
%00011000
%00111100
%00111100
%00111100
%00111100
%00111100
%00111100
%00011000
end
return otherbank
Unarmored_Ship rem ***************************Enemy sprites**************************
player0:
 %10011001
 %01111110
 %00100100
 %00011000
end

Closed_Ship
player0:
%00111100
%01011110
%11101101
%11110011
%11110111
%11110111
%01110110
%00101100
end

Open_Ship
player0:
 %00011000
 %00011000
 %00111100
 %00100100
 %01011010
 %01011010
 %01100110
 %11111111
 %11100111
 %11000011
end
return otherbank

Mellon_a rem **********************Weapons fired at Space Harrier**********************
player0:
%00000000
%00000000
%01111110
%11111111
%11111111
%01111110
%00000000
%00000000
end

Mellon_b
player0:
%01100000
%11110000
%11111000
%01111100
%00111110
%00011111
%00001111
%00000110
end 

Mellon_c
player0:
%00011000
%00111100
%00111100
%00111100
%00111100
%00111100
%00111100
%00011000
end

Mellon_d
player0:
%00000110
%00001111
%00011111
%00111110
%01111100
%11111000
%11110000
%01100000
end

Blade_a
player0:
%00000000
%00000000
%00011001
%10100111
%11100101
%10011000
%00001000
%00011100
end

Blade_b
player0:
%00100000
%01000000
%10111000
%00100100
%00100100
%10111101
%01000010
%00100100
end

Blade_c
player0:
%00011100
%00001000
%10011000
%11100100
%10100100
%00011000
%00010000
%00111000
end

Blade_d
player0:
%00100100
%01000010
%10111101
%00100100
%00100100
%10111000
%01000000
%00100000
end

Blade_e
player0:
%00011100
%00001000
%10011000
%11100101
%10100111
%00011001
%00000000
%00000000
end

Blade_f
player0:
%00100100
%01000010
%10111101
%00100100
%00100100
%00011101
%00000010
%00000100
end

Blade_g
player0:
%00111000
%00010000
%00011000
%00100101
%00100111
%00011001
%00010000
%00111000
end

Blade_h
player0:
%00000100
%00000010
%00011101
%00100100
%00100100
%10111101
%01000010
%00100100
end

Fireball_a
player0:
%00111100
%01000010
%11111111
%11111111
%11111111
%11111111
%01111110
%00111100
end

Fireball_b
player0:
%00111100
%00111100
%11000011
%11111111
%11111111
%11111111
%01111110
%00111100
end

Fireball_c
player0:
%00111100
%01111110
%10111101
%11000011
%11111111
%11111111
%01111110
%00111100
end

Fireball_d
player0:
%00111100
%01111110
%01111110
%10111101
%11000011
%11111111
%01111110
%00111100
end

Fireball_e
player0:
%00111100
%01111110
%11111111
%01111110
%10111101
%11000011
%01111110
%00111100
end

Fireball_f
player0:
%00111100
%01111110
%11111111
%11111111
%01111110
%10111101
%01000010
%00111100
end

Fireball_g
player0:
%00111100
%01111110
%11111111
%11111111
%11111111
%01111110
%00111100
%00000000
end

Fireball_h
player0:
%00111100
%01111110
%11111111
%11111111
%11111111
%11111111
%01111110
%00111100
end

data LoPointer
$a6
end
data HiPointer
$f5
end
data Height
$12
end

Test
player4pointerlo=LoPointer[0]: player4pointerhi=HiPointer[0]: player4height=Height[0]
player4x=70: player4y=70: COLUP4=10
el
drawscreen: goto el

Link to comment
Share on other sites

Dang! I could have sworn that I deleted all of them.

 

Hmmm....A sprite appears, but it's missing it's bottom half, and there's a shape above its head.

Oh, nevermind. I recompiled and checked out the list file, and removing those return otherbanks changed the location of the sprites a little. Although changing the lo pointer to its new value $a0 draws most of the sprite, except for the top of its head. But changing the height to $14 fixed that.

 

Well, I think I can figure out the rest from here. Thank you for all your help.

Link to comment
Share on other sites

Dang! I could have sworn that I deleted all of them.

 

Hmmm....A sprite appears, but it's missing it's bottom half, and there's a shape above its head.

Oh, nevermind. I recompiled and checked out the list file, and removing those return otherbanks changed the location of the sprites a little. Although changing the lo pointer to its new value $a0 draws most of the sprite, except for the top of its head. But changing the height to $14 fixed that.

 

Well, I think I can figure out the rest from here. Thank you for all your help.

Also remember that your sprite data can be longer than what you had in that test program. For example, this was the sprite data used for Tone Toy 2008:

 

  player0:
 %00001110
 %00001010
 %00001010
 %00001010
 %00001110
 %00000000
 %00000010
 %00000010
 %00000010
 %00000010
 %00000010
 %00000000
 %00001110
 %00001000
 %00001110
 %00000010
 %00001110
 %00000000
 %00001110
 %00000010
 %00000110
 %00000010
 %00001110
 %00000000
 %00000010
 %00000010
 %00001110
 %00001010
 %00001010
 %00000000
 %00001110
 %00000010
 %00001110
 %00001000
 %00001110
 %00000000
 %00001110
 %00001010
 %00001110
 %00001000
 %00001110
 %00000000
 %00000010
 %00000010
 %00000010
 %00000010
 %00001110
 %00000000
 %00001110
 %00001010
 %00001110
 %00001010
 %00001110
 %00000000
 %00000010
 %00000010
 %00001110
 %00001010
 %00001110
 %00000000
 %00101110
 %00101010
 %00101010
 %00101010
 %00101110
 %00000000
 %00001010
 %00001010
 %00001010
 %00001010
 %00001010
 %00000000
 %00101110
 %00101000
 %00101110
 %00100010
 %00101110
 %00000000
 %00101110
 %00100010
 %00100110
 %00100010
 %00101110
 %00000000
 %00100010
 %00100010
 %00101110
 %00101010
 %00101010
 %00000000
 %00101110
 %00100010
 %00101110
 %00101000
 %00101110
 %00000000
 %00101110
 %00101010
 %00101110
 %00101000
 %00101110
 %00000000
 %00100010
 %00100010
 %00100010
 %00100010
 %00101110
 %00000000
 %00101110
 %00101010
 %00101110
 %00101010
 %00101110
 %00000000
 %00100010
 %00100010
 %00101110
 %00101010
 %00101110
 %00000000
 %11101110
 %10001010
 %11101010
 %00101010
 %11101110
 %00000000
 %00111010
 %00100010
 %00111010
 %00001010
 %00111010
 %00000000
 %11101110
 %10001000
 %11101110
 %00100010
 %11101110
 %00000000
 %11101110
 %10000010
 %11100110
 %00100010
 %11101110
 %00000000
 %11100010
 %10000010
 %11101110
 %00101010
 %11101010
 %00000000
 %11101110
 %10000010
 %11101110
 %00101000
 %11101110
 %00000000
 %11101110
 %10001010
 %11101110
 %00101000
 %11101110
end
 player0:
 %11100010
 %10000010
 %11100010
 %00100010
 %11101110
 %00000000
 %11101110
 %10001010
 %11101110
 %00101010
 %11101110
 %00000000
 %11100010
 %10000010
 %11101110
 %00101010
 %11101110
 %00000000
 %11101110
 %00101010
 %01101010
 %00101010
 %11101110
 %00000000
 %00111010
 %00001010
 %00011010
 %00001010
 %00111010
end

Edited by Random Terrain
Link to comment
Share on other sites

Thanks. The playfield would look a lot nicer if pfcolors was allowed. Also, I'm not crazy about having my sprite transparent, but so far it's only way I can have all the details that I want. But at least the enemy sprites and sprites of the weapons they shoot at you look OK.

 

Anyway, I'm going to have to start from scratch again, but thanks to Random Terrain's help, writing this game should be a whole lot easier.

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