I'm new to ActionScript and I'm confused about these two errors. I already have some prior coding experience from other languages.
Scene 1, Layer 'Actions', Frame 1, Line 78, Column 20 1084: Syntax error: expecting rightparen before colon.
Scene 1, Layer 'Actions', Frame 1, Line 85, Column 20 1084: Syntax error: expecting rightparen before colon.
This is my code.
function moveCharacter(evt:KeyboardEvent):void
{
if (evt.keyCode == Keyboard.RIGHT)
{
eggHead.scaleX = 1; //flip right
eggHead.x += 10;
//cycle through frames
if (eggHead.currentFrame == 9)
{
eggHead.gotoAndStop(2);
}
else
{
eggHead.gotoAndStop(eggHead.currentFrame+1);
}
}
if (evt.keyCode == Keyboard.LEFT)
{
eggHead.scaleX = -1; //flip left
eggHead.x -= 10;
//cycle through frames
if (eggHead.currentFrame == 9)
{
eggHead.gotoAndStop(2);
}
else
{
eggHead.gotoAndStop(eggHead.currentFrame+1);
}
}
}
function timing(evt:TimerEvent):void
{
timeStep += 1; //increment counter
if (run)
{ //only if run = true is shift key has been pressed
moveCharacter(evt:KeyboardEvent)
{
timeStep = 0; //reset the counter
}
}
else if (timeStep == 2)
{
moveCharacter(evt:KeyboardEvent)
{
timeStep = 0; //reset the counter
}
}
}
Lines 78 and 85 are the moveCharacter(evt:KeyboardEvent) function.
I'm not sure where the problem is, I can't see one, unless I'm blind.
The : character has a limited amount of uses in AS3 (most of them are various type declarations):
// Variable declaration.
var a:int;
// Variable declaration within a loop statement.
for (var i:int = 0; i < 10; i++)
{
// ...
}
// Ternary operator.
a = (Math.random() > 0.5)? 1: 0;
// Function declaration (both arguments and return type).
function convert(j:int, k:Number):String
{
return j + "_" + k;
}
// XML NameSpaces.
var x:XML = <soap:Envelope xmlns:soap="http://.../envelope/" />;
This is neither of them, hence the syntax error.
if (run)
{
moveCharacter(evt:KeyboardEvent)
{
timeStep = 0; //reset the counter
}
}
You should probably explain what kind of logic you wanted to code, because it is not clear what are you trying to do here.
The function moveCharacter was being called but you were typing a parameter declaration where the argument goes.
moveCharacter(evt:KeyboardEvent)
Your code doesn't have a keyboard event to pass at this spot. moveCharacter should be refactored to accept either "left" or "right" as arguments so that it doesnt require a keyboard event.
It's inherently unclear which direction the character should be moved from the time function. I assume the moveCharacter function is incomplete and missing forward and backward movement.
function moveCharacter(direction:String):void
{
direction = direction.toLowerCase();
if (direction == "right")
{
eggHead.scaleX = 1; //flip right
eggHead.x += 10;
//cycle through frames
if (eggHead.currentFrame == 9)
{
eggHead.gotoAndStop(2);
}
else
{
eggHead.gotoAndStop(eggHead.currentFrame+1);
}
}
if (direction == "left")
{
eggHead.scaleX = -1; //flip left
eggHead.x -= 10;
//cycle through frames
if (eggHead.currentFrame == 9)
{
eggHead.gotoAndStop(2);
}
else
{
eggHead.gotoAndStop(eggHead.currentFrame+1);
}
}
// TODO: Implement forward and backwards
}
function timing(evt:TimerEvent):void
{
timeStep += 1; //increment counter
if (run)
{ //only if run = true is shift key has been pressed
moveCharacter("forward");
timeStep = 0; //reset the counter
}
else if (timeStep == 2)
{
moveCharacter("forward");
timeStep = 0; //reset the counter
}
}
I want to open all nodes of Flex mx Tree in such a way that UI is responsive at all times. Normally when there are limited no of nodes then this code works just fine.
public function expandAllNodes():void {
for (var i:int = 0; i < this.dataProvider.length; i++) {
expandChildrenOf(this.dataProvider.getItemAt(i), true);
}
}
maybe i need to callLater instead of directly calling the function
public function expandAllNodes():void {
for (var i:int = 0; i < this.dataProvider.length; i++) {
calllater(expandChildrenOf,[this.dataProvider.getItemAt(i), true]);
}
}
but this is not working either.
Using callLater won't help in this case. From the documentation,
The callLater method queues an operation to be performed for the next screen refresh, rather than in the current update.
Using callLater in your loop will simply push all the expandChildrenOf() calls to the next screen refresh -- which will still put way too much work into a single update cycle.
Instead, you could spread your loop over several frames and limit work done per frame:
private var processingLimit:int = 10; //experiment to get a reasonable value for this
private var totalNodes:int = 0;
private var nodesProcessed:int = 0;
public function expandAllNodes():void {
this.totalNodes = this.dataProvider.length;
this.addEventListener(Event.ENTER_FRAME, expandNextNode);
}
private function expandNextNode(e:Event):void {
var numToProcess = Math.min(processingLimit + nodesProcessed, totalNodes);
for (var i:int = nodesProcessed; i < numToProcess; i++) {
nodesProcessed++;
expandChildrenOf(this.dataProvider.getItemAt(i), true);
}
if (numToProcess == totalNodes) {
this.removeEventListener(Event.ENTER_FRAME, expandNextNode);
}
}
n.b. Make sure that expandChildrenOf doesn't recursively open children of children -- if it does, then you could still end up expanding the entire tree based on a single call to expandChildrenOf(1);!
This is how i solved the issue
private const PROCESSING_LIMIT:int = 25;
public var _expandNodesStack:Vector.<Object>;
private function expandNextNode(e:Event):void {
for (var i:int = 0; i < PROCESSING_LIMIT; i++) {
var item:* = _expandNodesStack.pop();
if (item)
expandItem(item, true);
else
break;
}
if (_expandNodesStack.length == 0) {
this.removeEventListener(Event.ENTER_FRAME, expandNextNode);
}
}
public function expandAllNodes():void {
if(this.dataProvider == null || this.dataProvider.length <= 0) return;
if (_expandNodesStack != null && _expandNodesStack.length > 0) {
//already expanding so abort this operation
return;
}
if (_expandNodesStack == null) _expandNodesStack = new <Object>[];
iterateAndPushToStack(this.dataProvider.getItemAt(0));
_expandNodesStack.reverse();
this.addEventListener(Event.ENTER_FRAME, expandNextNode);
}
private function iterateAndPushToStack(item:Object):void {
if (iterator == null)
return;
// if it is not a branch item there's nothing to do
if (item != null && item.children is ArrayCollection && item.children.length > 0) {
_expandNodesStack.push(item);
var childItems:ArrayCollection;
childItems = item.children;
if (childItems) {
for each (var object:Object in childItems) {
iterateAndPushToStack(object);
}
}
}
}
I have the following problem:
I want to keep a score when i "hittest". I use the following code:
private function fnMoveMap():void
{
for (var i:int = 0; i < vPipeMax; i++)
{
var tmpPipe = _conMap.getChildAt(i);
//trace (tmpPipe.name);
if (tmpPipe._HIT.hitTestPoint(_P.x, _P.y, true))
{
tmpPipe.visible = false;
//stage.removeEventListener(Event.ENTER_FRAME, setScore);
vScores++;
txtScores.text = vScores.toString();
//break;
}
//reset pos
if (tmpPipe.x < 0)
{
//stage.addEventListener(Event.ENTER_FRAME, setScore);
tmpPipe.visible = true;
tmpPipe.x = 1050 - vXSpeed;
tmpPipe.y = randomRangeMC(minPipeY, maxPipeY);
//set score
//vScores++;
//txtScores.text = vScores.toString();
}
else
{
tmpPipe.x -= vXSpeed;
}
}
}
the var vScores keeps counts for 4 to 8 times.
How can i just count one?
The reason your vScores variable is incrementing by 4-8 is because you're looping multiple times with the for loop through vPipeMax.
You either need to restructure your code so that doesn't happen, or break out of the loop as soon as you increment the score.
Adobe's documentation on break: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/statements.html#break
I've been attempting to write some logic for a program I have been working on and have run into some difficulty.
Essentially what I'm creating on my stage programmatically is a 4x4 grid (16 blocks), which looks just like this:
The user's task is to plot a contiguous shape onto the grid by clicking on the blocks and their shape should feature no gaps and no diagonally plotted blocks, for example the following would be a legal shape:
However, the following shape wouldn't be and would throw out an error to the user in the form of a pop-up graphic:
The plotting process for the grid is associated with a 4x4 virtual representation of the grid in Boolean Array form and looks like this:
public static var ppnRowArray1:Array = [false,false,false,false];
public static var ppnRowArray2:Array = [false,false,false,false];
public static var ppnRowArray3:Array = [false,false,false,false];
public static var ppnRowArray4:Array = [false,false,false,false];
public static var ppnColumnArray:Array = [ppnRowArray1,ppnRowArray2,ppnRowArray3,ppnRowArray4];
As the user clicks and selects a block, changing the colour property to brown, the relevant boolean property in my 'virtual grid representation' array will change from false to true. If a plot is illegally made then this property is changed back to false and the user is then invited to try their next plot again.
I have managed to write the code which forces the user to plot a legal shape and works out when an illegal plot has been made, but I now need to write the logic for when a user de-selects a block from an existing legal shape, making it non-contiguous and this is where my problem lies.
Here is the working solution as it stands.
//---------------------------------------------------------------------
public static function ppnCountSetCells():int
{
//Count Each 4x4 Grid Cell
var count:int = 0;
for (var row=0; row<=3; row++)
{
for (var col=0; col<=3; col++)
{
if (ppnColumnArray[col][row])
{
count++;
}
}
}
return count;
}
//---------------------------------------------------------------------
public static function ppnBlockValid():Boolean
{
if (ppnCountSetCells() > 1)
{
for (var row=0; row<=3; row++)
{
for (var col=0; col<=3; col++)
{
if (ppnColumnArray[col][row] == true)
{
// Check if we are connected to another set square
var validNeighbours:int = 0;
// Check North
if (row > 0)
{
if (ppnColumnArray[col][row - 1] == true)
{
validNeighbours++;
}
}
// Check South
if (row < 3)
{
if (ppnColumnArray[col][row + 1] == true)
{
validNeighbours++;
}
}
// Check West
if (col > 0)
{
if (ppnColumnArray[col - 1][row] == true)
{
validNeighbours++;
}
}
//-----------------------------------------------------------------------------------------
// Check East
if (col < 3)
{
if (ppnColumnArray[col + 1][row] == true)
{
validNeighbours++;
}
}
//-----------------------------------------------------------------------
if (validNeighbours < 1)
{
return false;
}
//-----------------------------------------------------------------------
}
}
}
}
return true;
}
//---------------------------------------------------------------------
function addBlock(e:MouseEvent):void
{
//trace("You Have Clicked On Grid Block Number: " + e.currentTarget.id);
if (InterfaceButtons.panelOpen == false)
{
//Listen to see if the block click is adjoining and pass back to see if it is valid on the grid
var col:int = (e.currentTarget.id - 1) % 4;
var row:int = (e.currentTarget.id - 1) / 4;
ppnColumnArray[col][row] = true;
addOrRemove = "add";
ppnBlockValid();
//Get the Block Valid Result (True or False) and pass it into a Boolean variable to use later
ppnGridError = ppnBlockValid();
trace("Is This Valid? " + ppnBlockValid());
//----------------------------------------------------------------------------------------------
//Push Blocks Selected into Array
ppnShapeArray[e.currentTarget.id] = true;
trace(ppnShapeArray);
//----------------------------------------------------------------------------------------------
//Add 1 to the block count which directly effects the final outcome depending on ++ or --
ppnBlocksSelected++;
PlantPopNitDesignPlot.ppnPlotMade = false;
//Hide Block to Reveal Brown One
e.currentTarget.alpha = 0;
//-----------------------------------------------------------------------------------------------
//Output an error if one is present on Click based on gridError Boolean Variable
ppnOutputAddError();
if (ppnGridError == false)
{
//Restore the block's alpha property as it isn't allowed to be selected, removing counter by one -- and changing final output accordingly
e.currentTarget.alpha = 1;
ppnBlocksSelected--;
ppnColumnArray[col][row] = false;
ppnShapeArray[e.currentTarget.id] = false;
ppnPopulateTotalSiteUnitsTxt();
}
//Update final total
ppnPopulateTotalSiteUnitsTxt();
//Call again to do dynamic colour font change should total exceed 10
ppnPopulateTotalSiteUnitsTxt();
//Added in to make sure it executes every time if an error is made.
if (ppnGridError == true)
{
e.currentTarget.removeEventListener(MouseEvent.CLICK, addBlock);
e.currentTarget.addEventListener(MouseEvent.CLICK, removeBlock);
}
}
}
function removeBlock(e:MouseEvent):void
{
if (InterfaceButtons.panelOpen == false)
{
var col:int = (e.currentTarget.id - 1) % 4;
var row:int = (e.currentTarget.id - 1) / 4;
ppnColumnArray[col][row] = false;
addOrRemove = "remove";
ppnBlockValid();
ppnGridError = ppnBlockValid();
trace("Is This Removal Valid? " + ppnBlockValid());
//trace("You Have Clicked On Grid Block Number: " + e.currentTarget.id);
e.currentTarget.alpha = 1;
ppnShapeArray[e.currentTarget.id] = false;
//trace("ppnShapeArray - " + ppnShapeArray);
//---------------------------------------------------------------------
ppnBlocksSelected--;
PlantPopNitDesignPlot.ppnPlotMade = false;
//Output an error if one is present on Click based on gridError Boolean Variable
ppnOutputRemoveError();
if (ppnGridError == false)
{
//Restore the block's alpha property as it isn't allowed to be selected, removing counter by one -- and changing final output accordingly
e.currentTarget.alpha = 0;
ppnBlocksSelected--;
ppnColumnArray[col][row] = true;
ppnShapeArray[e.currentTarget.id] = true;
ppnPopulateTotalSiteUnitsTxt();
}
//Update Final Total
ppnPopulateTotalSiteUnitsTxt();
//Call again to do dynamic colour font change should total falls below 10
ppnPopulateTotalSiteUnitsTxt();
//Added in to make sure it executes every time.
if (ppnGridError == true)
{
e.currentTarget.addEventListener(MouseEvent.CLICK, addBlock);
e.currentTarget.removeEventListener(MouseEvent.CLICK, removeBlock);
}
}
}
}
}
//---------------------------------------------------------------------
Now, for most occurences this logic works and detects illegal plots when adding or removing a block to the shape, however recently I discovered that when I have 5 > blocks in the shape, the logic for detecting an error on removal fails in certain circumstances.
A few examples of shapes being declared true and legal when they are not (when a block has been removed) are as follows:
I can see that it is the logic written in my 'ppnBlockValid():Boolean' function that needs adjusting to compensate for these outputs. It seems you can only remove a block providing that the neighbouring blocks are still joined to something else. While this works for smaller shapes, larger shapes (e.g. 5 blocks or more) can theoretically be split down the middle, so I think the code needs adjusting to account for this.
But how? Any help on this would be greatly appreciated.
Many thanks in advance and if you need any further information from me please let me know.
Cheers,
Joel
Edited
Thank you very much for providing that enhanced code and explanation #dhc I really appreciate it, but I'm still a little confused about how to implement all this properly.
Here is my current 'ppnBlockValid' function code based on your suggestion below:
public static function ppnBlockValid():Boolean
{
ppnIslands = [];
ppnAddNewIsland = [];
ppnAddToExistingIsland = [];
if (ppnCountSetCells() > 1)
{
for (var row=0; row<=3; row++)
{
for (var col=0; col<=3; col++)
{
if (ppnColumnArray[col][row] == true)
{
var addedToIsland = false;
// Check if we are connected to another set square
var validNeighbours:int = 0;
// Check North
if (row > 0)
{
if (ppnColumnArray[col][row - 1] == true)
{
validNeighbours++;
}
//----------------------------------
//ISLAND CHECK
if (ppnColumnArray[col][row - 1])
{
ppnAddToExistingIsland.push([col,row - 1],[col,row]);
addedToIsland = true;
}
}
// Check South
if (row < 3)
{
if (ppnColumnArray[col][row + 1] == true)
{
validNeighbours++;
}
}
// Check West
if (col > 0)
{
if (ppnColumnArray[col - 1][row] == true)
{
validNeighbours++;
}
//----------------------------------
//ISLAND CHECK
if (ppnColumnArray[col - 1][row])
{
ppnAddToExistingIsland.push([col - 1,row],[col,row]);
addedToIsland = true;
}
}
//-----------------------------------------------------------------------------------------
// Check East
if (col < 3)
{
if (ppnColumnArray[col + 1][row] == true)
{
validNeighbours++;
}
}
//-----------------------------------------------------------------------
if (! addedToIsland)
{
ppnIslands.push([col,row]);
}
//-----------------------------------------------------------------------
if (ppnIslands.length >= 2 && addOrRemove == "remove")
{
trace("TWO ISLANDS HAVE BEEN FORMED AND AN ERROR SHOULD BE OUTPUT");
validNeighbours--;
}
/**/
//return (ppnIslands.length<=1);// 0 islands is valid also!
//-----------------------------------------------------------------------
if (validNeighbours < 1)
{
return false;
}
//-----------------------------------------------------------------------
}
}
}
}
return true;
}
//---------------------------------------------------------------------
I have been using the following shape as my experiment with the code:
Based on the above code and example shape, my current trace output is:
ppnIsland = |0,0|,0,2
ppnAddNewIsland =
ppnAddToExistingIsland = 0,0, 1,0, 1,0, 2,0, 2,0, 3,0, 1,0, 1,1, 1,1, 1,2, 0,2, 1,2, 1,2, 2,2, 2,2, 3,2
It appears that despite the shape being contiguous, the code I've tried interpreting from you is finding an additional island, in this case 'Col: 0, Row: 2', before a block removal has even taken place? Is this right?
This code of course does output an error if I try to remove the middle (red) block as the 'ppnIsland' array contains > 1 island, however I don't think its detecting the correct output?
Do I need to cross-reference the 'ppnIsland' and 'ppnAddToExistingIsland' arrays using the indexOf command to check if either element is part of an existing island?
Joel
You could track "islands" as separate lists as you process (in ppnBlockValid). So, for instance (caps are selected tiles):
a B c d
e F g H
i J k L
m n o p
When you process row one, you create an island for B. When you process row 2, you find B connected to F, so the island becomes [B,F]. Then, when you encounter H, which is not connected, you have two islands: [B,F],[H]. On row 3, your islands would look like [B,F,J],[H,L]. If K were selected, you'd find J and L connected, and you'd consolidate them into one island. You only have to check the current row for connections between islands, so you'd only have to check J and L in this case.
If you end up with one island, you're fine, otherwise not. This is, unfortunately, an order n**2 search, but your grid is small so it probably doesn't mean much.
Something like this (WARNING: not debugged code):
private var islands : Array;
public function ppnBlockValid():Boolean {
islands = [];
if (ppnCountSetCells() > 1) {
for (var row=0; row<=3; row++) {
for (var col=0; col<=3; col++) {
if (ppnColumnArray[col][row]) {
var addedToIsland = false;
// Check if we are connected to another set square
// Check North
if (row > 0) {
if (ppnColumnArray[col][row-1]) {
addToExistingIsland([col,row-1],[col,row]);
addedToIsland = true;
}
}
// Check South - not needed since next row will catch this on North
// Check West
if (col > 0) {
if (ppnColumnArray[col-1][row]) {
addToExistingIsland([col-1,row],[col,row]);
addedToIsland = true;
}
}
// Check East - not needed since next col will catch this on West
if (!addedToIsland) { addNewIsland([col,row]); }
}
}
}
}
return (islands.length<=1); // 0 islands is valid also!
}
You just have to implement "addNewIsland" and "addToExistingIsland". addNewIsland is easy: just add a new element to the islands array. You may want to use a string ID for the tiles instead of an array (e.g. "01" instead of [0,1]) since it may make checking for existing elements easier (e.g. you can use indexOf to find a tile in an island).
addToExistingIsland is a bit trickier: you have to check if either element is part of an existing island, and consolidate those islands if so. If not, the new tile just gets appended to the island.
You don't need to maintain 3 arrays, just one island array that, at the end of ppnBlockValid, will either be length > 1 (invalid), or less (valid).
You cannot just populate the "ppnAddNewIsland" and "ppnAddToExistingIsland" arrays-- these should be functions. If ppnIslands is a class variable, then your addNewIsland function may look something like this:
private function addNewIsland(who) {
ppnIslands.push([who]);
}
... the only optimization I'd probably make is to turn who (passed as an array [col,row]) into a character string, as I mentioned, to make finding whether a tile exists in an island easier.
Then, you need a function like:
private function addToExistingIsland( existing_island_tile, new_tile ) {
}
This function must:
1. check whether these two tiles already exist in the same island (just return if so)
2. check whether new_tile is already on an island (consolidate the two islands into one if so)
3. otherwise, just add new_tile to the island that existing_island_tile is a member of
The code I presented should work pretty much as-is-- although you could add back in the "validNeighbours" logic if you want a quick exit for isolated tiles.
Initially the array holds the default values as 100. Once if the enemy looses its health then i want to set the default values from 100 to 0. When all the array elements gets a value of 0 then the message will trace as game win.
var enemyHealth:Array = new Array(100,100,100,100,0);
for (var i = 0; i< enemyHealth.length; i++)
{
if (enemyHealth[i] == 0)
{
trace ("game win");
}
}
Actually the issue is if any one of the array element holds a value of 0 then it trace a massage as game win.
So can any one help me in this regard.
You need to check all elements, not just one:
var allZero:Boolean = true;
var enemyHealth:Array = new Array(100,100,100,100,0);
for (var i = 0; i< enemyHealth.length; i++)
{
if (enemyHealth[i] != 0)
{
allZero = false;
break; // We know it's not a win, so we can stop the loop early
}
}
if (allZero) {
trace ("game win");
}
I would do something like this
var enemyHealth:Array = new Array(100,100,100,100,0);
var isDead:Boolean = true;
for (var i = 0; i< enemyHealth.length; i++)
{
if (enemyHealth[i] != 0)
{
isDead = false;
break;
}
}
if(isDead)
{
trace ("Game Win");
}
You can do what the other answerers have said or something like this which might help you more to get the exact amount of enemies dead.
var enemyHealth:Array = new Array(100,100,100,100,0);
var enemiesDead:int=0;
for (var i = 0; i< enemyHealth.length; i++)
{
if (enemyHealth[i] == 0)
{
enemiesDead++;
}
}
if(enemiesDead==enemyHealth.length)
{
trace("Game Over");
}
You can use the every method to check that every element of your array (or vector) meet a criterion.
const enemyHealth:Vector.<uint> = new <uint>[100,100,100,100,0];
const zeroHealth:Function = function(item:uint, index:int, vector:Vector.<uint>):Boolean {
return item === 0;
}
if (enemyHealth.every(zeroHealth)) {
trace("Game win")
}
I have changed the array to a Vector because they are more efficient, and you can specify the type of the elements, but it also works fine with array.