AS3 hittest keeps hitting - actionscript-3

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

Related

A* sometimes loops forever when traversing it's path back to the begin node

I have tried 2 different pseudocodes, from both Wikipedia and MIT, eventually both give me the same results:
sometimes, like on these screenshots, traversing loops forever because somehow there appears a link back somehow:
I include code in AS3:
{
private function searchPath(e:MouseEvent = null):void
{
for (var i:int = 0; i < nodes.length; i ++)
nodes[i].role = Node.IDLE_NODE;
if (!endNode || !beginNode) return;
beginNode.role = Node.BEGIN_NODE;
endNode.role = Node.END_NODE;
openSet.push(beginNode);
beginNode.g = 0;
beginNode.f = beginNode.h = heuristicCost(beginNode, endNode);
addEventListener(Event.ENTER_FRAME, update);
}
private function update(e:Event):void
{
if (openSet.length)
{
// searching for minimal f score node
var current:Node = openSet[0];
for (var i:int = 0; i < openSet.length; i ++)
if (openSet[i].f < current.f)
{
current = openSet[i];
}
current.role = Node.CURRENT_NODE;
// remove current node from openset
openSet.splice(openSet.indexOf(current), 1);
// walking through neighbours
for each(var neighbour:Node in current.neighbours)
{
if (neighbour == endNode)
{
neighbour.parentNode = current;
highlightPath(neighbour);
return;
}
if (current.g + heuristicCost(current, neighbour) >= neighbour.g)
continue;
neighbour.g = current.g + heuristicCost(current, neighbour);
neighbour.h = heuristicCost(neighbour, endNode);
neighbour.f = neighbour.g + neighbour.h;
// if neighbour is in the closed set or is in the openthen skip it
if (!(closedSet.indexOf(neighbour) > -1) && (openSet.indexOf(neighbour) < 0))
{
openSet.push(neighbour);
neighbour.parentNode = current;
}
}
// add current node to the closed set
closedSet.push(current);
}
else
{
while (closedSet.length) closedSet.pop();
trace("No solution");
removeEventListener(Event.ENTER_FRAME, update);
}
}
private function highlightPath(current:Node):void
{
var tp:Vector.<Node> = new Vector.<Node>();
tp.push(current);
while (current.parentNode) //this loops forever in situations from screenshots, because there's a link back
{
tp.push(current.parentNode);
current.role = Node.PATH_NODE;
current = current.parentNode;
}
current.role = Node.PATH_NODE;
while (openSet.length) openSet.pop();
while (closedSet.length) closedSet.pop();
for (var i:int = 0; i < nodes.length; i ++)
nodes[i].g = nodes[i].h = nodes[i].f = Infinity;
removeEventListener(Event.ENTER_FRAME, update);
}
}
Don't pay attention to the distances! That path is optimal, the nodes that are closer aren't connected(I hided connections on screenshots).
And also, forgot to mention that begin node on the screenshots is black, not orange.
Sorry, guys, I made a very silly mistake, I forgot to reset my parentNodes of Nodes to null after first run.
You should set neighbour.parentNode = current when you set neighbour.g. Right now you're setting parentNode to the first node that pushes neighbor onto the openSet
Also you will get much better performance if you use the proper data-structures (a set for closedSet; a priority-queue for openSet)

Flash hangs when I execute this particular loop

