Help with Nokia Snake-like collision testing?

Ask and answer questions about making games and related topics. Unrelated topics go in that other forum.

Moderators: marionline, SDHawk

Post Reply
User avatar
sheamkennedy
Liquid Metal Slime
Posts: 1110
Joined: Mon Sep 16, 2013 9:29 pm
Location: Tama-shi, Tokyo, Japan
Contact:

Help with Nokia Snake-like collision testing?

Post by sheamkennedy »

I am making a game which has a mechanic similar to that of Nokia Snake. I would like to make a code which stores the last 5 (x,y) positions of my hero and then checks for collision with these past 5 positions to see if the hero has overlapped their own trail.

I've haven't been coding for awhile and assumed this would be easy but I can't seem to figure out how to implement this.

This is what I've tried so far:

Code: Select all

#This checks if there is a collision with the trail (I currently only have a trail 2 blocks long)
#Note: count is measuring the steps taken
  if((hero x(me) == step 2x) && (hero y(me) == step 2y)) then(
    play sound(1, false, true) #plays a sound to indicate collision
  )
     
  if(count > 0) then( #If a step has been taken then store the current position xy values
    step 1x := hero x(me)
    step 1y := hero y(me)
  )
  
  if(count > 1) then( If a second step has been taken store the xy values as the previous xy position
    step 2x := step 1x
    step 2y := step 1y 
  )
As far as I can tell the stored value should be cycling through thus step 2x and step 2y should equal my previous xy position but this is not the case. Upon inspection the values of step 2x and step 2y remain at a value of (0, 0).
Last edited by sheamkennedy on Thu Aug 25, 2016 10:15 pm, edited 2 times in total.
⊕ P E R S O N A L M U S I C: https://open.spotify.com/album/6fEo3fCm5C3XhtFRflfANr
� C O L L A B M U S I C: https://dustpuppets.bandcamp.com/releases
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

Well, if the snake is only two blocks long you can't hit yourself anyway, since you can't turn backwards on yourself.

Storing the locations and order of the segments is a very appropriate use for slices, as you can add a new slice to the end ("set parent"), delete the slice at the other end ("free slice(first child(snake parent))"), and test whether a segment is placed somewhere with "slice at pixel(snake parent, x, y)". I guess you could still use a hero to animate the head sliding forward, although those sliding animations are more work than just having the head and tail jump a tile at a time. And you need to script your own movement anyway to disallow moving back the direction you came.
Last edited by TMC on Fri Aug 26, 2016 11:03 am, edited 1 time in total.
User avatar
Bob the Hamster
Lord of the Slimes
Posts: 7660
Joined: Tue Oct 16, 2007 2:34 pm
Location: Hamster Republic (Ontario Enclave)
Contact:

Post by Bob the Hamster »

Arrays are going to help a ton here. Someday we will have real arrays, but for now, fake arrays are not hard to do.

You could make some fake arrays with "read global" and "write global" but for what you are doing, slices are going to be easiest, since they already have X and Y properties, and you can use them to visually display your snake on the map.

First, create a slice container, and parent it to the map layer

Code: Select all

global variable(0, snake layer)

plotscript, create snake layer, begin
  snake layer := create container()
  set parent(snake layer, lookup slice(sl:hero layer))
  # Create 5 children to hold the 5 most recent positions
  variable(ch, i)
  for(i, 0, 4) do(
    ch := create rect(20, 20)
    set parent(ch, snake layer)
    # Make all the children start out at the hero's x,y position
    set slice x(ch, hero pixel x(0))
    set slice y(ch, hero pixel y(0))
  )
end
Now each time the hero completes a step, you can add a new child to the snake layer, and remove an old one.

Code: Select all

plotscript, each step snake, begin
  variable(ch)
  # Add a new segment at the hero's current 
  ch := create rect(20, 20)
  # this reparents the new child slice, and makes it the first child in the list
  move slice below(ch, first child(snake layer))
  set slice x(ch, hero pixel x(0))
  set slice y(ch, hero pixel y(0))
  # Remove the last child in the list
  free slice(last child(snake layer))
end
Finally, you can check for collisions like this:

Code: Select all

script, check for snake collisions, begin
  variable(ch)
  ch := first child(snake layer)
  while(ch) do(
    if(find colliding slice(snake layer, ch, false)) then(
      # Crash! A snake child touched a sibling
      exit returning(true)
    )
    ch := next sibling(ch)
  )
  # didn't find any collisions
  exit returning(false)
end
If any of this needs more explanations, just ask :)
User avatar
sheamkennedy
Liquid Metal Slime
Posts: 1110
Joined: Mon Sep 16, 2013 9:29 pm
Location: Tama-shi, Tokyo, Japan
Contact:

Post by sheamkennedy »

Thanks. I did manage to get it working by remembering and recalling map (x,y) positions but will probably switch over to the slice method since it'll be more efficient in the long run.
⊕ P E R S O N A L M U S I C: https://open.spotify.com/album/6fEo3fCm5C3XhtFRflfANr
� C O L L A B M U S I C: https://dustpuppets.bandcamp.com/releases
Post Reply