Build a Classic Snake Game in ActionScript 2.0

Well, we’re approaching the end of 2009, and as ever, these final days in December are a time for reflection, memories and nostalgia. At Activetuts+ we endeavor to be forward-thinking, moving with the times and embracing technology. Saying that, it’s also important we appeal to all our readers, so for those of you who haven’t made the jump yet, let’s finish off the year with a bit of ActionScript 2.0!

In this tutorial, you’ll create a simple AS2 snake game.

Step 1: Setting up the File

Start Flash, and click Create New: Flash File (Actionscript 2.0). You can set the stage size to whatever pleases you – I’ve set mine to 500 x 350. I do advise you to set the framerate to 30fps.

Now, you can either decide to follow this step and draw the required movieclips yourself, or you can skip ahead and use the ones I created. If you want to use the ones I created you can find them in the source file. Just add them to the library and drag them onto the stage. If you are going to draw your own: you don’t have to literally draw the same as I did, but do make sure you stick to the sizes.

Step 2: Create the Snake Pit

The first thing we’ll create is the pit for the snake to roam around. Create a rectangle of 400 x 250 and convert it to a movieclip. Make sure you pay attention to the registration point; make it top-left.

Make sure you give the snake pit the instance name snakepit and align it slightly above the center of the stage (so that we can add text below it later, without messing up the aesthetics).

Step 3: Create the Snake’s Head

Draw a square (perhaps with rounded corners) without a border (size 25 x 25) and copy it so you have 2 exactly the same. Convert one of them to a movieclip. Again, pay attention to the top-left registration.

Make sure you give it the instance name bodypart0 and double check that its size is 25 x 25.

Step 4: Snake’s Head ActionScript

Enter the “head” movieclip. Once inside it, add this line of code to the first and only frame:

stop();

Now, draw a little face on the snake’s head, so you can tell it apart from other bodyparts.

Step 5: Additional Face

Add a second frame to the “head” movieclip, and on this frame, draw a sad or dead face.

Step 6: Create the Other Bodyparts

Remember the duplicate square you created in step 3? We’re going to convert it to a movieclip now. Pay attention to the registration point again.

Make sure you give it the instance name bodypart.

Step 7: Create the Score Field

Create a dynamic text field below the right corner of the snake pit. Make sure you set the variable to score. Also, make sure the field is wide enough for several characters, and aligned to the right. The rest of the settings can be set according to your own style – I used Tahoma 24 Bold.

Step 8: Embedding the Font

Since it’s a dynamic text field, we’ll have to embed the font. Click the embed button in the properties panel (where you just defined the variable and text style).

You’ll see the popup shown below. Make sure you select Numerals [0..9].

Step 9: Create the Food

Draw a blue circle without a border, size 25 x 25, and then erase the center using the eraser tool. Now select the circle that remains and convert it to a movieclip. Alternatively, you can design a piece of food for yourself, as long as it remains 25 x 25.

Step 10: Food Instance Name

Give the food a suprising instance name of food. Double check that its size is 25 x 25.

Step 11: Adding Instructions

Left-below the snake pit seemed like a good place to put some pointers. Simply type the static text “Use the arrow keys to move” here. I know, arrow keys don’t function yet, but we’ll get to that shortly. I promise!

Step 12: Creating the Popup

Draw a white square (somewhere outside the stage, for now) and add the text “You died!” to it. This is the popup we’ll display after someone has lost a game.

Convert it to a movieclip, and give it the instance name popup as well. For alignment purposes, I’ve set the registration point to the center.

Step 13: Score

Double click on the popup you just created to enter it. Once inside it, create a dynamic text field (variable = score) and a button reading the text Play Again.

The button should be given the instance name againbutton.

Inside the button, you can create a slightly darker “Over” and even darker “Down” state.

Congratulations, you have created all the visual objects required for the snake game. Now over to the code!

Step 14: newgame Function

Before I throw a chunk of code at you, I’ll tell you what to do with it. All the code in this tutorial goes on the first and only frame of your movie. No need to attach it to buttons or anything. Now, have a look at this piece of ActionScript.

Editor’s Note: Sorry about this folks, the code syntax highlighter doesn’t want to display this particular chunk of ActionScript in FireFox. Take a look at the code here.

