Jump to content
IGNORED

Another rookie question - what card am I on?


Mik's Arcade

Recommended Posts

Hey all -

 

This is going to be an easy question, I just know it.

 

I want to know what CARD I am sitting on when a collision between two spites.  Depending on the offset, I know it will be somewhere within an 8x8 pixel range of a card

 

On a funny note, I spent an hour the other night doing just the OPPOSITE. It is easy plot out table the X and Y coordinate of a spite by CARD.

 

IE, CARD 104 is located on row 5, column 4

X = 8 * column = 32

Y = 8 * row =40

I know this is basic stuff to the pros...lol.

 

Now I want the reverse!  how can I turn (sprite1x,sprite1y)  collides with (sprite2x,sprite2y) into the card number this lovely event occurs?

 

Is this what the peek or poke command is for? I've searched around topics and looked in Oscar's books....boy I wish his books had an index reference at the end

 

Link to comment
Share on other sites

It looks like these functions in the CONSTANTS.BAS help with this problem...

 

DEF FN screenpos(aColumn, aRow)                =               (((aRow)*BACKGROUND_COLUMNS)+(aColumn))
DEF FN screenaddr(aColumn, aRow)            = (BACKTAB_ADDR+(((aRow)*BACKGROUND_COLUMNS)+(aColumn)))
 

 

So, somehow I must be able to reverse engineer the address of the background table from where the 2 sprites collide.  Grr...I hate being on the tip of figuring something out but still missing that one critical piece....

 

so, the address for card 104 would be $0200 + 5 * 20 + 4 = $0304?

 

Either way, this doesn't solve my actual problem...lol

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

Both sprites are approximately at the same card number.

 

So let us say we use only one as reference  If this is an 8x8 sprite, we need to add 4 to each coordinate to get the center.

 

Column = (sprite_x + 4) / 8

Row = (sprite_y + 4) / 8

Card = row * 20 + column

 

Edited by nanochess
Link to comment
Share on other sites

12 hours ago, Mik's Arcade said:

Hey all -

 

This is going to be an easy question, I just know it.

 

I want to know what CARD I am sitting on when a collision between two spites.  Depending on the offset, I know it will be somewhere within an 8x8 pixel range of a card

Do you have the Advanced Game Programming book from @nanochess?  I have a block of code on page 279 to do just that.  My code goes a little further though, because it was for a game that uses Colored Squares graphics mode, and so I wanted to capture not only the card where the collision happened, but the quadrant within that card.  After that, I use a bitmask to determine whether that quadrant contained a black or white square.

 

The second, third, and fourth lines of code in that block are what will matter to you:

