Jump to content
IGNORED

Snake routine? Any takers?


Willsy

Recommended Posts

Would anyone fancy having a go at writing a snake routine in extended basic? You know, the standard snake thing where a snake (say, 10 segments long) moves horizontally until it bumps into something and then moves up/down and changes horizontal direction.

 

I wrote one in Forth a while ago, and it seems to work just fine. But what I couldn't work out (in the time I had available) was the drawing/erasing of the snake segments. I'm pretty sure that *all* you have to do, to make the snake move, is draw the head, and erase the tail. You don't need to draw the segments inbetween. I couldn't make it work though.

 

In the end, what I actually coded, was a 10 *one* segment snakes, each taking care of erasing itself, updating it's position and checking the screen to see if it has hit a character. So, it *looks* like one snake, but it's actually 10 "objects" that are next to each other, giving the illusion of a snake.

 

Is that how's it's really done? There must be a more efficient way where just the head does the collision detection, and the tail is erased.

 

Anyone fancy a go? I'll then take the code and port it to TF for fun.

Link to comment
Share on other sites

There was a TI BASIC game ages ago that did this call Worm of Bemer - one difference being that you steered the snake at will. To make it work it tracked the position of every body segment in an array, but yes, only erased the tail and drew the head. I need a quickie, let me see if I can put it together in XB before bed :)

 

Doing it as separate objects, like you did, probably works better for a game like Centipede where it has to split up, though. :)

 

Link to comment
Share on other sites

I think the way you were describing (draw head + erase tail) is probably the most efficient. I'd probably go with that method, what bit of it didnt work Willsy?

 

I seem to rememer it leaving trails all over the place, but I can't remember now!

Link to comment
Share on other sites

100 RANDOMIZE
110 REM SNAKE THINGY
120 REM DEFINE ARRAYS FOR POSITION OF EACH PIECE
130 OPTION BASE 1
140 DIM R(10),C(10)
150 CNT=10 :: REM NUMBER OF PIECES
160 CALL CLEAR
170 REM SET UP SNAKE
180 FOR I=1 TO CNT
190 R(I)=1 :: C(I)=I+1 :: CALL HCHAR(1,I+1,42)
200 NEXT I
210 REM DRAW SOME WALLS
220 CALL VCHAR(1,1,35,24):: CALL VCHAR(1,32,35,24)
230 REM AND SOME RANDOM OBSTACLES TO HIT
240 FOR I=2 TO 24 :: CALL HCHAR(I,INT(RND*32)+1,35):: NEXT I
250 REM INITIALIZE DIRECTION AND RING BUFFER
260 DIR=1 :: REM MOVING RIGHT
270 HEAD=10 :: REM CURRENT HEAD IS ARRAY ENTRY 10
280 REM MAIN LOOP STARTS HERE
290 REM SAVE OLD HEAD
300 HR=R(HEAD):: HC=C(HEAD)
310 REM FIRST ROTATE THE RING BUFFER POINTERS
320 HEAD=HEAD+1
330 IF HEAD>CNT THEN HEAD=1
340 REM ERASE THE OLD TAIL (IN 'HEAD')
350 CALL HCHAR(R(HEAD),C(HEAD),32)
360 REM UPDATE THE POSITION
370 R(HEAD)=HR :: C(HEAD)=HC+DIR
380 REM CHECK FOR LEGAL MOVE
390 CALL GCHAR(R(HEAD),C(HEAD),X)
400 IF X=32 THEN 480
410 REM NOT LEGAL - DROP DOWN AND CHANGE DIRECTION
420 C(HEAD)=HC :: R(HEAD)=R(HEAD)+1
430 DIR=-DIR
440 REM CHECK FOR BOTTOM OF SCREEN AND WRAP
450 IF R(HEAD)>24 THEN R(HEAD)=1
460 REM CHECK LEGALITY AGAIN
470 GOTO 390
480 REM NEW POSITION IS OKAY, DRAW THE HEAD
490 CALL HCHAR(R(HEAD),C(HEAD),42)
500 REM AND LOOP
510 GOTO 280

 

Try that :)

Edited by Tursi
Link to comment
Share on other sites

Something I always wondered about Centipede was the interaction when you have close groups of mushrooms. This example:

 

#<****** snake enters here
##
#*
#*******> snake exits here

 

In Tursi's code the snake exits two lines below the double mushroom ##. I suspect the logic is such that the snake changes direction every time it moves down, which would explain why the snake above exits a line below the ## instead of directly below it. The collision detection probably goes like this:

 

1. snake hits the left wall, moves down 1 line, changes direction (now going right)

2. snake immediately hits mushroom against the wall, moves down 1 line, changes direction (now going left)

3. snake hits the left wall again, moves down 1 line, changes direction (now going right)

4. snake travels right now that the path is clear

 

Not that this is wrong, I'm just curious about how Centipede actually did it.

Link to comment
Share on other sites