Please do forgive me if this question is very stupid, but I couldn't figure out what to do, which is why I ask it.
Here, I declared a small white square as a movieclip symbol(Dot) and I wish to generate it after a specific gap on the entire screen.
So, when I execute this (test it) code on Flash CS6, it hangs. After that I will be forced to end the program without doing anything further.
import flash.ui.*;
stop();
Mouse.hide();
var ctX:int = 0,ctY:int = 0,done:Boolean = false;
var base:Object = MovieClip(root);
this.addEventListener(Event.ENTER_FRAME, eFrame);
function eFrame(event:Event):void
{
while (done == false)
{
var dots:Dot = new Dot ;
dots.x += (50 * ctX);
dots.y += (50 * ctY);
ctX++;
if (ctX == 11)
{
ctX = 0;
ctY++;
}
else if (ctX == 11 && ctY == 10)
{
done = true;
break;
}
stage.addChild(dots);
}
}
Thank you in advance.
I have attached a screenshot of the situation.
The loop will never finish because the condition for done=true is ctX==11, but ctX==11 causes ctX=0 in the first condition:
if (ctX == 11) // when ctX is 11
{
ctX = 0; // ctX is reset to 0
ctY++;
}
else if (ctX == 11 && ctY == 10) // so you will never have ctX=11 here
{
done = true;
break; // (Tip: you don't need `done` since `break` exits the loop)
}
You could fix this by swapping the conditions, but I think this use of a while loop is unnecessarily complex and fragile. Why not just use two for loops:
for (var ctX:int = 0; ctX < 11; ctX++) {
for (var ctY:int = 0; ctY < 11; ctY++) {
var dots:Dot = new Dot();
dots.x = (50 * ctX);
dots.y = (50 * ctY);
stage.addChild(dots);
}
}
This is much clearer and less fragile because the loops are fixed length.
You could even do it with one for loop and a little math, but you lose some clarity:
for (var i:int = 0; i < 11 * 11; i++) {
var dots:Dot = new Dot();
dots.x = (50 * (i % 11));
dots.y = (50 * int(i / 11));
stage.addChild(dots);
}

drag and drop game only two end results, right or wrong AS3

I have been banging away on this issue for a long time now and I would love someone to whack me upside the head. I feel like I am so close, but you know how that is.
I have a drag and drop game, 8 options and 5 are correct. I want the user to drag 5 items from the 8 to the right of the screen. When they reach 5, it gives them a result. Right or Wrong (to keep the process moving I am not making them keep re-trying). Well, at this point in my code, everything is working well, except, when the end comes it only shows the right answer no matter what they drag. Please help.
I hope this is clear, thanks for any advice. I already appreciate you if you even read this.
import flash.display.MovieClip;
var cor_mc:correct_items_mc = new correct_items_mc;
var nopeAnswers:incorrect_items = new incorrect_items;
var policies:Array = [policy_0,policy_1,policy_2,policy_3, policy_4,policy_5,policy_6, policy_7];
var correct_choices:Array = [0,2,4,5,6];
var selected_items:Array = [];
for (var i:int = 0; i < policies.length; i++) {
var mc:MovieClip = policies[i];
mc.buttonMode = true;
mc.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag);
mc.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop);
mc.home_x = mc.x;
mc.home_y = mc.y;
mc.is_correct = correct_choices.indexOf(i);
}
function fl_ClickToDrag(event:MouseEvent):void
{
event.currentTarget.startDrag();
setChildIndex(MovieClip(event.currentTarget), numChildren - 1);
}
function fl_ReleaseToDrop(event:MouseEvent):void
{
var dropIndex:int = policies.indexOf(event.currentTarget);
var target:MovieClip = event.currentTarget as MovieClip;
target.stopDrag();
if (target.hitTestObject(bucket_mc)) {
selected_items.push(target);
trace(selected_items);
target.x = bucket_mc.x;
target.y = bucket_mc.y + selected_items.length * 60;
} else { // no match ... false
target.x = target.home_x;
target.y = target.home_y;
}
if (selected_items.length === correct_choices.length)
{
for (i = 0; i < correct_choices.length; i ++)
{
var cur_choice = correct_choices[i];
if (!selected_items.indexOf(cur_choice)) {
addChild(nopeAnswers);
nopeAnswers.x = 0;
nopeAnswers.y = 100;
} else {
addChild(cor_mc);
cor_mc.x = 0;
cor_mc.y = 100;
}
}
}
}
From the Manual indexOf returns -1 if the element is not found rather than a boolean false.
Change the condition to:
if (selected_items.indexOf(cur_choice) < 0){
....
}
Also if any of your first 4 correct values have NOT been selected you still continue looping and so will still output cor_mc if the final correct item was selected. You need to stop the loop once you find a correct answer missing:
if (selected_items.indexOf(cur_choice) < 0) {
addChild(nopeAnswers);
nopeAnswers.x = 0;
nopeAnswers.y = 100;
break;
} else {
addChild(cor_mc);
cor_mc.x = 0;
cor_mc.y = 100;
}

How to rearranged items in an inventory