Snap = (#ZapperPosX / 256 + 3) AND $f8
Snap2 = ((#ZapperPosY + $80) / 256 + 3) AND $f8
Snap = (Snap2 / 8) * 20 + (Snap / 8) - 21

The final value of Snap is the background card I want.  First, I'll explain a couple things here pertaining to the Zapper.

 

In my game, two people jockey to control a Zapper which is bouncing around the screen and eventually collides with one of seven bouncing gumballs (or "bubbles", as I still called them when the book was written).  The Zapper is sort of crosshair-shaped with a hole in the middle, three pixels offset from the top left of the sprite image (that's why "+3" is in the equations).  It's the color of the background pixel peeking through the Zapper's hole that I have additional code to find out.  See the attached illustration.  The Zapper is silver-colored in 2-player mode.

 

Additionally, I use Mattel-style 8.8 floating-point arithmetic to maintain the position of all the sprites here for "sub-pixel precision", which is why "/256" is in the equations as well.  Finally, I use a technique to simulate double-resolution placement of the Zapper on the Y-axis, which is why "+$80" is in the one equation to calculate Snap2.

 

"AND $f8" is necessary for both equations because we're translating from a pixel location to a background card.  The last line recalculates Snap based on its previous value and the value of Snap2 to give us the final card number.  "-21" is necessary because we need to offset one card up and to the left.

 

In your case, you'll probably need to eliminate "+$80" from the second equation and "/256" from both equations.  As for "+3", you could probably calculate the difference between the X positions of the two objects in collision, and do the same for the Y positions.  That will give you the epicenter of the collision.  Replace "+3" with those calculated values.

DILLIGAS 2-Player.gif

Link to comment
Share on other sites

Yes, I have the book!  I didn't read  the 'tips from the trench' section because I'm still learning the basics...haha.

 

Thanks for the info, I will read up that section and review this post and see if I can get this working.  I guess the answer was not as simple as I thought it would be. Your example is great because I really want to understand and use color squares mode too so I'll get two lessons in one.

 

In my code I,  I just need to plop a predefined bitmap into the card using #backtab where the 2 sprites collide before one sprite gets reset and the other moves off to new location.

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

13 hours ago, nanochess said:

Both sprites are approximately at the same card number.

 

So let us say we use only one as reference  If this is an 8x8 sprite, we need to add 4 to each coordinate to get the center.

 

Column = (sprite_x + 4) / 8

Row = (sprite_y + 4) / 8

Card = row * 20 + column

 

aha!   This might be easier.   I just started making slighty randomized use of columns, rows and cards to move things around a play field, so this is the card math I was missing!!

 

thanks

  • Like 1
Link to comment
Share on other sites

15 hours ago, nanochess said:

Column = (sprite_x + 4) / 8

Row = (sprite_y + 4) / 8

Card = row * 20 + column

I think you need to add "-21" at the end of "Card" to offset by one column and row, since the top left corner would have sprite_x and sprite_y values of 8.  The three lines of code I provided are doing the same thing, but they are accomodating for a few other things, so this is much easier to understand.

Link to comment
Share on other sites

2 hours ago, Zendocon said:

I think you need to add "-21" at the end of "Card" to offset by one column and row, since the top left corner would have sprite_x and sprite_y values of 8.  The three lines of code I provided are doing the same thing, but they are accomodating for a few other things, so this is much easier to understand.

 

Hi there -

 

Yes, this works perfectly.  However, now i have an interesting yet unrelated problem that cropped up even before I put in this new code. I've cut and pasted the code for this entire section of the game below.  (bonus_loop).  Most of the code is tucked away in GOSUB procedures.

 

What seems to be happening is that the code below is that the section:

IF COL6 AND $003F THEN

sometimes executes more than once per loop.  This is why I am checking for chp <= 0 instead of just zero.  I've recycled the collision detection logic from Oscar's book and don't understand it 100%

 

I think the issue has to do with the fact the sprite(s) I use for the enemy take up 2 cards and I also use ZOOMY2 (ie, $0100 ).

 

It is inconsistent. Sometime, I hit the enemy and it drops only 1 hit point and the object on the correct card. (ie, it works correctly)

Other times, 2 hit points are dropped and it drops one object in the correct card, but then another one on the card of the new location that I moved the sprite, which is set as cx = min_x : cy = cy + 4.  Basically, I move the enemy back to left hand side of the play arena and 4 pixels down. (just like in the arcade...lol)

 

I doubt the code executes the entire loop and then comes back and executes the COL6 AND $003F code again.  How could it?   I thought commenting out the SPRITE 0 check would fix this but it still happens.  Sadly, I waste 4 sprites on this one character, but sprites 0 and 2 have most of the actual used bits.

 

Any idea what might be causing this?  I suspect it has to do with the 2 BITMAPS being used plus the ZOOMY2 causing 2 hits, but I still can't see how that would make the code to reduce chp by 1 and also print the backtab happen twice.

 

 

 

 

 

bonus_loop:

 

'' 1-Set Commander up and use weapons

on num_comm gosub disp_comm0, disp_comm1, disp_comm2, disp_comm3, disp_comm4, disp_comm5, disp_comm6
IF throw_star THEN ' Commander is on the attack, move weapon
   on num_comm gosub move_commw0, move_commw1, move_commw2, move_commw3, move_commw4, move_commw5, move_commw6
  ELSE               ' Set conditions on when commander will attack
   on num_comm gosub set_commw0, set_commw1, set_commw2, set_commw3, set_commw4, set_commw5, set_commw6
END IF   
on num_comm gosub disp_commw0, disp_commw1, disp_commw2, disp_commw3, disp_commw4, disp_commw5, disp_commw6
'END IF
'
'' 2-Update Sasuke
'
GOSUB update_sasuke

 

'

'' 3-Collision detection

IF COL6 AND $003F THEN
   c = 255
'   IF COL6 AND HIT_SPRITE0 THEN c = 0
   IF COL6 AND HIT_SPRITE2 THEN c = 2
   IF c = 2 THEN
      sound_effect = 3 : sound_state = 0
      chp = chp - 1
      IF chp <= 0 THEN
        goto yes_bonus
      ELSE
        IF num_comm = 5 THEN
          column = (cx + 4) / 8
          row = (cy + 4) / 8
          card = row * 20 + column - 21
          #backtab(card) = $0802 + 21 * 8

          cs = 2 : cx = min_x : cy = cy + 4 
        END IF
      END IF
   END IF  
END IF

'

' 4-Move commander

on num_comm gosub move_comm0, move_comm1, move_comm2 ,move_comm3, move_comm4, move_comm5, move_comm6
'

5- update timer
GOSUB move_bonus_bar
IF #bonus = 0 THEN     ' Time's up!
  GOTO no_bonus
END IF
'
'' 6-Moving Sasuke  
GOSUB move_sasuke
'

' for testing
PRINT AT 1,<.5>#BONUS
PRINT AT 10,<.5>chp
'
GOTO bonus_loop

 

 

 

 

 

 

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

First, I will recommend to you and everyone to use the "code" formatter when posting code.  It's an icon in the format toolbar that looks like "</>".  It makes it easier to read in monospaced fonts.

bonus_loop:

'' 1-Set Commander up and use weapons
on num_comm gosub disp_comm0, disp_comm1, disp_comm2, disp_comm3, disp_comm4, disp_comm5, disp_comm6
IF throw_star THEN ' Commander is on the attack, move weapon
   on num_comm gosub move_commw0, move_commw1, move_commw2, move_commw3, move_commw4, move_commw5, move_commw6
  ELSE               ' Set conditions on when commander will attack
   on num_comm gosub set_commw0, set_commw1, set_commw2, set_commw3, set_commw4, set_commw5, set_commw6
END IF   
on num_comm gosub disp_commw0, disp_commw1, disp_commw2, disp_commw3, disp_commw4, disp_commw5, disp_commw6
'END IF
'
'' 2-Update Sasuke
'
GOSUB update_sasuke

'
'' 3-Collision detection
IF COL6 AND $003F THEN
   c = 255
'   IF COL6 AND HIT_SPRITE0 THEN c = 0
   IF COL6 AND HIT_SPRITE2 THEN c = 2
   IF c = 2 THEN
      sound_effect = 3 : sound_state = 0
      chp = chp - 1
      IF chp <= 0 THEN
        goto yes_bonus
      ELSE
        IF num_comm = 5 THEN
          column = (cx + 4) / 8
          row = (cy + 4) / 8
          card = row * 20 + column - 21
          #backtab(card) = $0802 + 21 * 8
          cs = 2 : cx = min_x : cy = cy + 4 
        END IF
      END IF
   END IF  
END IF
'
' 4-Move commander
on num_comm gosub move_comm0, move_comm1, move_comm2 ,move_comm3, move_comm4, move_comm5, move_comm6
'
5- update timer
GOSUB move_bonus_bar
IF #bonus = 0 THEN     ' Time's up!
  GOTO no_bonus
END IF
'
'' 6-Moving Sasuke  
GOSUB move_sasuke
'
' for testing
PRINT AT 1,<.5>#BONUS
PRINT AT 10,<.5>chp
'
GOTO bonus_loop


Second, what is the value of "chp" going in?  When is it set, and to what?  I see only that you decrement it and compare, but it does not show what other values it could have outside that.

 

Third, why are you setting "c = 2" only to test "c" for that value right on the very next line?  Why not just do "IF COL6 AND HITSPRITE2 THEN ..." followed by the actual code to handle the event?

 

Finally, regarding the multiple collision triggers, it's hard to determine from your isolated code above, but consider that your sprites may still be touching for longer than one frame or loop iteration.  If you check for collisions on one iteration, and after moving the sprites they are still touching, it will trigger the same collision again on the next iteration.

 

To your game, these are two distinct collisions; to the player, it is the same collision, for the sprites are still colliding from before.

 

You may need to set some sort of semaphore (flag) when sprites collide and only react to a collision when it is not set, which marks the start of a collision event.  You then clear the semaphore when the sprites are not colliding, indicating that they are ready for a new event.

 

If, on the other hand, your multiple collisions are indeed being triggered within the same iteration, then the problem could be in the way you are testing them.  You may not be setting or resetting properly your "c" or "chp" variables.

 

    dZ.

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

2 hours ago, DZ-Jay said:

First, I will recommend to you and everyone to use the "code" formatter when posting code.  It's an icon in the format toolbar that looks like "</>".  It makes it easier to read in monospaced fonts.


bonus_loop:

'' 1-Set Commander up and use weapons
on num_comm gosub disp_comm0, disp_comm1, disp_comm2, disp_comm3, disp_comm4, disp_comm5, disp_comm6
IF throw_star THEN ' Commander is on the attack, move weapon
   on num_comm gosub move_commw0, move_commw1, move_commw2, move_commw3, move_commw4, move_commw5, move_commw6
  ELSE               ' Set conditions on when commander will attack
   on num_comm gosub set_commw0, set_commw1, set_commw2, set_commw3, set_commw4, set_commw5, set_commw6
END IF   
on num_comm gosub disp_commw0, disp_commw1, disp_commw2, disp_commw3, disp_commw4, disp_commw5, disp_commw6
'END IF
'
'' 2-Update Sasuke
'
GOSUB update_sasuke

'
'' 3-Collision detection
IF COL6 AND $003F THEN
   c = 255
'   IF COL6 AND HIT_SPRITE0 THEN c = 0
   IF COL6 AND HIT_SPRITE2 THEN c = 2
   IF c = 2 THEN
      sound_effect = 3 : sound_state = 0
      chp = chp - 1
      IF chp <= 0 THEN
        goto yes_bonus
      ELSE
        IF num_comm = 5 THEN
          column = (cx + 4) / 8
          row = (cy + 4) / 8
          card = row * 20 + column - 21
          #backtab(card) = $0802 + 21 * 8
          cs = 2 : cx = min_x : cy = cy + 4 
        END IF
      END IF
   END IF  
END IF
'
' 4-Move commander
on num_comm gosub move_comm0, move_comm1, move_comm2 ,move_comm3, move_comm4, move_comm5, move_comm6
'
5- update timer
GOSUB move_bonus_bar
IF #bonus = 0 THEN     ' Time's up!
  GOTO no_bonus
END IF
'
'' 6-Moving Sasuke  
GOSUB move_sasuke
'
' for testing
PRINT AT 1,<.5>#BONUS
PRINT AT 10,<.5>chp
'
GOTO bonus_loop


Second, what is the value of "chp" going in?  When is it set, and to what?  I see only that you decrement it and compare, but it does not show what other values it could have outside that.

 

Third, why are you setting "c = 2" only to test "c" for that value right on the very next line?  Why not just do "IF COL6 AND HITSPRITE2 THEN ..." followed by the actual code to handle the event?

 

Finally, regarding the multiple collision triggers, it's hard to determine from your isolated code above, but consider that your sprites may still be touching for longer than one frame or loop iteration.  If you check for collisions on one iteration, and after moving the sprites they are still touching, it will trigger the same collision again on the next iteration.

 

To your game, these are two distinct collisions; to the player, it is the same collision, for the sprites are still colliding from before.

 

You may need to set some sort of semaphore (flag) when sprites collide and only react to a collision when it is not set, which marks the start of a collision event.  You then clear the semaphore when the sprites are not colliding, indicating that they are ready for a new event.

 

If, on the other hand, your multiple collisions are indeed being triggered within the same iteration, then the problem could be in the way you are testing them.  You may not be setting or resetting properly your "c" or "chp" variables.

 

    dZ.

Based on what you and Zendocon posted, I believe the solution is to set and use a flag to mark the START of collision and use to that flag to execute the code.

 

Now I will just answer your other questions for clarity:

 

1) I will use the code formatting moving forward (as long as I remember to!), thanks

2) chp = commander hit points.  I set that to 3 at the start of the battle and you need to hit the dude 3 times to finish him off.  There are 6 boss fights and most of them only need 1 hit, but once they start to repeat I will bump up the number 

3) c = 2.   Yeah, I cannibalized this code from Oscar's "Pumpkin Master game".  There are actually 4 sprites being used per boss (what a waste) so I was originally checking all 4, then figured I only needed to check for 2.  But, to your point, I am going to clean this up. In the main loop of the game this same logic is used to check for 6 different sprites all moving about and it seems to work fine. Perhaps this is the flag logic in action.

4) there is not really a lot of magic on when they collide.  I simply have a bullet decreasing (moving up) along the y-axis with the x-axis a fixed value, and it needs to connect with the commander who is going back and forth along the x-axis with a fixed y-axis value, and they simply need to meet on the y-axis.  There should only be two valid values they meet at for any given time since the sprite takes up two BITMAP.  They start at y = 32 and 40, for example and the bullet always starts on y=88

 

