Do you like my tutorials?

Then consider supporting me on Ko-fi

Talking about Plants Vs Zombies game, Actionscript 3, Flash and Game development.

As promised in fully explaining a PopCap game post, here we go with Plants Vs Zombies.

I have to say I am not a great PvZ player (shame on me), so if you notice something wrong during the series, let me know.

Defining the main structure of the game

PopCap did a great look and feel job with PvZ as defending your house from brain eater zombies has a great appeal… and all in all killing zombies is fun, as confirmed by blockbuster like Resident Evil, Left 4 Dead and Dead Rising. But this has nothing to do with the gameplay, which could be Butchers Vs Plumbers, Pigeons Vs Camels or Circles Vs Squares.

During the series, good circles will prevent evil squares to get to the base. Also, the structure of the game field can be simplified in a tile based game.

Take this situation:

And try to imagine it this way:

What we have is a plant on (2,2) ready to stop a zombie walking on row 2, another zombie approaching on row 3 and a sun falling through column 4. There can’t be another plant on (2,2), and a new zombie never appear between row 2 and 3.

Again, bow to PopCap for making you believe this was the hardest game to code.

Creation of the game field

As you can see in the above picture, the game field is a 5 rows x 9 columns matrix, so the first thing is defining an array with the same properties. I assume your fla file has a document class called Main. So this is the content of Main.as:

package {
	import flash.display.Sprite;
	public class Main extends Sprite {
		private var gameField:Array;
		public function Main():void {
			setupField();
		}
		private function setupField():void {
			gameField=new Array();
			for (var i:uint=0; i<5; i++) {
				gameField[i]=new Array();
				for (var j:uint=0; j<9; j++) {
					gameField[i][j]=0;
				}
			}
		}
	}
}

At the end of the script gameField array contains the 5x9 matrix.

Drawing the game field

This is more for a debug purpose, anyway we are going to draw the game field. I am using some rectangles drawn on the fly with drawRect method and filled with a random green.

package {
	import flash.display.Sprite;
	public class Main extends Sprite {
		private var gameField:Array;
		public function Main():void {
			setupField();
			drawField();
		}
		private function setupField():void {
			gameField=new Array();
			for (var i:uint=0; i<5; i++) {
				gameField[i]=new Array();
				for (var j:uint=0; j<9; j++) {
					gameField[i][j]=0;
				}
			}
		}
		private function drawField():void {
			var fieldSprite:Sprite=new Sprite();
			var randomGreen:Number;
			addChild(fieldSprite);
			fieldSprite.graphics.lineStyle(1,0xFFFFFF);
			for (var i:uint=0; i<5; i++) {
				for (var j:uint=0; j<9; j++) {
					randomGreen=(125+Math.floor(Math.random()*50))*256;
					fieldSprite.graphics.beginFill(randomGreen);
					fieldSprite.graphics.drawRect(25+65*j,80+75*i,65,75);
				}
			}
		}
	}
}

What drawField function does could have been done directly in setupField function, but I wanted to keep things separate for a tutorial purpose. The only interesting line is the random green color generation between #007D00 and #00AE00 at line 25.

This is our game field. If you want to draw decent tiles, let me know

Catching suns

Suns are PvZ's currency. They fall from the sky and land on a square. Picking them up, the player can buy plants.

We are using a timer event to drop a sun every five seconds. Refer to understanding AS3 Timer class if you aren't familiar with it.

At the moment suns don't fall down from the sky but just appear in a random tile. At the moment, I don't know if two suns can land on the same tile. In this example they can, but if the original game does not allow it just let me know.

When a sun is on the ground, it can be picked up by the player. A mouse event listener handles the whole process. This is the script:

package {
	import flash.display.Sprite;
	import flash.utils.Timer;
	import flash.events.TimerEvent;
	import flash.events.MouseEvent;
	public class Main extends Sprite {
		private var gameField:Array;
		private var flowersTimer:Timer=new Timer(5000);
		private var sun:sunMc;
		private var sunContainer:Sprite=new Sprite();
		public function Main():void {
			setupField();
			drawField();
			fallingSuns();
		}
		private function fallingSuns():void {
			addChild(sunContainer);
			flowersTimer.start();
			flowersTimer.addEventListener(TimerEvent.TIMER, newSun);
		}
		private function newSun(e:TimerEvent):void {
			var sunRow:uint=Math.floor(Math.random()*5);
			var sunCol:uint=Math.floor(Math.random()*9);
			sun = new sunMc();
			sunContainer.addChild(sun);
			sun.x=52+sunRow*65;
			sun.y=130+sunRow*75;
			sun.addEventListener(MouseEvent.CLICK,sunClicked);
		}
		private function sunClicked(e:MouseEvent):void {
			e.currentTarget.removeEventListener(MouseEvent.CLICK,sunClicked);
			var sunToRemove:sunMc=e.currentTarget as sunMc;
			sunContainer.removeChild(sunToRemove);
		}
		private function setupField():void {
			gameField=new Array();
			for (var i:uint=0; i<5; i++) {
				gameField[i]=new Array();
				for (var j:uint=0; j<9; j++) {
					gameField[i][j]=0;
				}
			}
		}
		private function drawField():void {
			var fieldSprite:Sprite=new Sprite();
			var randomGreen:Number;
			addChild(fieldSprite);
			fieldSprite.graphics.lineStyle(1,0xFFFFFF);
			for (var i:uint=0; i<5; i++) {
				for (var j:uint=0; j<9; j++) {
					randomGreen=(125+Math.floor(Math.random()*50))*256;
					fieldSprite.graphics.beginFill(randomGreen);
					fieldSprite.graphics.drawRect(25+65*j,80+75*i,65,75);
				}
			}
		}
	}
}

And a brief recap of the function used:

drawField: phyisically drawing the field

fallingSuns: setting up the suns to make them fall

newSun: creation of a new sun

setupField: preparing the field array

sunClicked: called when the player clicks on a sun

This is the result:

Pick up suns with the mouse.

Download the source code of the latest example. Next time, we'll add smooth animation to falling suns and we will buy our first plant.

Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.