Something I always wondered about Centipede was the interaction when you have close groups of mushrooms. This example:

 

#<****** snake enters here
##
#*
#*******> snake exits here

 

In Tursi's code the snake exits two lines below the double mushroom ##. I suspect the logic is such that the snake changes direction every time it moves down, which would explain why the snake above exits a line below the ## instead of directly below it. The collision detection probably goes like this:

 

1. snake hits the left wall, moves down 1 line, changes direction (now going right)

2. snake immediately hits mushroom against the wall, moves down 1 line, changes direction (now going left)

3. snake hits the left wall again, moves down 1 line, changes direction (now going right)

4. snake travels right now that the path is clear

 

Not that this is wrong, I'm just curious about how Centipede actually did it.

 

The way I did it in my Forth example was to change horizontal direction when hitting an object (that includes screen edge - I drew a frame around the edge of the screen) and change vertical direction at the top/bottom of the screen.

 

Actually, I think I did it exactly the same as Tursi. The example is shown on the Chicago Faire video. (20 minutes into the video)

Link to comment
Share on other sites

Well, I spent entirely to much time today frame-stepping in MAME to see how the original Centipede moves. It is actually pretty interesting. The collision detection is not done until *after* the turn has been made and then the only test is to see what is now in front of the head. So in the case above, the # against the wall would not have caused any collision or direction change and the Centipede would just walk over it.

  • Like 2
Link to comment
Share on other sites

Well, I spent entirely to much time today frame-stepping in MAME to see how the original Centipede moves. It is actually pretty interesting. The collision detection is not done until *after* the turn has been made and then the only test is to see what is now in front of the head. So in the case above, the # against the wall would not have caused any collision or direction change and the Centipede would just walk over it.

 

Eh? If it's not done until after thev turn is made then what prompts it to turn in the first place? Confused!

Link to comment
Share on other sites

The determination to turn is based on what is *in front* of the Centipede head only. So, in the example above:

 

#<***** Centipede hits wall, moves down, reverses direction
##****> The mushroom against the wall is walked-over
#
#

 

When the Centipede detects the wall, it will move down and reverse direction. However, once it gets to the next line, the mushroom that was directly below it would simple be *walked over*. This is because once the head have moved down and facing the opposite direction, that mushroom is not in front of the Centipede. Of course the Centipede body is done with sprites so the movement does not affect the tiled mushroom play field. To get the rapid back and forth of the Centipede moving straight down, you need something like this:

 

#*
#*#
#*
#*#
#>

 

Not that is matters, I just always wondered (for some unknown reason) about the mechanics of the original arcade game. It is also interesting to see the irregularity of the body segments while turning. The game was very organic and it really blows me away how much detail was put into the mechanics.

 

Link to comment
Share on other sites