thanks all!

 

 

Link to comment
Share on other sites

1 hour ago, Mik's Arcade said:

Based on what you and Zendocon posted, I believe the solution is to set and use a flag to mark the START of collision and use to that flag to execute the code.

Well ... that's not exactly what I meant.

 

What I recommend is to set a flag to mark that collisions have been (or are being) handled.  In other words, something like this (warning: untested pseudo-code only!):

  ' Check if the sprite collided
  IF (COL6 AND HITSPRITE0) THEN
    ' Check if the collision has been handled already
    ' if so, ignore it.
    IF (COL6_HANDLED = 0) Then
      COL6_HANDLED = 1
      ' do the collision handling here
    END IF

  ' If the sprite is not colliding,
  ' clear the handled flag
  ELSE
   COL6_HANDLED = 0
  END IF

 

That should illustrate the logic, but you may want to alter it to fit your needs.

 

The point is that you only want to handle a collision if it is new.  You could set a flag at the start of a collision to signal that you should handle it; but that sounds like double-checking the condition:  "IF (collision-happened) THEN collision-flag = TRUE" ... "IF (collision-flag = TRUE) THEN handle-collision".

 

Ideally, you would only check the condition once and handle it.  Then the flag just alerts you to ignore a double collision.

 

Quote

Now I will just answer your other questions for clarity:

 

1) I will use the code formatting moving forward (as long as I remember to!), thanks

No worries, it's just helpful, especially when reading on the iPad. :)

 

Quote

2) chp = commander hit points.  I set that to 3 at the start of the battle and you need to hit the dude 3 times to finish him off.  There are 6 boss fights and most of them only need 1 hit, but once they start to repeat I will bump up the number 

Got it.  Consider that -1, -2, -3, etc., are all less than zero.  So, if you continue decrementing "chp" and testing for a negative value, it may continue "killing" the boss, unless you reset the value back to zero.

 

Perhaps you should only test for -1 ...

 

Quote

3) c = 2.   Yeah, I cannibalized this code from Oscar's "Pumpkin Master game".  There are actually 4 sprites being used per boss (what a waste) so I was originally checking all 4, then figured I only needed to check for 2.  But, to your point, I am going to clean this up. In the main loop of the game this same logic is used to check for 6 different sprites all moving about and it seems to work fine. Perhaps this is the flag logic in action.

 

Are the four sprites overlapping directly?  If not, you may want to define your collision region as a bounding box, described by offsets from some of the sprites.

 

If they overlap in the same 8x8 space, then you may only need to check one, the one with the largest surface area.  If you are using hardware collisions, you may need to test multiple sprites to cover the full range of pixels that can collide.  I am not very familiar with your game, so I cannot tell which would be best.

 

 

By the way, I wouldn't consider 4 sprites per boss a waste.  Doesn't it add more detail?  I think that's a good thing. :)

 

 

Quote

4) there is not really a lot of magic on when they collide.  I simply have a bullet decreasing (moving up) along the y-axis with the x-axis a fixed value, and it needs to connect with the commander who is going back and forth along the x-axis with a fixed y-axis value, and they simply need to meet on the y-axis.  There should only be two valid values they meet at for any given time since the sprite takes up two BITMAP.  They start at y = 32 and 40, for example and the bullet always starts on y=88

 

I'm a bit confused.  Sometimes it sounds as if you are using hardware collisions (pixel overlap), and sometimes it sounds like you are using positional collisions (BACKTAB card match), and other times it sounds like you are using bounding box collisions (coordinate comparisons).

 

Or perhaps you are using a mixture of all three, depending on the case?  If so, then perhaps it would help if you specify what you are doing for a given case that's giving you trouble, rather than addressing them as if they were the same.

 

     -dZ.

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

We are probably getting into territory where I don't fully understand how it all works.  The ONLY collision detection code being used is what I lifted from Oscar's pumpkin master

IF COL6 AND $003F THEN

c = 255

'   IF COL6 AND HIT_SPRITE0 THEN c = 0

   IF COL6 AND HIT_SPRITE2 THEN c = 2

I'm not sure what the $003F is really for, and the HIT_SPRITE0 comes from the CONSTANTS.BAS and the value is $0001 which says it indicates that "another sprite" collided with spite 0.  I may just need that.

 

The 6th sprite is obviously the travelling bullet

The enemy commander uses sprites 0-3 and his weapons use 4-5

Originally, I was checking all 4 sprites for collision but sprites 1 and 3 are not needed for a check as 0 and 2 have all the meat.

I'm not checking for card number or when the y-axis values connect, it is literally just the code above.

 

Right now I'm doing a quick review of entire program.  I'm organizing all the fields and putting them into an include file and taking an inventory. I think I can get rid of some that I can recycle from other variables and will probably add a few new ones.  I also have some redundant code that I can remove.  Then I am going to review the entire section on collision and take your 'handled' flag into consideration.  I get where you are going with it and I can hopefully do away with the stuff from Oscar's code I don't get.

 

thanks

Link to comment
Share on other sites

47 minutes ago, Mik's Arcade said:

