Jump to content
IGNORED

Space Invader (Armada) player defenses


fsuinnc

Recommended Posts

So, Hypothetically ?, if someone was wanting to make a Space Armada type game using IntyBASIC, how would you make the little defensive barriers the player can hide behind?  How do you make just part of it disappear when a bullet hits it from top or bottom? I'm a little confused how you put a block there then take just some of it away.

 

 

Link to comment
Share on other sites

6 minutes ago, fsuinnc said:

So, Hypothetically ?, if someone was wanting to make a Space Armada type game using IntyBASIC, how would you make the little defensive barriers the player can hide behind?  How do you make just part of it disappear when a bullet hits it from top or bottom? I'm a little confused how you put a block there then take just some of it away.

 

 

The way I would do it, would be in the same way character animations are done:  replacing the graphics card with a different one that is missing pixels.

 

Think of those barriers as being animated, only that the next animation frame comes not at regular intervals, but when hit by a bullet.

Link to comment
Share on other sites

2 minutes ago, DZ-Jay said:

The way I would do it, would be in the same way character animations are done:  replacing the graphics card with a different one that is missing pixels.

 

Think of those barriers as being animated, only that the next animation frame comes not at regular intervals, but when hit by a bullet.

Thanks. That's what I was thinking.  It just seems like the barriers are about 16 pixels wide and it takes 5 or 6 shots to get through them.  That seems like a lot of animation frames and a lot of tracking to know which one to display.  It seems like you would adjust a gram on the fly maybe but tracking that burns a lot of variables.

Link to comment
Share on other sites

16 minutes ago, fsuinnc said:

Thanks. That's what I was thinking.  It just seems like the barriers are about 16 pixels wide and it takes 5 or 6 shots to get through them.  That seems like a lot of animation frames and a lot of tracking to know which one to display.  It seems like you would adjust a gram on the fly maybe but tracking that burns a lot of variables.

Hmmm ... usually you don't necessarily track a specific pixel where the bullet hit, but a region.

 

If the barriers are 16 pixels wide, that would take 2 cards.  You just create a single animation sequence of one card getting destroyed, a few pixels at a time.  This sequence can be used for both sides.

 

You then track the current state of each card independently.  That's two variables.

 

For it to work, you need to test for collisions of each side individually.

 

For example, suppose you decompose the destruction of each barrier side into 4 steps.  That's four animation cards.  You then have a variable to track the state of each side.  They both start at 4 = full.

 

When the left one gets hit, you decrement it's state and update its graphics card using the new state value as an index.  If it gets hit again, you do it all again.  You continue doing this until the state reaches zero, and the barrier is no longer there and therefore you don't need to react to collisions anymore.

 

If at any point the right side gets hit, you do exactly the same thing but using its own variable and graphics card.

 

In that way, both can be destroyed independently of each other, but because they are side-by-side, they give the illusion of the barrier collapsing.

 

That's the theory anyway. :)

Edited by DZ-Jay
Link to comment
Share on other sites

20 minutes ago, DZ-Jay said:

Hmmm ... usually you don't necessarily track a specific pixel where the bullet hit, but a region.

 

If the barriers are 16 pixels wide, that would take 2 cards.  You just create a single animation sequence of one card getting destroyed, a few pixels at a time.  This sequence can be used for both sides.

 

You then track the current state of each card independently.  That's two variables.

 

For it to work, you need to test for collisions of each side individually.

 

For example, suppose you decompose the destruction of each barrier side into 4 steps.  That's four animation cards.  You then have a variable to track the state of each side.  They both start at 4 = full.

 

When the left one gets hit, you decrement it's state and update its graphics card using the new state value as an index.  If it gets hit again, you do it all again.  You continue doing this until the state reaches zero, and the barrier is no longer there and therefore you don't need to react to collisions anymore.

 

If at any point the right side gets hit, you do exactly the same thing but using its own variable and graphics card.

 

In that way, both can be destroyed independently of each other, but because they are side-by-side, they give the illusion of the barrier collapsing.

 

That's the theory anyway. :)