My hope was with RXB that people would attack problems like these with the commands like CALL RMOTION(sprite#) that reverses sprite motion 180 degrees

or CALL GMOTION(sprite#,row,col) gets the motion of a sprite and swapping the row and col would make a sprite turn 90 degrees.

Negate the values and you get a 180 degree and if you use Motion you could mathematically get the sprite to turn in a circle.

Also as I cleaned up other sprite calls like Distance, Coinc and Motion.

  • Like 1
Link to comment
Share on other sites

My hope was with RXB that people would attack problems like these with the commands like CALL RMOTION(sprite#) that reverses sprite motion 180 degrees

or CALL GMOTION(sprite#,row,col) gets the motion of a sprite and swapping the row and col would make a sprite turn 90 degrees.

Negate the values and you get a 180 degree and if you use Motion you could mathematically get the sprite to turn in a circle.

Also as I cleaned up other sprite calls like Distance, Coinc and Motion.

 

That reminds me , Rich .... I really need to make some sort of RXB game ....... yes .... that would be ineresting .... I'll come up with something. Sorry to interrupt! :)

Link to comment
Share on other sites

My hope was with RXB that people would attack problems like these with the commands like CALL RMOTION(sprite#) that reverses sprite motion 180 degrees

or CALL GMOTION(sprite#,row,col) gets the motion of a sprite and swapping the row and col would make a sprite turn 90 degrees.

Negate the values and you get a 180 degree and if you use Motion you could mathematically get the sprite to turn in a circle.

Also as I cleaned up other sprite calls like Distance, Coinc and Motion.

 

Any chance of ever getting RXB on a cartridge?

Link to comment
Share on other sites

Interesting, it seems I no longer have permission to download from here. . .at least not in this thread, as others do work.

 

My guess is that it has more to do with those specific files. Try downloading the attached dummy.txt file to see whether I might be right. Rich (@RXB), any ideas?

 

...lee

 

dummy.txt

Edited by Lee Stewart
Link to comment
Share on other sites

  • 1 month later...

I was bored in my lunch break, so I finally got around to converting Tursi's snake code:

 

10 VALUE CNT \ number of snake segments (150)
0 VALUE DIR \ direction. 1=right -1=left (260)
0 VALUE HEAD \ pointer into array (270)
0 VALUE HR	 \ head row (300)
0 VALUE HC	 \ head column (300)
CREATE ROW CNT CHARS ALLOT \ row array (140)
CREATE COL CNT CHARS ALLOT \ column array (140)

: SETUP ( -- )
1 GMODE \ 32 column mode
\ initialise snake array and draw snake...
CNT 0 DO ( 180)
 0 ROW I + C! \ initialise row (190)
 I 1+ COL I + C! \ initialise column (190)
 0 I 1+ 42 1 HCHAR
LOOP
\ draw some walls...
0 0 35 24 VCHAR 0 31 35 24 VCHAR ( 220)
\ and some random obstacles to hit...
23 1 DO I 32 RND 35 1 HCHAR LOOP ( 240)
\ initialise direction and ring buffer...
1 TO DIR \ moving to the right (260)
CNT 1- TO HEAD \ current head is the 10th entry (270)
;

: CHECK-MOVE ( -- )
\ check for legal move...
ROW HEAD + C@ COL HEAD + C@ GCHAR ( 390)
32 <> IF ( 400)
 \ not legal, change direction...
 HC COL HEAD + C! ( 420)
 ROW HEAD + C@ 1+ ROW HEAD + C! ( 420)
 DIR NEGATE TO DIR ( 430)
 \ check for bottom of screen and wrap...
 ROW HEAD + C@ 23 > IF ( 450)
	 0 ROW HEAD + C! ( 450)
	 BREAK? \ check break key (fctn 4)
 THEN
 RECURSE \ check legality again (470)
THEN ;

: MAIN-LOOP ( -- )
BEGIN
\ save old head...
ROW HEAD + C@ TO HR COL HEAD + C@ TO HC

\ rotate the ring buffer pointers...
HEAD 1+ CNT MOD TO HEAD

\ erase the old tail (in 'head')...
ROW HEAD + C@ COL HEAD + C@ 32 1 HCHAR

\ update the position...
HR ROW HEAD + C!
HC DIR + COL HEAD + C!

CHECK-MOVE

\ new position is okay; draw the head
ROW HEAD + C@ COL HEAD + C@ 42 1 HCHAR
AGAIN ;

: GO ( -- ) SETUP MAIN-LOOP ;

 

I've used the same comments as Tursi. Numbers in brackets are the equivalent lines in Tursi's XB program.

 

My version uses a little bit of recursion. The XB program, having detected an illegal move changes direction and moves down one screen line. Having done that, it checks again that the move is legal (line 470). Well, there's no GOTO in Forth, so I factored the legality check into its own definition, then used RECURSE. RECURSE simply causes the definition to call itself again. When a legal move is finally determined the recursion un-winds itself, as one would expect.

 

You can paste the above code directly into TF V1.1 (which comes built into classic99). Dyed-in-the-wool console die-hards can type the following more compact version directly in:

 

10 VALUE CNT 0 VALUE DIR
0 VALUE HEAD 0 VALUE HR 0 VALUE HC
CREATE ROW CNT CHARS ALLOT
CREATE COL CNT CHARS ALLOT

: SETUP
1 GMODE CNT 0 DO
 0 ROW I + C! I 1+ COL I + C! 0 I 1+ 42 1 HCHAR
LOOP 0 0 35 24 VCHAR 0 31 35 24 VCHAR
23 1 DO I 32 RND 35 1 HCHAR LOOP
1 TO DIR CNT 1- TO HEAD ;

: CHECK-MOVE
ROW HEAD + C@ COL HEAD + C@ GCHAR 32 <> IF
 HC COL HEAD + C! ROW HEAD + C@ 1+ ROW HEAD + C!
 DIR NEGATE TO DIR
 ROW HEAD + C@ 23 > IF 0 ROW HEAD + C! BREAK? THEN
 RECURSE
THEN ;

: MAIN-LOOP
BEGIN
ROW HEAD + C@ TO HR COL HEAD + C@ TO HC
HEAD 1+ CNT MOD TO HEAD
ROW HEAD + C@ COL HEAD + C@ 32 1 HCHAR
HR ROW HEAD + C! HC DIR + COL HEAD + C! CHECK-MOVE
ROW HEAD + C@ COL HEAD + C@ 42 1 HCHAR
AGAIN ;

: GO SETUP MAIN-LOOP ;

 

TurboForth takes on average approx 1.5 seconds to move the snake all the way down the screen. XB when I measured it required approx 41 seconds on average, making TF V1.1 approx. 27.3 times faster. TF V1.2 takes approx 1.3 1.1 seconds (as close as I could measure it) making it ~31.5 37 times faster. Like anyone needs convincing!

 

We need some convenient way of instrumenting execution times! The human eye and a stopwatch is not very accurate! Plus it draws attention in the office! ;)

 

http://www.youtube.com/watch?v=Gxt11NDxsYA

 

snake_tf.txt

snake_xb.txt

  • Like 1
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...