A question about the logic of making a "Snake" game

  • Thread starter Jamin2112
  • Start date
  • Tags
    Game Logic
In summary, there are two main procedures for determining where the snake's food should appear next in a "Snake" game. The first is to pick a random location on the screen and continue picking new locations until one is found that does not collide with the snake. The second involves using the positions of the links that make up the snake to determine a proper next location for the food. This method could be made more efficient by forward-seeking in steps of a prime number or implementing "quadratic probing" to add more randomness.
  • #1
Jamin2112
986
12
I've started to make a "Snake" game (example: http://www.kongregate.com/games/uchiha/classic-snake-game) and reached a dead end. I'm not sure the programmatically best way of figuring out where the snake's "food" should next appear. It should of course appear anywhere on the screen that doesn't collide with the snake. I therefore think there are 2 procedures:

  • (1) Pick a random location on the screen. If this location lies somewhere on the snake, then pick another random location. Do this until you find a proper location.
  • (2) Use the positions of the links that compose the snake to figure out a proper next random location for the food.

The first one is inefficient, especially when the snake is long. The second one, I don't know how to write. Any ideas for how I can write the second one?

By the way, here's what I have so far:

The snakegame class is: jaminweb.com/Snakegame.html

Code:
        $(document).keydown(function(e)
        {
            switch(e.which)
            {
                case 37: // left arrow key
                  s.redirect(3);
                  break;

                case 38: // up arrow key
                  s.redirect(4);
                  break;

                case 39: // right arrow key
                   s.redirect(1)
                   break;

                case 40: // down arrow key
                   s.redirect(2);
                   break;

                default: return; // exit this handler for other keys
            }
            e.preventDefault(); // prevent the default action (scroll / move caret)
         });

        function snakegame(C, C_h, C_w)
        {
                /* NOTE TO SELF: C is a Raphel object. Can't find a method to return the height
                   and width of a Raphael object in the documentation: 
                   [PLAIN]http://raphaeljs.com/reference.html#Raphael.[/PLAIN] 
                   Using C_h and C_w for now, but should probably change it later.
                */
                
                this.linkSize = 30; // size of a snake unit, in pixels
                
                this.food = C.rect(10, 30, this.linkSize, this.linkSize);
                this.food.attr("fill","#39275b")
                this.food.glow();
                
                /* On instantiation, the snake direction is down and has 1 link */
                this.dy = this.linkSize;
                this.dx = 0;
                this.link = C.rect(C_h/2, C_w/2, this.linkSize, this.linkSize);
                this.link.attr("fill", "#d7a900");
                this.body = [this.link];
                
                /* Event listener for changing the direction of the
                   snake with arroy keys on the keyboard
                */
                this.redirect = function(dirnum)
                {
                    switch (dirnum)
                    {
                        /*
                            dirnum corresponds to
                            1 ---> right
                            2 ---> down
                            3 ---> left
                            4 ---> up
                        */
                        case 1: 
                            this.dx = this.linkSize;
                            this.dy = 0;
                            break;
                        
                        case 2:
                            this.dx = 0;
                            this.dy = this.linkSize;
                            break;
                        
                        case 3:
                            this.dx = -this.linkSize;
                            this.dy = 0;
                            break;
                        
                        case 4:
                            this.dx = 0;
                            this.dy = -this.linkSize;
                            break;
                        
                        default: // never happens
                            break;
                    }
                            
                }
                this.move = function()
                {
                    /*
                        ...
                    */
                    var temp = this.body[0];
                    var BBhead = temp.getBBox();
                    if (BBhead.x < 0 || BBhead.x2 > C_w || BBhead.y < 0 || BBhead.y2 > C_h)
                    {
                        clearInterval(mover); 
                        return;
                    }
                    var BBfood = this.food.getBBox();
                    if (this.boxCollision(BBhead, BBfood))
                    {
                        this.moveFood();
                        this.addLink();
                    }
                    this.body[0].translate(this.dx, this.dy);
                    for (var i = 1, j = this.body.length; i < j; ++i)
                    {
                        this.body[i] = temp;
                        temp = this.body[i];
                    }
                }
                
                var mover = setInterval(this.move.bind(this), 300);   
                
                this.addLink = function()
                {
                    alert("you hit it!"); 
                }
                
                this.moveFood = function()
                {
                    
                }
                this.boxCollision = function(A, B)
                {
                    return A.x > B.x && A.x < B.x2 && A.y > B.y && A.y < B.y2;
                }

        }