We are probably getting into territory where I don't fully understand how it all works.

No worries, that's what we're here for.

 

Quote

The ONLY collision detection code being used is what I lifted from Oscar's pumpkin master


IF COL6 AND $003F THEN

c = 255

'   IF COL6 AND HIT_SPRITE0 THEN c = 0

   IF COL6 AND HIT_SPRITE2 THEN c = 2

I'm not sure what the $003F is really for, and the HIT_SPRITE0 comes from the CONSTANTS.BAS and the value is $0001 which says it indicates that "another sprite" collided with spite 0.  I may just need that.

 

Let us break down that code:

  • COL6:  This is an IntyBASIC directive that returns the collision status of Sprite #6.  The collision status is a bit field register, where each bit represents either another sprite, or the background.
  • $003F:  This is a hexadecimal value representing a bit mask -- that is, a set of bits to isolate from a bit field.  In this case, it translates to binary "&00011111," and represents the lower five bits of the COL6 collision status register, or the six sprites (#0 to #5) that come before Sprite #6.
  • IF COL6 AND $003F:  This conditional tests whether the lower five bits of COL6 are set.  In other words, it checks whether Sprite #6 has collided with any of the sprites #0 to #5.
  • c = 255:  By this point we know we have a collision, now we're going to test to what.  So, we start by setting a variable ("c") to an invalid value, in this case 255 is high enough and out of the way.  The idea is that we will set the variable to the number of a sprite that collided, and then check if the value actually changed.
  • HIT_SPRITE0:  This is a constant that represents the collision flag of Sprite #0.  This is the flag that would be set in a sprite's "COLx" collision status register if it collided with Sprite #0.  When it says "another sprite" what it means is that you check the collision status register of any other sprite against HIT_SPRITE0, and it will tell you whether that sprite collided with Sprite #0.

 

Note that Pumpkin Master is checking whether Sprite #6 (player bullet) collided with any of the other 6 sprites (pumpkins).  It checks them all, but only keeps the last one in the list that hit.  The presumption is that only one pumpkin can be hit by the bullet at a time, since pumpkins do not overlap, so only one of those conditions will be true.  It may be cheaper, processing wise, to do it this way, but alternatively, you could have uses IFELSE in all the cases after the first one.

 

At the end, if one of those pumpkins was hit, the code handles the collision.

 

In your case, if you have only one sprite that you need to test against, you do not need to separate the collision test and the event handler; you could just do it in one go without the middle-man variable.

 

 

Quote

The 6th sprite is obviously the travelling bullet

The enemy commander uses sprites 0-3 and his weapons use 4-5

Originally, I was checking all 4 sprites for collision but sprites 1 and 3 are not needed for a check as 0 and 2 have all the meat.

That makes sense:  you only need to test those sprites which cover the collision region with their pixels.

 

However, if I understand correctly, your multiple hardware sprites represent a single logical sprite, thus colliding against any of them is a single event.  This is different from the Pumpkin Master game, in which you need to know which pumpkin was hit.  In your case, any of the sprites colliding means that the one commander has been hit.

 

If so, you can combine all the collisions in one single test:  just adjust the mask in the "IF" statement to test the bits for the sprites of the commander.  This depends on whether you include the two sprites for the weapon in your collision range:

 

   C Register:    Address = $0018 + MOB #

      13   12   11   10    9    8    7    6    5    4    3    2    1    0
    +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
    | ?? | ?? | ?? | ?? |  0 |  0 |  0 |  0 |  1 |  1 |  1 |  1 |  1 |  1 |  = $003F
    |    |    |    |    |BORD| BG |MOB7|MOB6|MOB5|MOB4|MOB3|MOB2|MOB1|MOB0|
    +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
                                               ^    ^    ^    ^    ^    ^
                                               |    |    |    |    |    |
                                               `-----------------------------------> Collision with commander sprites (including weapon).


      13   12   11   10    9    8    7    6    5    4    3    2    1    0
    +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
    | ?? | ?? | ?? | ?? |  0 |  0 |  0 |  0 |  0 |  0 |  1 |  1 |  1 |  1 |  = $000F
    |    |    |    |    |BORD| BG |MOB7|MOB6|MOB5|MOB4|MOB3|MOB2|MOB1|MOB0|
    +----+----+----+----+----+----+----+----+----+----+----+----+----+----+
                                                         ^    ^    ^    ^
                                                         |    |    |    |
                                                         `-------------------------> Collision with commander sprites (excluding weapon).

 

You then test with something like this:

Const COMMANDER_MASK = $000F  ' (or $003F)

IF (COL6 AND COMMANDER_MASK) THEN
  ' The bullet collided with one of the commander sprites.
  ' Handle the collision right here, without further ado.

END IF

 

To avoid doing the math for the mask, you may want to just combine the "HIT_xxx" flags from "Constants.bas," that's what they are there for. ;)

Const COMMANDER_MASK = (HIT_SPRITE0 + HIT_SPRITE1 + HIT_SPRITE2 + HIT_SPRITE3)

 

Quote

I'm not checking for card number or when the y-axis values connect, it is literally just the code above.

Got it.

 

Quote

Right now I'm doing a quick review of entire program.  I'm organizing all the fields and putting them into an include file and taking an inventory. I think I can get rid of some that I can recycle from other variables and will probably add a few new ones.  I also have some redundant code that I can remove.  Then I am going to review the entire section on collision and take your 'handled' flag into consideration.  I get where you are going with it and I can hopefully do away with the stuff from Oscar's code I don't get.

Cool!  Let us know how it goes.  ?

 

     -dZ.

 

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

thanks for the very detailed explanation.   I need a bit of time to digest it, but I really think that:

 

 

Const COMMANDER_MASK = (HIT_SPRITE0 + HIT_SPRITE1 + HIT_SPRITE2 + HIT_SPRITE3)

is going to fix it.  I think I am also starting to get it.  As you point out, in the main loop, I'm testing to see which of the 6 (5 in the final version)  enemies on the screen get hit, but on this bonus loop, I only check for one as all 4 sprites represent one entity.  I need to go study the Intellivision Wiki again, especially the STIC.  I have to get a better handle on this backend stuff and really want to use the F/B and color stack for improved graphics. Chapter 1 and 2 of Oscar's new book is going to help with graphics and sound.

 

great lesson, thanks.

 

On a fun note, I came close to beating to Christmas Carol.  It is a lot of fun to play AND replay.  What tool did you use for very detailed title screen?

  • Like 1
Link to comment
Share on other sites

23 minutes ago, Mik's Arcade said:

thanks for the very detailed explanation.

No worries, it's my pleasure.

 

23 minutes ago, Mik's Arcade said:

I need a bit of time to digest it, but I really think that:

 

Take your time and ask any other questions you may have.

 

23 minutes ago, Mik's Arcade said:

I think I am also starting to get it.  As you point out, in the main loop, I'm testing to see which of the 6 (5 in the final version)  enemies on the screen get hit, but on this bonus loop, I only check for one as all 4 sprites represent one entity.

That makes sense.  But I will say one more thing:  even though all 4 sprites represent a single entity, you may want to see if the bullet collided with any of them, just to make sure every single pixel of the entity is accounted for.

 

Because you are combining the tests into a single one with a mask, it costs you nothing extra to check all of them together.

 

If you find bit-masking confusing, you may want to check out this tutorial I wrote some time ago describing how they work.  It's a bit basic, going through Binary Arithmetic, Boolean Logic, and finally to Bit Masks, but it should provided some context if you need it.

 

 

23 minutes ago, Mik's Arcade said:

I need to go study the Intellivision Wiki again, especially the STIC.  I have to get a better handle on this backend stuff and really want to use the F/B and color stack for improved graphics. Chapter 1 and 2 of Oscar's new book is going to help with graphics and sound.

 

Not really a tutorial, but in the following post I describe in basic terms how the Color Stack works.  It is part of a larger answer to someone's question, but the initial paragraphs should give you an idea of how the Color Stack is handled by the hardware:

 

23 minutes ago, Mik's Arcade said:

On a fun note, I came close to beating to Christmas Carol.  It is a lot of fun to play AND replay.  What tool did you use for very detailed title screen?

 

I did it by hand -- one pixel at a time. ;)

 

