package
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.Shape;
import flash.events.Event;
import flash.geom.Point;
/**
* Tower Defense Game v 0.1.2
* Source: http://www.flashgametuts.com/tutorials/as3/how-to-create-a-tower-defense-game-in-as3-part-3/
* @author
*/
public class Game extends MovieClip
{
// Game State Constants
public static const STATE_INIT:int = 10;
public static const STATE_TITLESCREEN:int = 15;
public static const STATE_NEWLEVEL:int = 20
public static const STATE_PLAY:int = 25;
public static const STATE_SHOWSCORE:int = 30;
public static const STATE_GAMEOVER:int = 35;
public static const HITPOINTS_TOTAL:int = 1;
public static const NUM_ENEMIES:int = 10;
public static const ENEMY_SPEED:int = 55;
public static const ENEMY_SPAWN_RATE:int = 24;
// Game Map Constants
public static const MAP_COLS:int = 22;
public static const MAP_ROWS:int = 12;
public var gameState:int = 0; // Global State variable
public function Game():void
{
gameState = STATE_INIT; // Sets global game state to initialize the game
addEventListener(Event.ENTER_FRAME, gameLoop); // Starts up game loop to be called every ENTER_FRAME
addEventListener(CustomEventTurret.ADD_TURRET, addTurretHandler); // Listens for the Block calling the Add Turret event
}
/**********************************
* LEVEL DEFINING CODE
*/
// Array to hold the first map level and road. Empty Space = 0, Straight Road = 1, Waypoints start from 2 through the end
// This is a bit clunky but a step in the right direction - the goal was to change to a waypoint system rather (vector) rather than a plot graph
private var lvlArray:Array = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,6,1,1,7,0,0,10,1,1,11,0,0,14,1,1,15,0,0,
0,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,
0,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,
2,3,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,16,1,17,
0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,
0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,
0,4,1,1,5,0,0,8,1,1,9,0,0,12,1,1,13,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
];
private var lvlMinWaypoint:int = 2;
private var lvlMaxWaypoint:int = 17; // Necessary to pre-index our travelPath array
// ********************************
// Difficulty Settings
private var enemySpeed:int = 0; // Holds the default level speed (should probably move into a level settings object
private var enemySpawnRate:int = 0; // Holds default speed which enemies spawn, deterimes wait time between enemies
// Current Level Settings
private var currentLevel:int = 0; // Current level that the game is presently playing.
private var enemyFrameCounter:int = 0; // Counter to check spawn and wave rates
private var blockModel:Array = []; // Model array to hold all tiles
private var enemiesModel:Array = []; // Model array to hold all visible enemies
private var travelPath:Array = []; // Array of Point obects which represent the path the enemies will take
private var numEnemies:int; // Max number of enemies in the level
private var incomingCount:int; // Test if we have reached the max number of enemies
private var score:int = 0; // User's kill score
private var tempEnemy:Enemy; // We evaluate from our enemies array frequently so having a global enemy prevents having to allocate the variable
private var tempTurret:Turret; // We evaluate from our turrets array (global turret)
private var tempBullet:Bullet;
private var turretsModel:Array = []; // Holds any turrets that the player has created
private var bulletsModel:Array = [];
public function startGame():void{ // We'll run this function every the game begins.
currentLevel = 0;
gameState = STATE_TITLESCREEN; // Game has been initialized, show the title screen on next game loop pass
}
public function showTitleScreen():void {
// TODO: Show Title Screen and make it clickable to start the game
gameState = STATE_NEWLEVEL; // User has clicked off the title screen, start the new level on the next game loop pass
}
public function startLevel():void{ // We'll run this function every a level begins.
blockModel = []; // Initialize or empty the arrays for the new level
enemiesModel = [];
travelPath = new Array(lvlMaxWaypoint - lvlMinWaypoint + 1); // Create a new travelPath array with empty indeces equal to the total number of waypoints
enemyFrameCounter = 0; // Set all level variables to 0s
numEnemies = 0;
incomingCount = 0;
score = 0;
makeRoad(); // Create the level map
getLevelSettings(); // Initialize the global settings for the current level
gameState = STATE_PLAY; // Game is ready for the main game loop
}
public function getLevelSettings():void
{
numEnemies = NUM_ENEMIES;
enemySpeed = ENEMY_SPEED;
enemySpawnRate = ENEMY_SPAWN_RATE;
}
public function makeRoad():void {
var col:int = 0;
var row:int = 0; // Locational variable for rows
var block:Block;
var x:int = 0;
var y:int = 0;
var p:Point; // Point objects hold x and y coordinates and have functions to test the distance between two points
// This temporary point object will be added to as waypoints travelPath array
for (var i:int = 0; i < lvlArray.length; i++) { // Loop through the Level Array and create the Blocks
x = (i - row * 22) * 25;
y = row * 25;
if (lvlArray[i] >= lvlMinWaypoint) // If it is a waypoint block add it to travelPath
{
p = new Point(x, y); // Instantiate a Point object
travelPath[lvlArray[i] - lvlMinWaypoint] = p; // Add the Point to the travelPath array at the index location specified by the lvlArray map
// (subtract lvlMinWaypoint since arrays start at 0 not 2 in this case)
}
block = new Block(lvlArray[i],x,y); // Instatiate a new block
addChild(block); // Adds the Block (which is an empty MovieClip) to the stage
block.render(); // Calls the block's render function which draws the rectangle
blockModel.push(block); // Store our new block in the model array
col++; // Each time we add a block is a new column
if (col == MAP_COLS) // Increment the row each time col reaches the end
{
row++;
col = 0;
}
}
}
public function addTurretHandler(event:CustomEventTurret):void
{
makeTurret(event.block.x, event.block.y);
event.block.turretAdded();
}
// Creates a new Turret object at x and y and inserts it into the turretsModel array
public function makeTurret(xValue:int,yValue:int):void {
var turret:Turret = new Turret(); // Temporary variable to create the new Turret
turret.x = xValue + 12.5; // Set the coordinates to the middle of the object hence the + 12.5
turret.y = yValue + 12.5;
turretsModel.push(turret); // Add it to our model
addChild(turret); // Add it to the stage
}
// Game loop code from Week 3 lab - stores current game mode and is called every ENTER_FRAME
public function gameLoop(e:Event):void {
switch(gameState) { // gameState is a global variable which holds the current game mode
case STATE_INIT :
initGame(); // Start a new game
break;
case STATE_TITLESCREEN:
showTitleScreen(); // Doesn't currently do anything except advance the state
break;
case STATE_NEWLEVEL:
startLevel(); // Sets up current level variables
break;
case STATE_PLAY:
playGame(); // Game is currently playing
break;
case STATE_SHOWSCORE:
break;
case STATE_GAMEOVER:
gameOver(); // Run the game over code
break;
}
}
public function initGame():void
{
startGame();
}
public function playGame():void // Main game loop
{
checkEnemies(); // Checks if we need to add any new enemies
update(); // Calls all visible objects that need to update
cleanUpEnemies() // Check collisions or if any enemies made it to the end
render(); // Calls all visible objects that need to render
}
public function update():void
{
for each (tempEnemy in enemiesModel)
{
tempEnemy.update();
}
for each(tempTurret in turretsModel)
{
//makes sure turrets don't shoot out of range
tempTurret.target = null;
for each (tempEnemy in enemiesModel)
{
var distance:Number = (Math.sqrt(Math.pow(tempEnemy.y - tempTurret.y, 2) + Math.pow(tempEnemy.x - tempTurret.x, 2))); //let's define a variable which will be how far the nearest enemy is
if(distance < tempTurret.range)
{
if (tempTurret.fire(tempEnemy)) {
tempBullet = new Bullet(tempTurret.x, tempTurret.y, tempEnemy);
addChild(tempBullet);
bulletsModel.push(tempBullet);
trace("fired");
break;
}
}
}
tempTurret.update();
}
for each(var tempBullet in bulletsModel)
{
var i:int = 0; i < bulletsModel.length; i++
if (tempBullet.hitTarget == true)
{
tempEnemy.adjustHealth(tempBullet.damage);
removeChild(bulletsModel[i]); //Remove it from the stage
bulletsModel.splice(i, 1);
}
}
}
public function render():void
{
for each (tempEnemy in enemiesModel)
{
tempEnemy.render();
}
for each(tempBullet in bulletsModel)
{
tempBullet.update();
tempBullet.render();
}
}
public function checkEnemies():void
{
enemyFrameCounter++; // Increment the counter so we know how many game loop frames have passed for spawn rate and wave delay
if ((enemyFrameCounter >= enemySpawnRate) && (incomingCount < numEnemies)) { // If we've waited long enough and we still have more enemies to spawn
tempEnemy = new Enemy(enemySpeed, Enemy.HIT_POINTS_TOTAL, travelPath); // Create an enemy
addChild(tempEnemy); // Add it to the stage
enemiesModel.push(tempEnemy); // Add it to the Model array
incomingCount++; // Note that we've added a new enemy for this wave
enemyFrameCounter = 0; // Reset the frame timer
}
}
public function cleanUpEnemies():void
{
for (var i:String in enemiesModel) // A For...in Loop - Loop through the enemies array. For...in loops return the index of the item
{
if (enemiesModel[i].finished) // If the enemy got to the end
{
removeChild(enemiesModel[i]); // Remove it from the stage
enemiesModel.splice(i, 1); // Remove it from the array
tempEnemy == null;
if (tempEnemy == null) {
for (var j:int = 0; j < enemiesModel.length; j++) {
tempEnemy = enemiesModel[i];// clean up and find another target
}
}
}
dispose();
}
}
public function dispose():void
{
}
public function gameOver():void {
//gameState = STATE_INIT;
}
}
}