It's messy, but hopefully you can see my intent and give me some ideas for how to build off what I have now.
 
Last edited by a moderator:
Technology news on Phys.org
  • #2
The first method should be fine, really. I've made a similar snake game in html5 with method 1. Works perfectly.

Modern PCs don't lag much when computing a single random number.
 
  • #3
Instead of doing it purely random you should pick a random point in the array and forward-seek until you find a free space. This way the upper bound is N rather than unknown. That and you don't waste cycles generating random numbers.
 
  • #4
DavidSnider said:
Instead of doing it purely random you should pick a random point in the array and forward-seek until you find a free space. This way the upper bound is N rather than unknown. That and you don't waste cycles generating random numbers.

Then the piece of food will always be right near the snake. He'll be stuck in one area of the screen because the piece of food will always appear next to one of his units.
 
  • #5
Jamin2112 said:
Then the piece of food will always be right near the snake. He'll be stuck in one area of the screen because the piece of food will always appear next to one of his units.

The vast majority of the time the initial space chosen will be empty, when the screen is mostly filled it's always going to be near the snake anyway. You could add a random jitter factor that says "pick the nth open spot you find" where n is a random number. You can also pick a random seek direction for less predictability.
 
Last edited:
  • #6
Jamin2112 said:
Then the piece of food will always be right near the snake

You could forward-seek in steps of p locations, where p is relatively prime to the size of the playing area.

That will step through all the board locations in sequence, but in pseudo-random order.

For "more randomness", look up the "quadratic probing" technique for dealing with collisions in hash tables.
 

1. What is the logic behind creating a "Snake" game?

The logic behind creating a "Snake" game involves several key elements, such as:

  • The movement of the snake, which is controlled by the player's input.
  • The growth of the snake as it consumes food or power-ups.
  • The collision detection between the snake, its own body, and other objects in the game.
  • The scoring system, which increases as the snake grows and decreases if the snake collides with obstacles.
  • The game over condition, which is triggered when the snake collides with obstacles or when the player chooses to quit the game.

2. How do you program the movement of the snake in a "Snake" game?

The movement of the snake is typically programmed using a combination of conditional statements and variables. The direction of the snake is controlled by the player's input, which is then translated into changes in the snake's position on the game grid. As the snake moves, its body segments are repositioned and the game board is updated accordingly.

3. What is the importance of collision detection in a "Snake" game?

Collision detection is crucial in a "Snake" game because it determines the outcome of the game. The snake must be able to detect when it collides with its own body or with obstacles in order to trigger the game over condition. Without accurate collision detection, the game would not function properly and the player would not be able to control the snake's movements effectively.

4. How is scoring calculated in a "Snake" game?

In a "Snake" game, scoring is typically based on the length of the snake. As the snake consumes food or power-ups, its length increases and the player's score goes up. However, if the snake collides with obstacles, its length decreases and the score decreases accordingly. Some "Snake" games may also include additional scoring elements, such as time bonuses or special challenges.

5. What are some potential challenges in creating a "Snake" game?

Some potential challenges in creating a "Snake" game include:

  • Designing and implementing smooth and responsive movement for the snake.
  • Creating accurate collision detection that takes into account various scenarios, such as the snake colliding with its own body or with obstacles at different angles.
  • Balancing the difficulty of the game to keep it challenging but not too frustrating for players.
  • Incorporating interesting and varied obstacles and power-ups to keep the gameplay engaging.
  • Optimizing the game's performance to ensure it runs smoothly on different devices and platforms.

Similar threads

  • Programming and Computer Science
Replies
4
Views
1K
  • Programming and Computer Science
Replies
2
Views
1K
  • Programming and Computer Science
Replies
33
Views
6K
  • Engineering and Comp Sci Homework Help
Replies
4
Views
1K
Replies
1
Views
7K
Replies
15
Views
4K
Back
Top