In truth, I drew all my scenes in ASCII using dots (".") and hashes ("#"), with some additional symbols denoting colors.  I then wrote a script to "rip" the ASCII file into tiles, identify the unique ones, match any ones from GROM, and generate data.

 

So, how did I draw the Christmas Carol title screen?  I updated the drawing in the ASCII file, sometimes as little as changing one character, then ran a "build" script that would run the tile ripper, then assemble, and run the emulator.  I then took a screenshot and studied it to make sure it looked right.  Then I did it again.

 

Here's a video I made of putting together all the screenshots I took while designing the title screen:

 

     -dZ.

Link to comment
Share on other sites

wow...I watched the screen design video and just don't have your art skills.... I did this this screen pixel by pixel and it's all I got, oh well. I'm going to watch the other videos too. I'm going to go over and see about redoing the 2 game screens and reduce the amount of cards used so I can define some more BITMAPS. The problem with making these entire screen backgrounds is that I have to use MODE 1  and am very limited with the color set otherwise.

 

I tried the commander_mask code and I still have the problem so I will keep digging at it. It's not really a show stopper but it does throw a wrench into just one of the boss fights.

 

I reviewed the code and wrote up a list of variables used and I can most likely do away with a few.  I also reduced the enemy count to 5 on the screen at any time. I now have an extra spite to play with so many I can animate the actual player just a bit.  I also have a lot of code I can delete because I can just recycle existing code. I thought I would need some unique code to handle each of the battles but that was not always the case.

 

I think I am going to spend a couple of hours reading and studying on how to do better graphics and also sound before polishing the game up. I feel confident I can release this to the group before Chritmas.   Not exactly a game in the spirit of Christmas though....haha.  

 

 

 

sasuke.png

Link to comment
Share on other sites

14 hours ago, Mik's Arcade said:

wow...I watched the screen design video and just don't have your art skills....

Thanks.  It's mostly OCD that compels me to persevere -- mostly through trial-and-error -- until it "looks right," whatever that ends up being.  That's why you see in the video a bunch of screenshots where only one or two pixels are changed, then put back, then put again, then moved, etc.  It's sort of like experimental.

 

Quote

I did this this screen pixel by pixel and it's all I got, oh well. I'm going to watch the other videos too. I'm going to go over and see about redoing the 2 game screens and reduce the amount of cards used so I can define some more BITMAPS. The problem with making these entire screen backgrounds is that I have to use MODE 1  and am very limited with the color set otherwise.

Your screen looks fine, and captures the essence of the game, so don't knock yourself down.  Perhaps the moon could use a bit of curvy refinement, but it is still recognizable.

 

Mode #1 is Foreground/Background mode, which should allow for better color flexibility, so I do not think that is your problem.  It does not support the extended GROM characters, which may reduce the GRAM count on your screen, but the scene itself does not seem like it should require all that many GRAM cards.

 

Quote

I tried the commander_mask code and I still have the problem so I will keep digging at it. It's not really a show stopper but it does throw a wrench into just one of the boss fights.

You can always post the code and someone here may be able to help.  Also, what is the exact nature of the problem you are seeing?

 

If you are using the IntyBASIC SDK and you are interested in taking the "Red Pill" into the world of the jzIntv debugger, I can give you some pointers on how to check your variables and see what's going on, with breakpoints and variable watches, etc. ... Mind you, it's all command-line based, and a bit cryptic at first, so do not expect magic.  It is, though, a very powerful tool for troubleshooting.

 

Just let me know.

 

Quote

I reviewed the code and wrote up a list of variables used and I can most likely do away with a few.  I also reduced the enemy count to 5 on the screen at any time. I now have an extra spite to play with so many I can animate the actual player just a bit.

What do you mean?  How does an extra sprite grant you the ability to animate the player?  Couldn't you animate him with the sprites it already has?

 

Quote

I also have a lot of code I can delete because I can just recycle existing code. I thought I would need some unique code to handle each of the battles but that was not always the case.

That's great!  Do not be afraid of subroutines.  From my perspective, I would recommend factoring the game into modular subroutines first, and only replacing them with inline code and GOTOs if and when you hit a performance problem that requires it.

 

Quote

I think I am going to spend a couple of hours reading and studying on how to do better graphics and also sound before polishing the game up. I feel confident I can release this to the group before Chritmas.   Not exactly a game in the spirit of Christmas though....haha.  

One thing that may help, something that works for me, is to try to draw it on paper first -- graphic paper if you have it.  You can then take a picture, put it in a graphics program like Paint.Net or Pixelmator, and play with it until it looks good.  Then rip it with IntyColor and see how it looks in a quick mock-up program.

 

If anything seems out of place, or weird, go back to the graphics program and adjust it.  Then rip it again, lather, rinse, repeat.

 