I'm creating a game in AS3.
The player can grabb items and add it to his inventory in a line.
Everything is working, but I've got a bug when the player use an item wich is in the middle of the line.
It doesen't rearanged well..
(here is a video if I'm not very clear : http://ul.to/z7su5dqm or here https://drive.google.com/file/d/0B5-MjJcEPm3lTTlDV09MYWxMOFE/edit?usp=sharing)
I've got the code that add the item to the inventory :
public function addInvItem(itemName:String):void{
var itemRef:Object = getDefinitionByName(itemName.toLowerCase()+"Inv");
var addedItem:MovieClip = new itemRef;
addedItem.displayName = itemName;
if (playerItems.length < 8){ // This is for the top row of up to 4 items
addedItem.y = 520;
addedItem.x = 60 + (playerItems.length) * 100;
}
if (isUnique(addedItem)){
this.addChild(addedItem);
playerItems.push(addedItem);
allItems.push(addedItem);
addedItem.buttonMode = true;
addedItem.invItem = true;
addedItem.addEventListener(MouseEvent.CLICK, useItem, false, 0, true);
puzzle = Engine.puzzle;
puzzle.gotItem(addedItem.displayName);
}
So the first item is add at x= 60 and y = 520.
And then I've got this code in order to remove and rearranged the items :
public function removeInvItem(itemName:String):void{
removedItem = itemName;
var itemNum:int;
for (var i in playerItems){
if (playerItems[i].displayName == itemName){
playerItems[i].visible = false;
itemNum = i;
} else {
playerItems[i].visible = true;
}
}
playerItems = playerItems.filter(checkForItem);
// Rearrange the rest of the items
for (i in playerItems){
if (i >= itemNum){
playerItems[i].x -= 100;
}
}
}
Do you see where could be the error that push my first item ? (I suppose it came from playerItems[i].x -= 100).
I must find a way to tell the code that first item can't be less than x = 60 but the other must move x= -100 everytime their are used...
Any idea how I can do that ?
Thank you very much,
You are correct in assuming playerItems[i].x -= 100; is where the problem is caused. You are subtracting the current x position without any checks for if that falls over your inventory icon asset.
You could do something like this instead:
public function removeInvItem(itemName:String):void{
removedItem = itemName;
var itemNum:int;
for (var i in playerItems){
if (playerItems[i].displayName == itemName){
playerItems[i].visible = false;
itemNum = i;
} else {
playerItems[i].visible = true;
}
}
adjustInventory( itemNum );
}
public function adjustInventory( itemNum:int ):void {
var i:int;
for ( i=itemNum; i < playerItems.length; i++ ) {
//you can replace 60 with inventoryIcon.x + inventoryIcon.width instead
playerItems[i].x -= playerItems[i].x - 100 >= 60 ? 100 : playerItems[i].x - 60;
}
}
This evaluates the distance you are about to move before you do it, and only moves the necessary inventory items. I haven't tested this code but this should put you on the right path.

AS3: Vector item isn't spliced

Hello I am creating a system with a gun that shoots bullet.
The update function is processed this way:
var b:Bullet;
var l:uint = bulletList.length;
var i:uint;
for (i = 0; i < l; i++) {
b = bulletList[i];
b.sprite.x += b.vx;
b.sprite.y += b.vy;
if (b.sprite.x > 1200 || b.sprite.x < -100 || b.sprite.y < -1000) {
deleteBullet(b);
bulletList.splice(i,1);
}
}
public function deleteBullet(b:Bullet) {
b.sprite = null;
b = null;
}
When I shoot a bullet and it goes of the edge it generates an error, and sometimes it creates a new one but that one doesn't have any motion at all. This is the error I get:
RangeError: Error #1125: The index 1 is out of range 1.
You're getting that error because you're splicing your array while in a for loop.
instead of using 'l' as your parameter for the for loop, use bulletList.length directly as every iteration it will look at the CURRENT length which will reflect anything spliced out of it. You'll also need subtract your iterator when splicing as that shifts all future indexes down by one.
for (i = 0; i < bulletList.length; i++) {
b = bulletList[i];
b.sprite.x += b.vx;
b.sprite.y += b.vy;
if (b.sprite.x > 1200 || b.sprite.x < -100 || b.sprite.y < -1000) {
deleteBullet(b);
bulletList.splice(i,1);
i--;
}
}