I think I get what your saying (though maybe not).  In the case of these barriers there isn't a set way for the destruction to happen.  If a single 8X8 card is used and we say it has 4 4x4 sections and each hit removes one section, the sections can be hit in any order so the destructions animation needs (I think) 16 frames to cover the possibilities but still doable.  (as usual) Your explanation and knowledge is much appreciated.

 

 

 

Link to comment
Share on other sites

On 2/7/2021 at 6:06 PM, fsuinnc said:

I think I get what your saying (though maybe not).  In the case of these barriers there isn't a set way for the destruction to happen.  If a single 8X8 card is used and we say it has 4 4x4 sections and each hit removes one section, the sections can be hit in any order so the destructions animation needs (I think) 16 frames to cover the possibilities but still doable.  (as usual) Your explanation and knowledge is much appreciated.

 

 

 

Well, that's one way of doing it.  What I am suggesting is that you do not have to complicate it that much.  That it should be fine to just detect a collision within the entire 8 pixel wide card and take a chunk out of the barrier.  I've seen it done like that in other games, like the mushrooms in Centepede.

 

In that game, the mushrooms are depleted a few pixels at a time on every shot.  However, if you pay attention, the mushrooms always lose a little from the left side, then a little from the right side, then a bit of the center, and so on.  On every shot, pixels are removed in exactly the same sequence, irrespective of where in the mushroom the bullet collided.  It's like an animation sequence advanced after each collision.

 

A similar technique could be applied for the bunkers.

 

All that said, I just took a look at a gameplay video of Space Armada and see that they actually take a pixel off where the shot it.  So, if you want to replicate this, you'll probably need to update the card by computing the position of the hit and taking a pixel off from the GRAM card itself.

 

That should be doable.  You will have to convert the screen coordinate of the collision point, into the corresponding pixel within the GRAM card underneath.  Not trivial, but not too hard either.

 

There are various assumptions you can make.  The X and Y coordinates for each barrier card is known to you (they do not move, or if you move them to counter scrolling, adjusting them is trivial).  The GRAM cards used are of a specific size, so you know the exact places where they will be hit.  Hits always come from the top or the bottom, never in the middle.  Etc.

 

    dZ.

Edited by DZ-Jay
Link to comment
Share on other sites

So, essentially reserving a few gram cards for bunkers and treating them as a bitmap.  Since only one pixel gets changed is it possible to write to a single gram byte rather than update the whole card?

 

The bunkers in space armada look like the are made up of three sprites, double width, so only three gram cards are used.

Link to comment
Share on other sites

10 minutes ago, mr_me said:

So, essentially reserving a few gram cards for bunkers and treating them as a bitmap.

That's what I was thinking.

 

Quote

Since only one pixel gets changed is it possible to write to a single gram byte rather than update the whole card?

No, you cannot update a single pixel in GRAM, but you can update the byte it's in.  A GRAM card is stored as eight consecutive bytes in 8-bit RAM.  Each byte represents a row in the card.

 

In IntyBASIC, you could do that with a POKE statement rather than the DEFINE statement.

 

The way I would do it is to keep a sort of map of the bits in a buffer for each bunker, update it there, then compute the pixel and its byte position in GRAM and POKE it.

 

Alternatively, if you are using hardware collision detection, you could use the position of the bullet to compute the same.  However, you will then have to retrieve the GRAM card first in order to know the makeup of the surrounding pixels.

 

Quote

The bunkers in space armada look like the are made up of three sprites, double width, so only three gram cards are used.

That's good!  Then you only need a buffer for each card.

 

   -dZ.

Edited by DZ-Jay
Link to comment
Share on other sites