(I use ASCII because it feeds my slow-and-steady OCD tendencies, but that's not necessarily a good thing!)

 

Another alternative is to ask for help from one of the fabulous resident artists in this community or AtariAge in general.  There are quite a few that have volunteered work or assitance in the past.

 

 

     -dZ.

 

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

In case you were wondering, here's an example of a source file for a scene from Christmas Carol.  This one is for the "Throne Scene," which is just a bunch of presents:

; =============================================================================
; Copyright 2010-2021, James Pujals (DZ-Jay), <dz-game@techunlimited.net>.
; =============================================================================

@@THRONE_SCENE:

; ----------------
; Foreground:
; ----------------
; 0 = Black
; 1 = Dark Green
; 2 = Yellow
; 3 = Orange
; 4 = Purple
; 5 = Red
; 6 = White
; 7 = Light Blue

; ----------------
; Background (Color Stack):
; ----------------
; 0 = Black
; 1 = Dark Green
; 2 = Yellow
; 3 = Purple
GRAM_BLOCK: ThroneScene
COLOR_STK:  C_BLK, C_RED, C_YGR, C_DGR

;:0      :1       :2       :3       :4       :5       :6       :7       :8       :9       :10      :11      :12      :13      :14      :15      :16      :17      :18      :19
:COL=0,0 :COL=0,0 :COL=0,0 :COL=5,0 :COL=5,0 :COL=0,0 :COL=0,0 :COL=0,0 :COL=0,0 :COL=0,0 :COL=0,0 :COL=0,0 :COL=0,0 :COL=0,0 :COL=2,0 :COL=2,0 :COL=0,0 :COL=0,0 :COL=0,0 :COL=0,0 ;
........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ; \
........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ;  |
........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ;  |
........ ........ ........ .......# #....... ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ........ ;  |_ Row #0
........ ........ ........ ......#. .#.##... ........ ........ ........ ........ ........ ........ ........ ........ ........ ....##.. ..###... ........ ........ ........ ........ ;  |
........ ........ ........ ......#. .##..#.. ........ ........ ........ ........ ........ ........ ........ ........ ........ ...#..#. .#...#.. ........ ........ ........ ........ ;  |
........ ........ ........ ..#####. ###..##. ........ ........ ........ ........ ........ ........ ........ ........ ........ ...#...# #....#.. ........ ........ ........ ........ ;  |
........ ........ ........ .#...### #####..# ........ ........ ........ ........ ........ ........ ........ ........ ........ ....#### .#.##... ........ ........ ........ ........ ; /
:COL=0,0 :COL=0,0 :COL=0,0 :COL=2,1 :COL=2,0 :COL=0,1 :COL=0,1 :COL=0,0 :COL=0,1 :COL=7,0 :COL=7,0 :COL=7,0 :COL=0,1 :COL=0,1 :COL=2,1 :COL=2,0 :COL=0,1 :COL=0,0 :COL=7,0 :COL=0,0 ;
........ ........ ........ ##...##. ..#.#### ######## ######## ######## ........ ........ ........ ........ ######## ######## ......#. #.##.... ........ ........ ........ ........ ; \
........ ........ ........ ######.# ..##..## ######## ######## ######## ........ ........ ....#### ........ ######## ######## ....##.. #.#.#... ........ ........ ........ ........ ;  |
........ ........ ........ ######.# ..####.# ######## ######## #.##.### ........ ........ ...#.... #....... ######## ######## ........ #.#..... ........ ........ ........ ........ ;  |
........ ........ ........ #####.## ..###### ######## ######## ##..#### ........ ........ ..###... ###..... ######## ######## ........ #.#..... ........ ........ ........ ........ ;  |_ Row #1
........ ........ ........ ###..### ..###### ######## ######## ......## ........ ........ .#...### ...#.... ######## ######## ........ #.#..... ........ ........ ........ ........ ;  |
........ ........ ........ ######## ######## ######## ######## ######## ........ ........ .#..#..# ..##.... ######## ######## ######## ######## ........ ........ ........ ........ ;  |
........ ........ ........ .......# ..#..... ##..#.## ######## ......## ........ .....#.# ##.###.# ##.###.. ######## ######## ........ #.#..... ........ ........ ..##.#.. ........ ;  |
........ ........ ........ .......# ..#..... #.#..#.# ######## ######## ........ ....###. ###.###. ###.###. ######## ######## ######## ######## ........ ........ .#.##.#. ........ ; /
:COL=2,0 :COL=7,0 :COL=4,0 :COL=2,1 :COL=2,0 :COL=1,1 :COL=3,1 :COL=3,0 :COL=2,1 :COL=7,0 :COL=7,0 :COL=7,0 :COL=0,1 :COL=0,1 :COL=2,1 :COL=2,0 :COL=2,1 :COL=0,1 :COL=6,0 :COL=0,1 ;
........ ........ ........ ######## ######## ######## ######## .####### ........ .....### .###.### .###.### ######## ######## ........ #.#..... ........ ######## ######## ######## ; \
........ ..##.##. ........ ######## ..###### #.###.## ######## .####### ........ ....#.## #.###.## #.###.## ######## ######## ........ #.#..... ..#..... ######## #.###.## ######## ;  |
........ .#..#..# ........ ######## ..###### ######## ######## .####### ..#...#. ....##.# ##.###.# ##.###.# ##.#.### ####.### ........ #.#....# ######.. ####.### ######## ##.#.### ;  |
...##... .###.### ....#... ######## ..###### ###.###. ######## .####### .####### ....###. ###.###. ###.###. ###.#### #...#... ........ #.#....# .#.#.#.. #......# ###.###. #.#.#.## ;  |_ Row #2
..#..#.. .####### ..##.##. ######## ..###### ######## ........ ........ .###.### .....### .###.### .###.### #..#...# #.#...#. ........ #.#....# #.#.##.. ######## ######## ######## ;  |
######## .###.### ........ ######## ..###### #.###.## ######## .####### .####### ....#.## #.###.## #.###.## ######## #...#... ........ #.#....# .#.#.#.. #......# #.###.## #.#.#.## ;  |
.#.#.#.# .###.### ..##.##. ######## ..###### ######## ######## .####### .###.### ....##.# ##.###.# ##.###.# #..#...# #.#...#. ........ #.#....# #.#.##.. ######## ######## ######## ;  |
######## ..##.##. ..##.##. ######## ..###### ###.###. ######## .####### .####### .....##. ###.###. ###.###. #..#...# #...#... ........ #.#....# .#.#.#.. #......# ###.###. #.#.#.## ; /

 

It may look confusing, but I use special syntax-highlighting in my source code editor that makes it easier for me to follow.  To me it looks like this:

Untitled.thumb.png.190685ff8955eaf3cea49bad2fdf0a25.png <-- Presents scene

 

The title screen is done similarly:

1072966079_Untitled2.thumb.png.20e43100f84b1a3c98681e05d23dca9f.png <-- Tree part

 

Untitled.thumb.png.d58e18b8074210a017ca6852a5f09ecb.png <-- Text part

 

In any case, I use the ASCII grid of dots as my canvas, and hash character as the brush to mark the pixels.  The colors, I imagine in my head and set them at the top of each card.  I then rip, build, and run to see how it looks; and adjust as necessary.

 

I've seen people use MS Paint and IntyColor faster and more successfully, making great pixel art and scenes for Intellivision games; but I'm just not that good working like that.  Like you, I am also not an artist, so I do what I can in the best way that works for me. :)

 

     -dZ.

 

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

ha  -

 

I actually like your ASCII template better, because there is a clear distinction between the columns and rows.

 

In PAINT.NET, while I have the template someone made that sets up a nice screen, I still have to always be mindful and count out the 8x8 blocks and it is easy to lose sight of it once you fill in blocks. I should probably modify the template to have a mockup like your Ascii version for a canvas, and then just copy the 8x8 blocks onto the screen once I finish. I really only want to tweak the two screens to use less cards so I can define more BITMAPS instead.  They hog up the screen.  Then maybe I can add some more animation for when the character moves so it flows better. I only currently have ONE alternate card to standing still, so it looks jerky and stupid to just swap between those 2.

 

The main and bonus screen use MODE 1 because it won't work with the screens I created in PAINT/INTYCOLOR otherwise.  It messes them up if I try to use color stack.

 

Now that I cleaned up the code a bit, I'm going to shift gears for a little break and start working on sound. I want to tinker with the sound voices and come up with some sounds that mimic the coin op.  Then, I have just a handful of small music pieces to make.  I think this part will be easy since I do understand music theory somewhat and the stuff used in the game is very basic, all single notes and not very long. I have to synch these sounds with the small cutscenes on the screen, like when you die or get to game over, or when you finish off the required number of enemies and then the commander appears on the screen.  Stuff like that.

 

On a funny note, there is a one paragraph mention in chapter 1 of Oscar's advanced game programming that discusses my collision issue.  (1.4 - Collision trouble).  And the bottom line, it mentions what you guys have been talking about where I need a special flag to prevent double collision detection.  It says I also need to WAIT so the video frame will complete. If I'm still having this issue once I go back to it, I'll consider taking the red pill.  But, it makes sense. The hit point count sometimes decreases by 2 instead of one, so my collision logic is run twice. I just need to add the flag logic to stop the double count.

 

Oh, and the main character only uses 1 sprite, that's what I was talking about.  He looks like smurf, and who wants their hero to be a smurf?  I'm going to make his bottom half a different color, but I wanted to see if I can overlay blond hair on his head with the extra sprite and use FLIPX to make it move.  I probably won't bother since I won't have that extra sprite free on the bonus screen unless I take one away from the commander.

 