In a nutshell, this bit of code does the following. First, the original bodypart is made invisible – we’ll use duplicates soon. Some default values are (re)set, any duplicates left from the previous game are deleted. In the do { } while() loop, the food and bodypart0 (the head) are given an x and y coordinate. If this matches (so they are at the exact same spot), they are given a new coordinate, until we no longer have a match. Then, the arrays are set up in which we’ll contain the bodyparts’ x and y coordinates.

Step 15: Grabbing the Direction

In this bit of code, we create a keyListener object, which we attach to Key, which represents the keyboard. Whenever a key is pressed, the onKeyDown function is triggered. From the getCode() function, we’ll derive which key was pressed and then define the direction according to this. We’ll store this in the direction variable for later use. Remember: all the code of this tutorial goes on the first and only frame of your movie.

		keyListener = new Object();
		keyListener.onKeyDown = function () {
			keycode = Key.getCode()
			if (keycode == 37) {
				direction = 'left'
			}
			else if (keycode == 38) {
				direction = 'up'
			}
			else if (keycode == 39) {
				direction = 'right'
			}
			else if (keycode == 40) {
				direction = 'down'
			}
		};
		Key.addListener(keyListener);
		

Step 16: onEnterFrame Function

The function down here is a big one. It’s executed on every frame, but only really does something every 5 frames. It checks if the snake isn’t moving outside the box, and then moves all the bodyparts along to their new position. It then checks if the food is there too, and then eats it using the eat() function we’ll discuss later. Then, it checks if the snake is smashing into a wall, and lastly it checks if the snake bites itself in the tail. All these functions will be added soon (insideSnake(), dead(), etcetera). Remember: all the code of this tutorial goes on the first and only frame of your movie.

		this.onEnterFrame = function () {
			if (game) {
				if (framecount/5 == Math.ceil(framecount/5)) {
					if (!(bodypart0._y <= snakepit._y && direction == 'up') && !(bodypart0._y+bodypart0._height >= snakepit._y+snakepit._height-2 && direction=='down') && !(bodypart0._x+bodypart0._width >= snakepit._x+snakepit._width - 2 && direction =='right') && !(bodypart0._x <= snakepit._x && direction == 'left'))
					{
						bodypartsy[0] = bodypart0._y;
						bodypartsx[0] = bodypart0._x;
						for (i=bodypartsy.length-1;i > 0; i--) {
							eval('bodypart'+i)._y = bodypartsy[(i-1)]
							eval('bodypart'+i)._x = bodypartsx[(i-1)]
							bodypartsy[i] = eval('bodypart'+i)._y
							bodypartsx[i] = eval('bodypart'+i)._x
						}
					}
					if (food._x == bodypart0._x && food._y == bodypart0._y) {
						eat()
					}
					if (direction) {
						if (direction == 'up') {
							if (bodypart0._y <= snakepit._y) {
								dead()
							}
							else {
								bodypart0._y-= bodypart0._width
							}
						}
						else if (direction == 'down') {
							if (bodypart0._y+bodypart0._height >= snakepit._y+snakepit._height-2) {
								dead()
							}
							else {
								bodypart0._y+= bodypart0._width
							}
						}
						else if (direction == 'right') {
							if (bodypart0._x+bodypart0._width >= snakepit._x+snakepit._width - 2) {
								dead()
							}
							else {
								bodypart0._x+= bodypart0._width
							}
						}
						else if (direction == 'left') {
							if (bodypart0._x <= snakepit._x) {
								dead()
							}
							else {
								bodypart0._x-= bodypart0._width
							}
						}
					}
					if (game) {
						if (insideSnake(bodypart0._x,bodypart0._y,true)) {
							dead()
						}
					}
				}
				framecount++
			}
		}
		

Step 17: dead() Function

This one’s nice and easy. It executes the actions that need to be taken when the snake dies: the score needs to be defined in the popup, the popup shown, the snake’s dead-face shown and the game-variable set to false (as the game ended).

		function dead() {
			popup.score = 'score: '+(bodypartsx.length-1)
			popup.swapDepths(this.getNextHighestDepth())
			popup._visible = true
			bodypart0.gotoAndStop(2)
			game = false;
		}
		

Step 18: eat() Function

