# Frogger game in Actionscript 3

I am creating a Frogger game in Flash AS3 and just wanted to see if anyone can help me improve it without breaking the game.

The reason I ask for it because I don't have any errors, but I do get over 50 of these:

Warning: 3596: Duplicate variable definition.

package {

import flash.display.*;
import flash.events.*;
import flash.ui.*;

public class Frogger extends MovieClip
{
private var life, timeElapsed, totalTimer:Number;
private var p1speedX, p1speedY:Number;
private var gotoWin, gotoLose, standingOnLog:Boolean;
private var logs, Trucks, homes, logsYPos, TrucksYPos:Array;

{
stop();
}

public function startWin()
{
}

public function startLose()
{
}

public function startGame()
{
timeElapsed = 0;
totalTimer = 60;
life = 3;
p1speedX = 0;
p1speedY = 0;
gotoWin = false;
gotoLose = false;
standingOnLog = false;
Trucks = new Array();
logs = new Array();
homes = new Array();
logsYPos = new Array(115,165,215,265);
TrucksYPos = new Array(365,415,465,515);

setupGame();

stage.focus = this;

for (var i=1; i<=3; i++)
{
var newTruck = new Truck();
newTruck.x = -300 * i;
newTruck.y = TrucksYPos[0];
newTruck.speedX = 5;
Trucks.push(newTruck);
}

for (var i=1; i<=1; i++)
{
var newTruck = new Truck();
newTruck.x = (170 * i) + 500;
newTruck.y = TrucksYPos[1];
newTruck.speedX = -25;
Trucks.push(newTruck);
}

for (var i=1; i<=4; i++)
{
var newTruck = new Truck();
newTruck.x = (-220 * i) + 100;
newTruck.y = TrucksYPos[2];
newTruck.speedX = 8;
Trucks.push(newTruck);
}

for (var i=1; i<=2; i++)
{
var newTruck = new Truck();
newTruck.x = (200 * i) + 350;
newTruck.y = TrucksYPos[3];
newTruck.speedX = -5;
Trucks.push(newTruck);
}

for (var i=1; i<=4; i++)
{
var newLog = new LogWood();
newLog.x = -300 * i;
newLog.y = logsYPos[0];
newLog.speedX = 5;
logs.push(newLog);
swapChildren(mcP1,newLog);
}

for (var i=1; i<=2; i++)
{
var newLog = new LogWood();
newLog.x = (170 * i) + 500;
newLog.y = logsYPos[1];
newLog.speedX = -5;
logs.push(newLog);
swapChildren(mcP1,newLog);
}

for (var i=1; i<=2; i++)
{
var newLog = new LogWood();
newLog.x = (-220 * i) + 100;
newLog.y = logsYPos[2];
newLog.speedX = 14;
logs.push(newLog);
swapChildren(mcP1,newLog);
}

for (var i=1; i<=3; i++)
{
var newLog = new LogWood();
newLog.x = (250 * i) + 400;
newLog.y = logsYPos[3];
newLog.speedX = -5;
logs.push(newLog);
swapChildren(mcP1,newLog);
}
}

private function setupGame()
{

for (var i=0; i< MovieClip(root).numChildren; i++)
{
var object = MovieClip(root).getChildAt(i);

if (object is Home)
{
homes.push(object);
}}}

private function gotoStartGame(evt:MouseEvent)
{
btnStartGame.removeEventListener(MouseEvent.CLICK, gotoStartGame);
gotoAndStop("game");
}

{
}

private function keyDownHandler(evt:KeyboardEvent)
{
if (evt.keyCode == Keyboard.LEFT)
{
p1speedX = -1;
}
else if (evt.keyCode == Keyboard.RIGHT)
{
p1speedX = 1;
}

if (evt.keyCode == Keyboard.UP)
{
p1speedY = -1;
}
else if (evt.keyCode == Keyboard.DOWN)
{
p1speedY = 1;
}
}

private function keyUpHandler(evt:KeyboardEvent)
{
if ((evt.keyCode == Keyboard.LEFT) || (evt.keyCode == Keyboard.RIGHT))
{
p1speedX = 0;
}
if ((evt.keyCode == Keyboard.UP) || (evt.keyCode == Keyboard.DOWN))
{
p1speedY = 0;
}
}

public function update(evt:Event)
{
handleUserInput();
handleGameLogic();
handleDraw();

if (gotoWin)
triggerGoToWin();
else if (gotoLose)
triggerGoToLose();
}

private function handleUserInput()
{
if (p1speedX > 0)
{
if (mcP1.x + 50 < 800)
mcP1.x += 50;

p1speedX = 0;
mcP1.rotation = 90;
mcP1.play();
}
else if (p1speedX < 0)
{
if (mcP1.x - 50 > 0)
mcP1.x -= 50;
p1speedX = 0;
mcP1.rotation = -90;
mcP1.play();
}

if (p1speedY < 0)
{
mcP1.y -= 50;

p1speedY = 0;
mcP1.rotation = 0;
mcP1.play();
}
else if (p1speedY > 0)
{
if (mcP1.y + 50 < 600)
mcP1.y += 50;
p1speedY = 0;
mcP1.rotation = -180;
mcP1.play();
}
}

private function handleGameLogic()
{
timeElapsed++;

for (var i=Trucks.length-1; i>= 0; i--)
{
Trucks[i].x += Trucks[i].speedX;

if (Trucks[i].hitTestPoint(mcP1.x,mcP1.y))
{
life--;
resetGame();
}

if (Trucks[i].speedX < 0 && Trucks[i].x <= -50)
{
Trucks[i].x = 850;
}
else if (Trucks[i].speedX > 0 && Trucks[i].x >= 850)
{
Trucks[i].x = -50;
}
}

var standingOnLog = false;
for (var i=logs.length-1; i>= 0; i--)
{
logs[i].x += logs[i].speedX;
if (logs[i].hitTestPoint(mcP1.x,mcP1.y))
{
standingOnLog = true;
mcP1.x += logs[i].speedX;
}

if (logs[i].speedX < 0 && logs[i].x <= -50)
{
logs[i].x = 850;
}
else if (logs[i].speedX > 0 && logs[i].x >= 850)
{
logs[i].x = -50;
}
}

for (var i in homes)
{
if (homes[i].hitTestObject(mcP1))
{
homes[i].gotoAndStop("occupied");
mcP1.x = 400;
mcP1.y = 565;
}
}

if (mcP1.y < 290)
{
if (!standingOnLog)
{
life--;
resetGame();
}
}

if ((totalTimer - Math.floor(timeElapsed/30) <= 0) ||
(life <= 0))
gotoLose = true;

var allOccupied = true;
for (var i in homes)
{
if (homes[i].currentLabel == "empty")
allOccupied = false;
}
if (allOccupied)
gotoWin = true;
}

private function handleDraw()
{
txtTime.text = String(totalTimer - Math.floor(timeElapsed/30));
txtLife.text = String(life);
}

private function clearGame()
{
for (var i=Trucks.length-1; i>= 0; i--)
{
removeChild(Trucks[i]);
Trucks.splice(i,1);
}

for (var i=logs.length-1; i>= 0; i--)
{
removeChild(logs[i]);
logs.splice(i,1);
}
}
private function triggerGoToWin()
{
clearGame();
removeEventListener(Event.ENTER_FRAME, update);
gotoAndStop("win");
}

private function triggerGoToLose()
{
clearGame();
removeEventListener(Event.ENTER_FRAME, update);
gotoAndStop("lose");
}

private function resetGame()
{
mcP1.x = 400;
mcP1.y = 565;
}
}
}