Link to comment
Share on other sites

1 hour ago, Mik's Arcade said:

ha  -

 

I actually like your ASCII template better, because there is a clear distinction between the columns and rows.

 

In PAINT.NET, while I have the template someone made that sets up a nice screen, I still have to always be mindful and count out the 8x8 blocks and it is easy to lose sight of it once you fill in blocks. I should probably modify the template to have a mockup like your Ascii version for a canvas, and then just copy the 8x8 blocks onto the screen once I finish.

Maybe create a grid on a second layer that can be disabled for rendering.

 

Quote

I really only want to tweak the two screens to use less cards so I can define more BITMAPS instead.  They hog up the screen.

I'm sorry, but I do not understand what you mean by "define more BITMAPS" ... Do you mean for sprite animation?

 

Quote

Then maybe I can add some more animation for when the character moves so it flows better. I only currently have ONE alternate card to standing still, so it looks jerky and stupid to just swap between those 2.

Ah, I think I understand.  You have pre-loaded your animation cards into GRAM, and so having the scene consume a big chunk of it reduces the availability of GRAM for animation.

 

In that case, you may want to consider dynamically loading the animation card of a sprite as needed, cycling the same card slot.  That's how I do all my animations in my games.

 

I understand that stock IntyBASIC is not really friendly to this technique, but perhaps others can share any solutions they may have.

 

Quote

The main and bonus screen use MODE 1 because it won't work with the screens I created in PAINT/INTYCOLOR otherwise.  It messes them up if I try to use color stack.

Well, the Color Stack works differently, and only supports four background colors in a circular list.  Mode #1 allows you to freely select the foreground and background colors for each card independently.  It does have some limitations, but generally it affords more flexibility in color selection.

 

Quote

Now that I cleaned up the code a bit, I'm going to shift gears for a little break and start working on sound. I want to tinker with the sound voices and come up with some sounds that mimic the coin op.  Then, I have just a handful of small music pieces to make.  I think this part will be easy since I do understand music theory somewhat and the stuff used in the game is very basic, all single notes and not very long. I have to synch these sounds with the small cutscenes on the screen, like when you die or get to game over, or when you finish off the required number of enemies and then the commander appears on the screen.  Stuff like that.

"Synch'ing" the musical pieces should be as simple as just calling the "PLAY" command at appropriate times.

 

Quote

On a funny note, there is a one paragraph mention in chapter 1 of Oscar's advanced game programming that discusses my collision issue.  (1.4 - Collision trouble).  And the bottom line, it mentions what you guys have been talking about where I need a special flag to prevent double collision detection.  It says I also need to WAIT so the video frame will complete.

The WAIT should be standard part of your main game loop.  Collision registers can only be read during a brief window of time when the video chip (STIC) is resetting the raster for the next frame, called Vertical Blanking (VBLANK).  This is a limitation of the Intellivision hardware.  In fact, the data bus of the CPU is locked out of the graphics sub-system altogether, including GRAM and the STIC, until VBLANK occurs, at which point the STIC relinquishes control and lets the CPU in.

 

The WAIT statement just forces a busy loop until the next VBLANK interrupt occurs, which marks the start of a new frame and allows your program to access all aspects of the video sub-system, including sprites, screen modes, GRAM, scroll, collisions, etc.

 

So, using WAIT at the top of your loop essentially synchronizes your game loop with the VBLANK cycle.  What this means is that, right after the WAIT statement, you can be sure to have the latest collision information, and any previously buffered graphics commands like DEFINE or SCROLL executed.

 

You could put the WAIT statement at any point in your game loop, just know that it will just sit there idle until the next frame.  We typically do that when we're done processing a frame, which usually coincides with your game loop iteration.

 

In fact, a lot of programs put the WAIT statement at the end of the game loop indicating, "I'm done with this frame, we now wait for the next."

 

The reason I recommend putting it at the top is because it allows you to start processing the next frame as quickly as possible after the VBLANK event occurs.  If you put it at the end, it will just wait in a busy loop until VBLANK, then test the exit condition of the game loop, and jump/goto the top to continue with the next iteration.

 

Putting it at the top allows you to do all that extra stuff before the busy loop, so by the time VBLANK happens and IntyBASIC returns control to your program, you can start processing your next frame.

 

Quote

If I'm still having this issue once I go back to it, I'll consider taking the red pill.  But, it makes sense. The hit point count sometimes decreases by 2 instead of one, so my collision logic is run twice. I just need to add the flag logic to stop the double count.

For it to be count twice in the way that the book describes, your game loop must run through more than one iteration.  If this is the case, then yes, the semaphore/flag will solve it.

 

However, I am not convinced that this is the case, since you have mentioned before that the count decreases within the same loop iteration.  If that assessment is correct (and perhaps it is not), then something else must be going on -- like testing the same collision multiple times at different points in the same iteration.

 

Quote

Oh, and the main character only uses 1 sprite, that's what I was talking about.  He looks like smurf, and who wants their hero to be a smurf?  I'm going to make his bottom half a different color, but I wanted to see if I can overlay blond hair on his head with the extra sprite and use FLIPX to make it move.  I probably won't bother since I won't have that extra sprite free on the bonus screen unless I take one away from the commander.

Ah, got it.

 

You could reduce the detail of the commander for the sake of adding it to the player sprite.  In my opinion, the player's avatar is the most important object in the game, and the one that the player focuses on more than anything else.  Indeed, it is the thing that the player will be staring at almost exclusively -- everything else is at the periphery of his range of vision.

 

Because of that, it would make sense to sacrifice other elements, within reason, for the sake of making the player sprite as cool as it can be.  Maybe the commander would look just as impressive and intimidating with one less sprite ...

 

There's also diegetic ways to incorporate such changes into your game.  For example, I had a similar need in the boss level of Christmas Carol:  I ran out of sprites and could not use the Evil Snowman, which required three (one for the body and two for the twiggy arms).  I could use it if I included it without arms, but that sounded awfully lame.  I could also invent a brand new enemy that uses a single sprite, but I've already introduced the Bad Toy in the boss level, so that seemed awkward and even more lame.

 

So, with one sprite left and no single-sprite enemy ... what to do?  My solution was to turn the Snowman into a single-sprite rolling snowball in a cut-scene.  I came up with a silly story of the Snowman getting melted down by the toy robot.

 

This served two main purposes:  First it explained to the player why the Snowman changed, in a simple, entertaining, and story-driven way.  This allowed me to re-use an established character with little hassle, and without distracting the player with extraneous new detail in what is intended to be a stressful new situation:  a boss level with new game mechanics.

 

Second, and more importantly, it worked around the hardware limitation of not having any more sprites for enemy details in that level.

 

      -dZ.

 

 

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

About that WAIT.

 

I do have a WAIT in the main loop ONE time. It's actually in the middle.

 

In the bonus_loop, having the WAIT in there really slows down the action so I had commented it out and forgot about until just now!  It makes no sense because in the main loop there is much more going on and everything runs faster! How can this be?  There are 5 moving enemies on screen at once plus the player plus your shot and enemy shots. The only thing I can think of is that on the bonus screen, all of the sprites use ZOOMY2 or ZOOMY4

 

I moved the WAIT to the start of each loop and the main_loop seems to run exactly the same, and now in this bonus loop the action is really slowed down like it was before. But, on the flip side it seems to fix the hit point issue because the code seems to now only run once per loop per hit.  Now I just need to find a way to speed up the battle or work around the double count without the WAIT in there.

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