The function below is triggered in the onEnterFrame function we discussed earlier, when the food is picked up. It first duplicates a part of the snake’s body, then positions it at the spot of the last bodypart (so that it’ll join in the line on the next frame). Its coordinates are added to the coordinate containing arrays, and the food is repositioned (somewhere not inside the snake!). Also, the score is updated.

		function eat() {
			duplicateMovieClip(bodypart,'bodypart'+bodypartsy.length,this.getNextHighestDepth())
			bodypart0.swapDepths(this.getNextHighestDepth())
			eval('bodypart'+bodypartsy.length)._y = eval('bodypart'+(bodypartsy.length-1))._y
			eval('bodypart'+bodypartsx.length)._x = eval('bodypart'+(bodypartsy.length-1))._x
			bodypartsy.push(eval('bodypart'+bodypartsy.length)._y)
			bodypartsx.push(eval('bodypart'+bodypartsx.length)._x)
			do {
				food._x = snakepit._x + Math.floor(((snakepit._width-food._width)/food._width)*Math.random())*food._width
				food._y = snakepit._y + Math.floor(((snakepit._height-food._height)/food._height)*Math.random())*food._height
			} while(insideSnake(food._x,food._y));
			score = bodypartsx.length-1
		}
		

Step 19: insideSnake() Function

This function merely checks if the inputted coordinates match any of the coordinates of the snake’s bodyparts. If skiphead is set to true, it is allowed to match the head’s coordinates (when checking if the head bites its tail, this comes in handy).

				function insideSnake(xneedle, yneedle,skiphead) {
			if (skiphead) { startat = 1; }
			else { startat = 0; }
			for (q=startat; q<bodypartsx.length; q++) {
				if (bodypartsx[q] == xneedle) {
					if (bodypartsy[q] == yneedle) {
						return true;
					}
				}
			}
			return false;
		}
		

Step 20: The Popup Button

As a last bit of code; we still have to add an on-release function to the button inside the popup! It’ll trigger the newgame() function we discussed earlier, when clicked. Remember: all the code of this tutorial goes on the first and only frame of your movie – including this bit about the button!

		popup.againbutton.onRelease = function() {
			newgame()
		}
		

Step 21: Wrapping it All Up

I’m sure you’ve done this before, but now is the time: hit Ctrl+Enter (or Cmd+Enter on a Mac) to compile the swf file and test your game. It should now be fully functional. Enjoy!

Conclusion

If you made it all the way here; congratulations! You created quite an addictive game, in AS2! Of course, a game is never finished. There is always room for creative improvement.

If you have any questions or suggestions, feel free to comment below. Also, I’m quite curious to see files produced as a result of this tutorial – I’d love to see a link in the comments!

Thanks for reading my tutorial. I hope you enjoyed it as much as I did.

Related Posts

Add Comment

