Jump to content
  • entries
    39
  • comments
    0
  • views
    820

AI: Scanning


Piledriver

25 views

I explained how the AI interacted with the playfield.  To do this I need to scan rectangular regions of playfield for obstacles.  That's what I want to discuss today.

 

Lets simplify the problem to only determining if a given tile in a playfield row is empty or solid.  PF0 is not used so any tile in there is empty.  My first "solution" was something like this:

1.  Convert ship horizontal position to a tile column (There are 0-39 playfield tiles or playfield columns).

2.  if (column is 00-03) - index is in the unused pf0, return 0
3.  if (column is 04-11) - remap column to 0-7 (subtract 04) then reverse column (column = 7 - column), convert this to an empty byte but with a 1 in the bit position of the column, now and this with PF1 and return result.
4.  if (column is 12-19) - remap column to 0-7 (subtract 12), convert this to an empty byte but with a 1 in the bit position of the column, now and this with PF2 and return result.
5.  if (column is 20-27) - remap column to 0-7 (subtract 20) then reverse index (index = 7 - index), convert this to an empty byte but with a 1 in the bit position of the column, now and this with PF2 and return result.
6.  if (column is 28-35) - remap column to 0-7 (subtract 28), convert this to an empty byte but with a 1 in the bit position of the column, now and this with PF1 and return result.
7.  if (column is 36-39) - column is in the unused mirrored pf0, return 0
8.  if result is 0 the pf tile is empty - otherwise it isn't.

 

I think I got this explained right....?  The details don't matter what matters is this is WAY too complicated!!!  The game might have to scan up to 20 blocks in a single frame so this was the wrong approach.  This was another one of those moments where I thought I was trying to do something impossible on Atari.  I learned you don't get too far with 2600 programming if you give up easily.

 

Anyways I was able to express the complexities above in some tables.  In the solution I came up with you take the ship's horizontal column value and use that to index into two tables... this gives you values (masks) that you and with PF1 and PF2 respectively... then or those values together and you have 0 if the column is empty or non zero otherwise!  Here's the two tables I mentioned.  I put them side by side to make them easier to compare.

 

TABLE_PF1MASKSWIDTH1_BANK2:     TABLE_PF2MASKSWIDTH1_BANK2:
    .byte #%00000000                .byte #%00000000    ;0
    .byte #%00000000                .byte #%00000000    ;1
    .byte #%00000000                .byte #%00000000    ;2
    .byte #%00000000                .byte #%00000000    ;3
    
    .byte #%10000000                .byte #%00000000    ;4
    .byte #%01000000                .byte #%00000000    ;5
    .byte #%00100000                .byte #%00000000    ;6
    .byte #%00010000                .byte #%00000000    ;7
    .byte #%00001000                .byte #%00000000    ;8
    .byte #%00000100                .byte #%00000000    ;9
    .byte #%00000010                .byte #%00000000    ;10
    .byte #%00000001                .byte #%00000000    ;11
    
    .byte #%00000000                .byte #%00000001    ;12
    .byte #%00000000                .byte #%00000010    ;13
    .byte #%00000000                .byte #%00000100    ;14
    .byte #%00000000                .byte #%00001000    ;15
    .byte #%00000000                .byte #%00010000    ;16
    .byte #%00000000                .byte #%00100000    ;17
    .byte #%00000000                .byte #%01000000    ;18
    .byte #%00000000                .byte #%10000000    ;19
    
    .byte #%00000000                .byte #%10000000    ;20
    .byte #%00000000                .byte #%01000000    ;21
    .byte #%00000000                .byte #%00100000    ;22
    .byte #%00000000                .byte #%00010000    ;23
    .byte #%00000000                .byte #%00001000    ;24
    .byte #%00000000                .byte #%00000100    ;25
    .byte #%00000000                .byte #%00000010    ;26
    .byte #%00000000                .byte #%00000001    ;27
    
    .byte #%00000001                .byte #%00000000    ;28
    .byte #%00000010                .byte #%00000000    ;29
    .byte #%00000100                .byte #%00000000    ;30
    .byte #%00001000                .byte #%00000000    ;31
    .byte #%00010000                .byte #%00000000    ;32
    .byte #%00100000                .byte #%00000000    ;33
    .byte #%01000000                .byte #%00000000    ;34
    .byte #%10000000                .byte #%00000000    ;35
    
    .byte #%00000000                .byte #%00000000    ;36
    .byte #%00000000                .byte #%00000000    ;37
    .byte #%00000000                .byte #%00000000    ;38
    .byte #%00000000                .byte #%00000000    ;39

 

It's hard to explain but these tables encapsulate all the complexities of the mirrored playfield and reversed bit order of PF1 and PF2.  The result though is I can check the value of a playfield block fast!  Recall that I needed to scan horizontal spans of playfield that were 1,2,3, or 4 tiles wide.  I made another version of these tables that give me the results for 3 tiles in a row.  If I needed to scan 2 blocks or 4 blocks I could generate masks for that by combining values from these tables.  This is a tad slower but it's a tradeoff and I don't need to have tables for 2 and 4 width PF spans.

 

There was another big but simple optimization.  For the front scan I have to scan Playfield spans that are 4 tiles wide by 2-3 tiles tall.  Any easy way to simplify this is to or together the PF1 bytes from the rows of the span and likewise with the PF2 bytes.  Then do the masking step after that.  With this row combining step and the tables I was able to greatly reduce the processing time on playfield scans!

 

I had a bit of a failure doing the AUTO flight AI.  I kept thinking the ship should be able to handle just about any obstacle.  I spent a lot of time on the "far scanner".  It was a pretty neat idea - detect distant objects early enough to have time to avoid them.  I actually implemented this and it worked... except I couldnt make it fast enough and the screen would roll so I had to yank it out.  Here's a mockup of one of my designs to give you some idea what I was up to.
 

screen41-Copy-Copy.png.3067846927b554326680131bf0d154ee.png

0 Comments


Recommended Comments

There are no comments to display.

Guest
Add a comment...

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