1 hour ago, Mik's Arcade said:

About that WAIT.

 

I do have a WAIT in the main loop ONE time. It's actually in the middle.


 

Any particular reason for that?

 

Quote

In the bonus_loop, having the WAIT in there really slows down the action so I had commented it out and forgot about until just now!  It makes no sense because in the main loop there is much more going on and everything runs faster! How can this be?  There are 5 moving enemies on screen at once plus the player plus your shot and enemy shots. The only thing I can think of is that on the bonus screen, all of the sprites use ZOOMY2 or ZOOMY4


 

 

Sprite magnification is a hardware feature, so it will not affect performance one way or the other.

 

The slowness may be due to the loop iteration taking longer than one frame to complete.

 

You see, the VBLANK interrupt will occur whether you wait for it or not -- it will interrupt the CPU and do some internal housekeeping managed by the IntyBASIC runtime, like processing scroll, sprite graphics, collisions, random numbers, etc.

 

If your game loop iteration takes longer than one whole video frame, the VBLANK will trigger regardless, and interrupt it.  When it returns control to your program, if it encounters a WAIT statement then, it will pause yet again for the next frame.  You've just halved your frame rate.

 

WAIT is only there for when you complete your processing of an iteration and want to synchronize with the frame rate, so you wait for the next one.  This is useful to keep the pace of the game constant -- the regular VBLANK interrupt at 60 Hz is the only source of timing on the Intellivision.

 

Sometimes it is not possible to fit all processing on a single frame, so you must split the work into multiple frames.  In such cases, you do some processing, then WAIT, and do the rest on the next frame.   Lather, rinse, repeat.


In any case, it is always useful to put your WAIT on a convenient and strategic place that will support your game engine.  This keeps you in control of when your processing occurs in relation to a video frame.

 

Quote

I moved the WAIT to the start of each loop and the main_loop seems to run exactly the same, and now in this bonus loop the action is really slowed down like it was before. But, on the flip side it seems to fix the hit point issue because the code seems to now only run once per loop per hit.  Now I just need to find a way to speed up the battle or work around the double count without the WAIT in there.

 

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

The wait I put in the MAIN loop follows Oscar's pumpkin master code (I know, a repeating pattern in my answers)  He actually placed it right BEFORE the collision detection code. I put it back here instead of the beginning since I noticed no performance changes.

 

I wonder why the bonus loop might take longer to do a full pass than the main loop?  Honestly, the code is almost the same, and now it is just dealing with one character instead of 5.  The only thing that is different is that it makes use of more GOBSUB calls because while we are only dealing with one character, it is one of 6 different characters.  The main loop only has a couple of GOSUB calls.  Could this be the segment issue?

 

I had to insert  ASM ORG $C100 in my program, and it is right before the block of code that is all the GOSUB procedures.  Perhaps all the GOSUBS take more time.  Though, I counted and the main loop will execute 3 GOSUB calls per loop and the bonus loop 5.

 

I've tried moving the WAIT all aroud the loop and it still slows it all down. However, one thing we have proven is that adding the WAIT definitely fixes the double count issue.

 

thanks again for the time you've spent commenting on this.

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

1 hour ago, Mik's Arcade said:

The wait I put in the MAIN loop follows Oscar's pumpkin master code (I know, a repeating pattern in my answers)  He actually placed it right BEFORE the collision detection code. I put it back here instead of the beginning since I noticed no performance changes.

 

In Oscar's game engine, he updates all sprite and animation states at the top, then calls WAIT, which does exactly what you expect:  it prepares the graphics data for the next frame, then waits for it.  As part of the VBLANK, collision data is collected by the runtime, so that's why collisions are then tested afterwards.  Everything that happens afterwards is a reaction to the collisions, and then it repeats.

 

That's a fine and effective way to organize your game loop in IntyBASIC since calling DEFINE and SPRITE only buffers the changes until the next VBLANK frame, at which point they are applied.

 

With this approach, changing it to the beginning will have other consequence.  Depending on how long your loop iteration runs, it may delay the rendering of your sprite updates.

 

Quote

I wonder why the bonus loop might take longer to do a full pass than the main loop?  Honestly, the code is almost the same, and now it is just dealing with one character instead of 5.  The only thing that is different is that it makes use of more GOBSUB calls because while we are only dealing with one character, it is one of 6 different characters.  The main loop only has a couple of GOSUB calls.  Could this be the segment issue?

Gosub does add some overhead to processing.  It is great for modular, structured code, but this convenience does not come for free.

 

I'd understand if you wish to keep your code private, but if you share it here, we may be able to offer some pointers.

 

Quote

I had to insert  ASM ORG $C100 in my program, and it is right before the block of code that is all the GOSUB procedures.  Perhaps all the GOSUBS take more time.  Though, I counted and the main loop will execute 3 GOSUB calls per loop and the bonus loop 5.

There is some overhead, but 5 versus 3 should not break the bank, as it were.  You say that the code is "almost the same"; can you point out any other differences you may have noticed?

 

Quote

I've tried moving the WAIT all aroud the loop and it still slows it all down. However, one thing we have proven is that adding the WAIT definitely fixes the double count issue.

Moving the WAIT around will change when the SPRITE and DEFINE statements are applied.  It will also perform a busy loop until the next frame event.  That means that if a frame even occurs naturally, because your loop iteration took too long to complete, and then a WAIT is encountered afterwards, it'll wait for the next frame again.

 

Like I said before, ideally you would only use a WAIT when you are done processing one frame and you are ready for the next one, so you synchronize with the vertical blanking of the video signal by waiting for the next interrupt event, and on you go.

 

Consider this simple game engine:

' Update sound effects on every frame
On Frame Gosub UpdateSoundEffects

' Main Game Loop
MAIN:
  ' Update logical world state
  Gosub GetUserInput
  Gosub UpdatePlayerState
  Gosub UpdateEnemyState
  Gosub CheckCollisions

  ' React to collisions here

  ' Render frame output
  Gosub UpdateSpriteAnimation
  Gosub UpdateSpritePositions
  Gosub UpdateBackgroundObjects

  ' We're done with one frame, wait for the next one
  WAIT
Goto MAIN

 

The things are done in a certain order so that the output of one cascades into the next one.  For instance, you want to handle user input so that you can then update the player state.  You also want to update enemy AI and positions so that you can see if they collided with the player or a bullet, etc.

 

This is sort of what the Pumpkin Master game code does, in general terms.  The main difference is that the loop starts with the "Render frame output" part:

' Main Game Loop
MAIN:
  ' Render frame output
  Gosub UpdateSpriteAnimation
  Gosub UpdateSpritePositions
  Gosub UpdateBackgroundObjects

  ' We're done with one frame, wait for the next one
  WAIT

' Update logical world state
  Gosub GetUserInput
  Gosub UpdatePlayerState
  Gosub UpdateEnemyState
  Gosub CheckCollisions

  ' React to collisions here

Goto MAIN

 

That's why it looks like the WAIT is in the middle ... well, it is in the middle of the loop iteration, but it is actually at the end of the entire frame processing pipeline.  So you can either,

  • Update logical state
  • Render frame
  • Wait
  • Repeat

or you can,

  • Render frame
  • Wait
  • Update logical state
  • Repeat

As they say, six of one or half-a-dozen of the other.

 

Quote

thanks again for the time you've spent commenting on this.

No worries, it's my pleasure.

 

     -dZ.

Edited by DZ-Jay
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...