Yes, someone (me??? not sure if this is someone else's work or not) plotted a sinus curve 5 years ago.

  include "contrib/constants.bas"

  MODE 1

  REM Macro to read GRAM memory which begins at $3800
  DEF FN gramadr(x,y,r) = $3800+x*8+y*128+r

  REM Set up screen full of GRAM characters + clear GRAM memory
  FOR py=0 TO 3:FOR px=0 TO 15
    #BACKTAB(py*20+px)=((py*16)+px)*8+7+GRAM
    DEFINE py*16+px,1,blank:WAIT
  NEXT px:NEXT py

  FOR px=0 TO 127
   py=16+sinval(px%32)
   #adr=gramadr(px/8,py/8,py%8)
   POKE #adr,PEEK(#adr) OR bitval(px%8):WAIT
  NEXT px

loop:
  GOTO loop

bitval:
  data 128,64,32,16,8,4,2,1 : REM Helper data to find out bit value

sinval:
  data 0,3,6,8,11,13,14,15,15,15,14,13,11,8,6,3
  data 0,-3,-6,-8,-11,-13,-14,-15,-15,-15,-14,-13,-11,-8,-6,-3

blank:
  BITMAP "........"
  BITMAP "........"
  BITMAP "........"
  BITMAP "........"
  BITMAP "........"
  BITMAP "........"
  BITMAP "........"
  BITMAP "........"

Link to comment
Share on other sites

3 minutes ago, carlsson said:

Yes, someone (me??? not sure if this is someone else's work or not) plotted a sinus curve 5 years ago.

 

  Hide contents

 



  include "contrib/constants.bas"

  MODE 1

  REM Macro to read GRAM memory which begins at $3800
  DEF FN gramadr(x,y,r) = $3800+x*8+y*128+r

  REM Set up screen full of GRAM characters + clear GRAM memory
  FOR py=0 TO 3:FOR px=0 TO 15
    #BACKTAB(py*20+px)=((py*16)+px)*8+7+GRAM
    DEFINE py*16+px,1,blank:WAIT
  NEXT px:NEXT py

  FOR px=0 TO 127
   py=16+sinval(px%32)
   #adr=gramadr(px/8,py/8,py%8)
   POKE #adr,PEEK(#adr) OR bitval(px%8):WAIT
  NEXT px

loop:
  GOTO loop

bitval:
  data 128,64,32,16,8,4,2,1 : REM Helper data to find out bit value

sinval:
  data 0,3,6,8,11,13,14,15,15,15,14,13,11,8,6,3
  data 0,-3,-6,-8,-11,-13,-14,-15,-15,-15,-14,-13,-11,-8,-6,-3

blank:
  BITMAP "........"
  BITMAP "........"
  BITMAP "........"
  BITMAP "........"
  BITMAP "........"
  BITMAP "........"
  BITMAP "........"
  BITMAP "........"

 

 

Neat-o! :)

Link to comment
Share on other sites

By the way, that generalizes the use of the GRAM card as a bitmap nicely, but still updates it as a whole card.

 

If the bunker is constrained to a single collision at a time (which seems to me a reasonable assumption), only one bit will be removed per collision, so updating a single byte at that point with a POKE is feasible.

 

   -dZ.

Link to comment
Share on other sites

I know that Space Armada uses sprites for the three bunkers.  The other sprites are: your gun, your shot, two enemy shots, and either a third enemy shot or the UFO.  The armada itself is rendered as background objects.

 

That means collision between your shot and the foreground indicates you hit an enemy.  Then it's just software calculations to determine which enemy was hit.

 

I think there is dedicated GRAM scratch space to appropriately shape the three bunkers as they are chipped away.  I hope that helps somehow.

Link to comment
Share on other sites

13 minutes ago, Zendocon said:

I know that Space Armada uses sprites for the three bunkers.  The other sprites are: your gun, your shot, two enemy shots, and either a third enemy shot or the UFO.  The armada itself is rendered as background objects.

Yes, that's how the implement the moving hordes of enemies: scrolling them in the background left and right.  Then the bunkers, player, and bullet sprites are adjusted to stay in place.

 

13 minutes ago, Zendocon said:

That means collision between your shot and the foreground indicates you hit an enemy.  Then it's just software calculations to determine which enemy was hit.

 

I think there is dedicated GRAM scratch space to appropriately shape the three bunkers as they are chipped away.  I hope that helps somehow.

Yes, that's what I thought and what I recommended, except instead of using "GRAM scratch space," to do it in a buffer outside GRAM, so that they can be updated outside the VBLANK critical path, and block-copied in one go.

 

     -dZ.

  • Like 1
Link to comment
Share on other sites

5 hours ago, Zendocon said:

I know that Space Armada uses sprites for the three bunkers.  The other sprites are: your gun, your shot, two enemy shots, and either a third enemy shot or the UFO.  The armada itself is rendered as background objects.

 

That means collision between your shot and the foreground indicates you hit an enemy.  Then it's just software calculations to determine which enemy was hit.

 

I think there is dedicated GRAM scratch space to appropriately shape the three bunkers as they are chipped away.  I hope that helps somehow.

So, I'm basically trying to make a space armada kind of game.  I know it's not groundbreaking but seemed fun.  I really like the discussion here, and like the Sine curve program, but even with the code I don't understand it.  (I haven't looked very long and I think I get what's it's doing but really don't get it in detail). 

 

but, for my space conqueror game the bad guys are scrolling across the screen and I'm pretty sure they are part of the background but I am trouble registering my bullets hitting the background. There is literally nothing on the screen that is not color 0 (black) except the bad guys but if I check for COL1 = HIT_BACKGROUND it registers a hit as soon as I fire. If I make sure the Y coordinate such that the bullet has cleared the gun it still seems to hit the background by hitting nothing. SC_vid2.gif.3fbfbec868051c0b9db56de5242bb227.gif

 

 

 

 

 

 

 

 

 

I'm stealing some of the code from Oscar's book if the gun looks familiar it's from the Raiders program. but even with the book I don't understand "IF COL1 AND $00FC THEN".  I know how to convert hex to decimal just not always sure where all the parts come from.  


also, is there a dummies guide to PEEK and POKE somewhere?  Is Poke or back tab faster/better than Print because I'm scrolling 36 spaceships using print statements.

 

Edited by fsuinnc
  • Like 1
Link to comment
Share on other sites

2 hours ago, fsuinnc said:

So, I'm basically trying to make a space armada kind of game.  I know it's not groundbreaking but seemed fun.  I really like the discussion here, and like the Sine curve program, but even with the code I don't understand it.  (I haven't looked very long and I think I get what's it's doing but really don't get it in detail). 

 

but, for my space conqueror game the bad guys are scrolling across the screen and I'm pretty sure they are part of the background but I am trouble registering my bullets hitting the background. There is literally nothing on the screen that is not color 0 (black) except the bad guys but if I check for COL1 = HIT_BACKGROUND it registers a hit as soon as I fire. If I make sure the Y coordinate such that the bullet has cleared the gun it still seems to hit the background by hitting nothing. SC_vid2.gif.3fbfbec868051c0b9db56de5242bb227.gif

 

 

 

 

 

 

 

 

 

I'm stealing some of the code from Oscar's book if the gun looks familiar it's from the Raiders program. but even with the book I don't understand "IF COL1 AND $00FC THEN".  I know how to convert hex to decimal just not always sure where all the parts come from. 


also, is there a dummies guide to PEEK and POKE somewhere?  Is Poke or back tab faster/better than Print because I'm scrolling 36 spaceships using print statements.

 

Your sprite for the bullet should be deactivated by using (for example) SPRITE 1,0 (supposing your bullet is the sprite 1)

 

If you are using any idiom where the first parameter contains $0300, it means it is checked for collisions, so when you enable it, it already made collision with its current X/Y position.

 

Now the syntax for checking collision against background should be IF COL1 AND $0100 THEN because the background is the bit 8 of each collisiion. Remember each sprite has its own collision register COL0-COL7 and can check for collision against each other sprite. I've repeated this table before:

 

$0001 = Against sprite 0

$0002 = Against sprite 1

$0004 = Against sprite 2

$0008 = Against sprite 3

$0010 = Against sprite 4

$0020 = Against sprite 5

$0040 = Against sprite 6

$0080 = Against sprite 7

$0100 = Against background (any pixel set to 1)

 

To get combinations you add up these values, so $00fc means collision against sprites 2-7.

 

PEEK and POKE can be used to access the screen, and it is the same speed as using #backtab for read and write, BUT IT IS MORE DIFFICULT TO READ. Personally I always use #backtab(c) = #d to write the screen, and #d = #backtab(c) to read from the screen.

 

PRINT on the other hand preserves the cursor position, so it is slower and very noticeable when updating big parts of the screen.

 

IMHO, I would use pre-shifted space invaders in 2px steps (7 GRAM for each one), and if you give a look to the original space invaders, only one invader is updated for each video frame!!!

 

Ok, I got lenghty!!!  ?

Link to comment
Share on other sites

19 hours ago, nanochess said:

Your sprite for the bullet should be deactivated by using (for example) SPRITE 1,0 (supposing your bullet is the sprite 1)

 

If you are using any idiom where the first parameter contains $0300, it means it is checked for collisions, so when you enable it, it already made collision with its current X/Y position.

 

Now the syntax for checking collision against background should be IF COL1 AND $0100 THEN because the background is the bit 8 of each collisiion. Remember each sprite has its own collision register COL0-COL7 and can check for collision against each other sprite. I've repeated this table before:

 

$0001 = Against sprite 0

$0002 = Against sprite 1

$0004 = Against sprite 2

$0008 = Against sprite 3

$0010 = Against sprite 4

$0020 = Against sprite 5

$0040 = Against sprite 6

$0080 = Against sprite 7

$0100 = Against background (any pixel set to 1)

 

To get combinations you add up these values, so $00fc means collision against sprites 2-7.

 

PEEK and POKE can be used to access the screen, and it is the same speed as using #backtab for read and write, BUT IT IS MORE DIFFICULT TO READ. Personally I always use #backtab(c) = #d to write the screen, and #d = #backtab(c) to read from the screen.

 

PRINT on the other hand preserves the cursor position, so it is slower and very noticeable when updating big parts of the screen.

 

IMHO, I would use pre-shifted space invaders in 2px steps (7 GRAM for each one), and if you give a look to the original space invaders, only one invader is updated for each video frame!!!

 

Ok, I got lenghty!!!  ?

Thanks. I'm not sure why I was thinking COL1 = HIT_BACKGROUND instead of COL1 AND HIT_BACKGROUND. fixed that issue.

I currently have like 16 GRAM for each of the two ships as they scroll across two screen positions so I guess I could cut that in half to speed things along (If I understand you correctly). I don't think I've ever used #backtab but will give a try. I definitely need the invaders to move faster. I hadn't considered moving a single invader each frame though it seems to make sense. I'm currently running in a big loop through all 36 aliens and it definitely bogs down if something else tries to happen (like a player shot). 

 

not too lengthy at all.

 

OK, I have the #backtab working. (not that it was difficult). However, I don't understand how to update just one invader each video frame (as Oscar referenced).

I mean I'm guessing this is related to the "On Frame" and 60 frames per second (NTSC). 

Currently I have a "For A = 0 to 35" loop and for each of the 36 aliens it gets the position, color and direction and anim frame, updates the screen, and then updates positions and checks to see if they have reached the end of row, etc. This takes a lot of time and bogs everything down.  How do I set things up so that the processing is in sync (as much as it can be) with the frames? I know that seems like a pretty basic question but I think (as an old Top down business programmer) I just have a problem visualizing how the program is running along and then 60 times a second it jumps from where ever it is to a particular procedure and then comes back and proceeds where it left off. If that is what happens then how do I keep track of where I am?

 

 

 

Edited by fsuinnc
update
  • Like 1
Link to comment
Share on other sites

13 hours ago, fsuinnc said:

OK, I have the #backtab working. (not that it was difficult). However, I don't understand how to update just one invader each video frame (as Oscar referenced).

I mean I'm guessing this is related to the "On Frame" and 60 frames per second (NTSC). 

Currently I have a "For A = 0 to 35" loop and for each of the 36 aliens it gets the position, color and direction and anim frame, updates the screen, and then updates positions and checks to see if they have reached the end of row, etc. This takes a lot of time and bogs everything down.  How do I set things up so that the processing is in sync (as much as it can be) with the frames? I know that seems like a pretty basic question but I think (as an old Top down business programmer) I just have a problem visualizing how the program is running along and then 60 times a second it jumps from where ever it is to a particular procedure and then comes back and proceeds where it left off. If that is what happens then how do I keep track of where I am?

 

 

 

You don't need to use ON FRAME to keep track of which invader to move.

 

The basic pseudocode for this game looks like this:

 

game_loop:

          GOSUB update_sprites

          WAIT

           GOSUB move_invader

           GOSUB move_invader_bullet

           GOSUB move_player_bullet

           GOSUB move_player

          GOTO game_loop

 

Now for the move_invader procedure it is a global variable next_invader containing the number of the next invader to move, and you need to keep an array for all the invaders telling if the invaders is alive or dead.

 

For example:

 

       c = 0

       DO

            next_invader = next_invader + 1

            c = c + 1

       LOOP WHILE invader_alive(next_invader) = 0 AND c < 36

 

It increases the next_invader variable until an alive invader is found, or stops if the invaders array is empty (all killed then c = 36)

 

Now because all invaders are aligned in a rectangle, you can get the x, y coordinate of the invader based on the top left of the rectangle.

 

         x = rectangle_x + next_invader % 6 * 2     ' Suppose the invaders are spaced by 2 cards

         y = rectangle_y + next_invader / 6 * 1     ' Suppose the invaders are one for each row.

 

The rectangle_x and rectangle_y position is moved when all invaders have been displaced in the same direction. The direction changes when one invaders touches the side of the screen, but the change shouldn't be done until all invaders are moved (otherwise the invaders array would disalign).

 

Use a notebook to illustrate the conditions that are required by the invaders to move, and keep track of variables. It will make it easier to implement.

 

 

 

 

Link to comment
Share on other sites

10 hours ago, nanochess said:

 

You don't need to use ON FRAME to keep track of which invader to move.

 

The basic pseudocode for this game looks like this:

 

game_loop:

          GOSUB update_sprites

          WAIT

           GOSUB move_invader

           GOSUB move_invader_bullet

           GOSUB move_player_bullet

           GOSUB move_player

          GOTO game_loop

 

Now for the move_invader procedure it is a global variable next_invader containing the number of the next invader to move, and you need to keep an array for all the invaders telling if the invaders is alive or dead.

 

For example:

 

       c = 0

       DO

            next_invader = next_invader + 1

            c = c + 1

       LOOP WHILE invader_alive(next_invader) = 0 AND c < 36

 

It increases the next_invader variable until an alive invader is found, or stops if the invaders array is empty (all killed then c = 36)

 

Now because all invaders are aligned in a rectangle, you can get the x, y coordinate of the invader based on the top left of the rectangle.

 

         x = rectangle_x + next_invader % 6 * 2     ' Suppose the invaders are spaced by 2 cards

         y = rectangle_y + next_invader / 6 * 1     ' Suppose the invaders are one for each row.

 

The rectangle_x and rectangle_y position is moved when all invaders have been displaced in the same direction. The direction changes when one invaders touches the side of the screen, but the change shouldn't be done until all invaders are moved (otherwise the invaders array would disalign).

 

Use a notebook to illustrate the conditions that are required by the invaders to move, and keep track of variables. It will make it easier to implement.

 

 

 

 

Thanks for the great (and simple) explanation.  I think I have covered most of what you mention with the important exception of the basic game_loop.  I will be rearranging some things in my code and hope I can get things working.  Whether I succeed or not, I still enjoy trying very much so thanks again for IntyBASIC!

  • Like 1
Link to comment
Share on other sites

On 2/12/2021 at 2:37 PM, DZ-Jay said:

Yes, that's how the implement the moving hordes of enemies: scrolling them in the background left and right.  Then the bunkers, player, and bullet sprites are adjusted to stay in place.

 

Yes, that's what I thought and what I recommended, except instead of using "GRAM scratch space," to do it in a buffer outside GRAM, so that they can be updated outside the VBLANK critical path, and block-copied in one go.

 

     -dZ.

so glad I read this thread.

 

this is why I was stuck on my game.  I was also working on a Space Armada clone and had no idea how to generate the armada itself.  I tihnk I need to work on a lot of smaller programs to learn how to do specific things before I tackle a complete game.

Edited by Mik's Arcade
Link to comment
Share on other sites

35 minutes ago, Mik's Arcade said:

so glad I read this thread.

 

this is why I was stuck on my game.  I was also working on a Space Armada clone and had no idea how to generate the armada itself.  I tihnk I need to work on a lot of smaller programs to learn how to do specific things before I tackle a complete game.

By all means, if you need it, ask for help in this forum.  There are lots of people willing to lend a hand. :)
 

  dZ.

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