Discussion 49 Comments

  1. design in a box says:

    looks good, but why AS2 instead of AS3?

  2. ThE_OwNeR says:

    Dutch:

    Erg vet man :D Tof dat ook Nederlanders iets bijbrengen aan Tuts :) Op welke school zit jij?

    English:

    Awesome! :D Really cool that we, the Dutch, also contribute to Tuts!

  3. Raoul says:

    Héhé, remember my first cellular phone ^^

  4. Tanja says:

    Oh, great! Finally some as2! Thank you!

  5. freed says:

    AS2 still rocks!

  6. Franco Rojas says:

    jajaja, esta genial llege hasta el 34 :D

  7. JC says:

    Wow nice and simple. THX!

  8. fatih says:

    that’s great but it would be better in as3

  9. Thi is better than the old mobile snake Game :) :) :)

  10. Bloody Mary says:

    old game idea and concept and the worst it’s AS2.

  11. lawrence77 says:

    My score is 33 only :(

  12. Bert says:

    Why AS2 :(

    • Ian Yates says:

      For those of you who don’t like the AS2 choice, sorry, but it’s not something that you have to put up with often. This was a (pretty cool) one-off for all those who follow Activetuts+ but haven’t yet jumped to AS3.

      Rest assured that we have some great AS3 content coming up in the new year.

      Happy 2010 everyone!

    • mrn says:

      Becouse i HATE AS3

      :p

  13. IamFace says:

    Nice. I like his mad face when you die haha

  14. Good tutorial, it doesn’t matter is’t as2, it can easily be turned to as3 !

  15. Karyl says:

    Dammit! I only got to 32 points!

  16. coder says:

    wondering why you guys are even bothering to post as2 articles. seriously? way to encourage people to stay behind the times.

  17. Petsenwerfer says:

    Is there a way to buffer the keystrokes? Because I always die when I try in a fast sequence up->left… seems like eating my tail.

    P.S. I’m a PHP programmer… I was just browsing the active.tutsplus.com

  18. brodie says:

    i cant open step 14 it says i dont have the program?

  19. jessie says:

    hi!

    I need help! I keep on getting this error message when I play the game:

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 9: Unexpected ‘gt’ encountered
    for (i=bodypartsy.length-1;i > 0; i–) {

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 11: Unexpected ‘}’ encountered
    }

    Total ActionScript Errors: 2 Reported Errors: 2

    any ideas on how to fix this?

  20. Teo says:

    Why do :

    if (framecount/5 == Math.ceil(framecount/5)) {…

    when you can check by :

    if (framecount % 5 == 0) {…

    ?

    It’s not wrong, it just seemed weird.

  21. Ranjit says:

    Vow.. Amazing… Thanks for sharing

  22. flixxor says:

    AS3 ftw!

    Why do you have to use AS2??? :o Easier is not a reason!

  23. LightBringer says:

    Hi, I know I’m kinda retarded LOL, maybe you can help me with this…. i’ve work with random spawn mc over grids and i always fail at some point, so i draw a 25×25 grid across the whole snakepit and try the food part of your code and I seems to have the same problem as the last time i try something like that, the distance between the “food” and the space on the grid seems to grow as it gets far from the left top corner, if someone could tell me what cause this it would be great
    I just use this at 2fps:

    onEnterFrame = function () {
    food._x = snakepit._x + Math.floor(((snakepit._width-food._width)/food._width)*Math.random())*food._width;
    food._y = snakepit._y + Math.floor(((snakepit._height-food._height)/food._height)*Math.random())*food._height;

    bodypart._x = snakepit._x + Math.floor(((snakepit._width-food._width)/food._width)*Math.random())*food._width;
    bodypart._y = snakepit._y + Math.floor(((snakepit._height-food._height)/food._height)*Math.random())*food._height;
    }

    thanks… I’m an idiot

  24. jink says:

    top score 42!

  25. andrew says:

    this is a pretty good example in actionscript 2, right now I need to write actionscript 2, surf the website but there are too many actionscript3 exmaple only.

  26. ^^ says:

    still some bugs in that game..
    why u can go to left .. while u are going to the right?
    and than u die ..
    u have to disable the oppesite key :>
    so:
    # if (keycode == 37 && direction = !”right”) {
    # direction = ‘left’
    # }

  27. Bart says:

    Thanks, cool tut!

    Very nice and inspiring, keep up the good work!

  28. shiv says:

    hey i like this tut thanks i am learning as it really helped me thanks

  29. Ron says:

    um… how can i fix this error?

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 98: Statement block must be terminated by ‘}’
    function insideSnake(xneedle, yneedle,skiphead) {

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 111: Syntax error.
    }

    Total ActionScript Errors: 2 Reported Errors: 2

  30. Pete says:

    How can i fix this error?

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 98: Statement block must be terminated by ‘}’
    function insideSnake(xneedle, yneedle,skiphead) {

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 111: Syntax error.
    }

    Total ActionScript Errors: 2 Reported Errors: 2

  31. John Front says:

    I’ve pasted the whole code in my first frame…but nothing happens!
    No score,snake’s head,body and the food lies outside the pit…
    Any ideas?

    • Jack says:

      I’ve pasted the whole code in my first frame…but nothing happens!
      No score,snake’s head,body and the food lies outside the pit…
      Any ideas?

  32. potatojim says:

    mine isnt working at all either :/

  33. nathan says:

    There is a flaw in this script somewhere. It doesn’t work and im not about to try and figure it out i dont know enough about actionscript to do so.

    • anon says:

      check if you have the instance of the snake pit labelled to “snakepit” on the properties tab. Mine didn’t work coz of this

  34. Chad says:

    I have walked through all steps and backtracked to verify I havn’t missed anything I am recieving this error when I try to view the swf.

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 9: Unexpected ‘gt’ encountered
    for (i=bodypartsy.length-1;i > 0; i–) {

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 11: Unexpected ‘}’ encountered
    }

    Total ActionScript Errors: 2 Reported Errors: 2

    Any Ideas???

  35. Davin says:

    how many layer i have to make?

Add a Comment