It is just a warning. The source of the warnings is that you redeclare the same variable newTruck:Truck numerous times in your startGame function as well as newLog:LogWood.

It's just a warning, because it is ok to do so. The reason it warns you is that it might not be your intention to do so, therefore helping you out.

If you want to get rid of those, you can declare the variables once in startGame before the loops like this:

var newTruck:Truck;


and then just reuse them in your loops, for example:

newTruck = new Truck();


To be consistent with your variable names, I would rename Trucks to lowercase trucks.

You have several for-loops that are very similar, for creating Trucks and LogWoods. Consider creating a function createTruck(x, y, speed); the implementation could also take care of adding the truck to the corresponding Array and adding the child to the MovieClip. That way, you could rewrite a for-loop like this:

    for (var i=1; i<=2; i++)
{
createTruck(200 * i) + 350, trucksYPos[3], -5);
}


And by doing this you also don't need the newTruck variable, as that will only exist within the createTruck function.

Instead of using the type Array, I suggest you use the Vector class which has the advantage of being typed so it only allows adding objects of a specific type. This has a significant compile-time advantage since it allows for better type-checking but it has a run-time disadvantage. (Although I don't think you need to be worried about the run-time disadvantage)

I am curious about how you use your startWin and startLose methods. I assume they're being called from a timeline somewhere. All they do is to add an event listener for the click of a button. Of course this is important, but should it have it's own method? Especially considering they do the exact same thing it feels strange. As soon as your btnBack exists (is not null), add the event listener, and do it only once. I don't see the need for two separate methods.

Using a switch-statement in your keyDownHandler method would reduce your line count and improve the readability of your code.

    switch (evt.keyCode) {
case Keyboard.LEFT:
p1speedX = -1;
break;
case Keyboard.RIGHT:
p1speedX = 1;
break;
case Keyboard.UP:
p1speedY = -1;
break;
case Keyboard.DOWN:
p1speedY = 1;
break;
}

• Although commonly thought otherwise, the real performance benefits in using Vectors is with int, uint, and Number. See this link for details on that aspect - stackoverflow.com/questions/8551527/as3-vector-of-arrays/… When dealing with non-primitive number types such as in this code, you aren't going to get the advantage most would suspect. The stronger typing is a compile time benefit, not run-time performance in this case. – prototypical Nov 18 '13 at 22:30
• @prototypical I didn't say it was a run-time performance benefit. I mostly prefer Vector just because of the compile time benefit. (This is actually one of the reasons I prefer the Java language, there are so many errors that are caught in compile-time rather than run-time, but that's a different topic) – Simon Forsberg Nov 18 '13 at 22:35
• Yeah, I agree, was mostly trying to give more clarity to the benefits of Vector vs Array. I do agree the compile-time advantages are worthy of note. I wasn't trying to say you were wrong, but rather just point to more on the topic of differences. – prototypical Nov 18 '13 at 22:38
• @prototypical And I'm glad you gave me the information about the run-time performance difference. I actually did not know that. I will update my answer with some of the information in these comments. – Simon Forsberg Nov 18 '13 at 22:46
• I think the run-time disadvantage is rather negligible myself. I tend to use Vectors mostly. However, there are some situations where I want to store multiple types, and in that case I choose an Array. When I discovered the performance aspect, my Vectors for game entities suddenly felt slower, haha :) Whereas before I felt like I was heavily optimizing by switching! – prototypical Nov 18 '13 at 23:02

Those errors come if you declare the same variable more then once within the same scope, your loops are declaring i as a new variable each time, you should put those different loops into different functions to perform the action required or use some kind of loop variable if you must do it this way...

private var loopVar:int = 0;

for(loopVar = 0; loopVar < 3; loopVar++)
for(loopVar = 0; loopVar <= secondLoopValue; loopVar++)


Not the best option but this will remove those errors because i wont be declared over and over, also quicker to reuse a variable rather then declare a new one (I think).

Just don't have more then one loop in any function or get use to those errors, the second option works for me sometimes ;) reminds me I still have work to do at the end of the project.