locate an object after tween - actionscript-3

i want to create kind of slot machine.
i googled and found a sample code for that.
import com.greensock.*;
import com.greensock.easing.*;
var blitMask1:BlitMask = new BlitMask( strip1, strip1.x, strip1.y,
strip1.width, 100, true, true, 0xffff00, true);
spin_btn.addEventListener(MouseEvent.CLICK, spin);
function spin(event:MouseEvent):void {
spin_btn.visible = false;
var newNumber:Number = (randomNumber(0, 9) * 100) + 1200;
TweenMax.to(strip1, 1, {y:String(newNumber), onComplete:showBtn});
}
function showBtn() {
spin_btn.visible = true;
}
function randomNumber(min:Number, max:Number):Number {
return Math.floor(Math.random() * (1 + max - min) + min);
}
There is an object on stage called strip1 that have 10 children.Is there any way to find out which number(child) is on the stage after the virtual slot machine has stopped?
In other words, there is a tween method for an object and I want to find out whats its location after tween.

I recently developed a slot machine for the sake of it. I'm sure there are quite a few ways to do this but this is the way I did it. This has to be done for each reel.
There are usually three symbols visible inside your blitmask. If your blitmask is one symbol high then this method will give you the visible symbol
First declare a variable to keep track of the centre symbol.
I positioned my strip so that the 3rd symbol was center in the blitmask window, remember this is not the index.
Basically you know where it is going to land so you can find out what the symbol is before it lands.
var REEL1:Number = 3;
function spin(event:MouseEvent):void
{
var newNumber:Number = (randomNumber(1, 10)) ;
//call function to find the symbol to land
REEL1 = GetReelPosition(REEL1, newNumber);
//work out the amount to tween. Random number * symbol height + strip length
//if you want a longer spin add more strip lengths
newNumber = (newNumber * 100) + 1000;
var myTimeline:TimelineMax = new TimelineMax();
myTimeline.append(new TweenLite(Strip1, 2, {y:String(newNumber)}));
//get target symbol as movieclip
var currentTile:MovieClip = Strip1.getChildAt(REEL1-1) as MovieClip;
//if you have export for actionscript, this will tell what the object is
trace(String(currentTile));
}
When creating your strip, make symbols from your images, export for actionscript then add to your strip from top to bottom. If you change a symbol then you will have to delete and paste from top to bottom again. The index reflects the order the symbols are added.
function GetReelPosition(reel:Number,num:Number):Number
{
reel = reel - num;
switch(reel)
{
//if symbol is the first number on the strip and random
//number = 1 (1-1) then the centre symbol is the last on the strip
case 0:
reel = 10;
break;
//if symbol is the first number on the strip and random
//number = 10 (1-10) then the centre symbol is the first on the strip
case 1:
case -9:
reel = 1;
break;
case 2:
case -8:
reel = 2;
break;
case 3:
case -7:
reel = 3;
break;
case 4:
case -6:
reel = 4;
break;
case 5:
case -5:
reel = 5;
break;
case 6:
case -4:
reel = 6;
break;
case 7:
case -3:
reel = 7;
break;
case 8:
case -2:
reel = 8;
break;
//case 9, -1:
case 9:
case -1:
reel = 9;
break;
}
return reel;
}
I updated the switch code. case 9, -1: was not reliable. I'm not sure what language I picked that one from.
This was my first flash project and I did this slot machine fairly quickly. I'm sure there are better ways to do this. Have a look at my slot?
http://rcras.com/pokies/funnyfarm

Use a class variable to keep track of the currently visible element.
You can use the onCompleteParams argument of the TweenMax to pass the desired number. This would be available in the onComplete Handler. Set the variable when the tween complete (slot machine stops).
///...
var selectedChildIndex:Number = -1;
function spin(event:MouseEvent):void {
spin_btn.visible = false;
var newNumber:Number = (randomNumber(0, 9) * 100) + 1200;
TweenMax.to(strip1, 1, {y:String(newNumber),
onComplete:showBtn, onCompleteParams:[1]});
}
function showBtn(index) {
spin_btn.visible = true;
selectedChildIndex = index;
}

Related

Nested movieclips; changing background frame

Where have all my children gone?
Hope this is a relatively simple answer to a less-than-intelligent question that's a consequence of how I learn things when not doing them for work. In this case I started a game about 3 years ago in AS3 as I was familiar with js at least and had also worked with shockwave back in the day. Anyway, when learning something offline like this I tend to learn just what I need to know to do what I need to do next, and can sometimes get pretty far into one area while missing something obvious and simple because I just haven't crossed that case yet.
We have a playing field and playing pieces. Those playing pieces (sailing ships) you see below are complex objects with dozens of properties and several children including graphics and text fields that change depending on the state of the ship. It's WEGO where each side plots moves, those moves are then executed one ship at a time alternatively between the two sides, then we have gun combat, etc. All that is there and works fine, a few thousand lines of code.
My current problem is that when a player clicks on a ship to select it, I unhide a yellow border to indicate which ship is selected and draw the complex ship detail screen you see top left, but for a long time I've wanted to change the background color of the playing piece as well.
After a long layoff I started working on this again and decided to start there. So I made new counters, added them as keyframes to the already existing symbol/class that contains all of the country default backgrounds, and modified the code. It works fine in that the background is changed to the correct highlighted version, and then goes back to default when deselected.
In the image the currently-selected ship is in the center, USS Constitution, its detail/info screen is also displayed. You can see the problem, all the children are gone on the playing piece. And they don't come back when you go back to the original default background.
At first I thought it was a z order problem but it isn't, I walked the selected ship playing piece background in the z index until they disappeared behind the ocean background, there was just open ocean where the ship playing piece used to be.
My best guess is that maybe the children have to be instanced on each frame of the parent's timeline each time you change the parent's frame but if so I'm not finding reference to or explanation of that. That and that seems really unwieldy way of doing things, I was completely caught off guard by the idea of the children caring what frame its parent is on unless there was coded logic telling it to.
Somehow even though I have thousands of lines of complex dialogs and screens displaying multiple dynamic children I have never changed the base background in any of those cases.
Also tried to google this, but had little luck. I couldn't even figure out a relatively simple question to ask.
I'll be happy to paste code but I don't seem to have a code problem but an understanding problem.
Example-selected ship with highlighted background graphic is in the center
For those who feel the code is important, this is the end of the 1500 line ship-creation function where most of the children get added:
textShipSailSpeed.name = "textShipSailSpeed";
textShipSailSpeed.width = 20;
textShipSailSpeed.height = 13;
textShipSailSpeed.x = 33;
textShipSailSpeed.y = 14;
textShipSailSpeed.embedFonts = true;
textShipSailSpeed.textColor = 0xFFFFFF;
textShipSailSpeed.rotation -= 90;
//full sails set
if ("full" == finalShip.sailState) {
textShipSailSpeed.text = finalShip.fullSailSpeed;
}
//battle sails set, which are reduced sails to improve visibility and reduce sail damage in combat
else {
textShipSailSpeed.text = finalShip.battleSailSpeed;
}
// textShipBattleSailSpeed and textShipFullSailSpeed no longer used on counters, but still used in Info screens
var textShipBattleSailSpeed: TextField = new TextField();
textShipBattleSailSpeed.name = "textShipBattleSailSpeed";
textShipBattleSailSpeed.text = finalShip.battleSailSpeed;
textShipBattleSailSpeed.visible = false;
var textShipFullSailSpeed: TextField = new TextField();
textShipFullSailSpeed.name = "textShipFullSailSpeed";
textShipFullSailSpeed.text = finalShip.fullSailSpeed;
textShipFullSailSpeed.visible = false;
//create sailState (battle/full) indicator
var sailStateIndicator: WSIM_Counters_SailtState_Indicator = new WSIM_Counters_SailtState_Indicator();
//set indicator to correct sailState background graphic
sailStateIndicator.gotoAndStop("battle");
if ("full" == finalShip.sailState) {
sailStateIndicator.gotoAndStop("full");
}
finalShip.addChild(sailStateIndicator);
//add ship and attach text fields
gridBG1.addChild(finalShip);
finalShip.addChild(textShipName);
finalShip.addChild(textShipSailSpeed);
finalShip.addChild(textShipTurnAllowance);
finalShip.addChild(textShipBattleSailSpeed);
finalShip.addChild(textShipFullSailSpeed);
finalShip.parent.setChildIndex(finalShip, 1);
//logging
if (log_shipCreation) {
trace(finalShip.name + " added added as child of background in createShip()");
}
//create background sprite "ship is selected" border
var border: Sprite = new Sprite();
border.name = "shipBorder";
border.graphics.beginFill(0xFFCC00, 1);
border.graphics.drawRect(-1, -1, 52, 132)
border.graphics.endFill();
border.visible = false;
//create background sprite combat border
var borderCombat: Sprite = new Sprite();
borderCombat.name = "borderCombat";
borderCombat.graphics.beginFill(0xFF0000, 1);
borderCombat.graphics.drawRect(-1, -1, 52, 132)
borderCombat.graphics.endFill();
borderCombat.visible = false;
//add the borders as children of ship
finalShip.addChild(border);
finalShip.addChild(borderCombat);
//move the borders in z-order to behind ship counter, so they show looking like a border
border.parent.setChildIndex(border, border.parent.getChildIndex(border) - 5);
borderCombat.parent.setChildIndex(borderCombat, borderCombat.parent.getChildIndex(borderCombat) - 6);
//PUSH TO MASTER SHIP ARRAYS
//finalShip is Side 1, add to master list of ship objects for Side 1
if (sideList[0] == finalShip.country) { ....
And this is part of the even larger selectShip function, here is where I clear the selected state on all ships on map and then set the current ship's background to currShip.country+"_sel" which is the correct frame label for the "selected" background images.
//clear combat selected state on all ships
for (var i: int = 0; i < shipListSide1.length; i++) {
//hide selection border sprite and set select property false
shipListSide1[i].combatSelected = false;
var borderChildCombat = shipListSide1[i].getChildByName("borderCombat");
borderChildCombat.visible = false;
//show default counter background, build label name
shipListSide1[i].gotoAndStop(shipListSide1[i].country+"_def");
}
for (var i: int = 0; i < shipListSide2.length; i++) {
//hide selection border sprite and set select property false
shipListSide2[i].combatSelected = false;
var borderChildCombat2 = shipListSide2[i].getChildByName("borderCombat");
borderChildCombat2.visible = false;
//show default counter background, build label name
shipListSide2[i].gotoAndStop(shipListSide2[i].country+"_def");
}
//check to see if this is selecting a target in gun combat
if ((false == currShip.side1 && enableCombatSelectSide2) || (currShip.side1 && enableCombatSelectSide1)) {
combatSelectShip(currShip);
}
//we're allowed to select this ship
if ((enableSelectSide1 && currShip.side1) || (enableSelectSide2 && false == currShip.side1)) {
//event is from a ship object
if (currShip is Ship_1) {
//remove previous ship info screen
if (currShipInfo.parent) {
currShipInfo.parent.removeChild(currShipInfo);
}
//clear selected state on all ships
for (var i: int = 0; i < shipListSide1.length; i++) {
//hide selection border sprite and set select property false
shipListSide1[i].selected = false;
var borderChild = shipListSide1[i].getChildByName("shipBorder");
borderChild.visible = false;
//default graphic already set in clearing combatselect status above
}
for (var i: int = 0; i < shipListSide2.length; i++) {
//hide selection border sprite and set select property false
shipListSide2[i].selected = false;
var borderChild2 = shipListSide2[i].getChildByName("shipBorder");
borderChild2.visible = false;
//default graphic already set in clearing combatselect status above
}
//Change graphic of selected ship to selected, highlighted color
currShip.gotoAndStop(currShip.country+"_sel");
//set selected state on clicked ship, unhide border
currShip.selected = true;
borderChild = currShip.getChildByName("shipBorder");
borderChild.visible = true;
Ok based on feedback about it being a z-order issue, the below is what I tried to move the missing children back above the playing piece background. If you notice it also has to be a z order issue as the "selected" border, which is a child of the playing piece like the missing ones, that happens to purposely be behind the playing piece graphic, displays correctly when the ship is in the selected state. See the original screenshot, the playing piece in the center that's selected and is missing its children also has a yellow border.
Anyway, below is what I tried. It works in that there are no errors but I really couldn't find these children in the debugger to confirm what happened, and so far I at least appear to have moved them up in the z order to the max before I get an out of range error, and the problem still exists - no ship graphic, ship name, movement allowance, etc.
//Change playing piece background of the selected ship to selected, highlighted color frame
currShip.gotoAndStop(currShip.country+"_sel");
//trying to move the children of the playing piece back above the playing piece graphic
var shipChildrenArray:Array = new Array("textShipName","textShipTurnAllowance","textShipSailSpeed","sailStateIndicator");
for each(var childItem:String in shipChildrenArray) {
currShip.setChildIndex(currShip.getChildByName(childItem), 3);
}
Your parent movieclip should have layers. The child movieclip that you want to always be visible needs to extend across all frames of the parent.
Note that I did not see what you say I should be able to see on your graphic. Since I don't know what you think it should look like, I wasn't able to spot the difference between what it does look like and that.
You may find you get better feedback if you post a screen capture of the timeline and post any code that's involved.
I try to build a simple replica of your hierarchy here:
package {
import flash.display.MovieClip;
import flash.events.*;
public class gameTestDoc extends MovieClip {
var pieceArray:Array = new Array();
public function gameTestDoc() {
stage.addEventListener(MouseEvent.CLICK, selectPiece);
for (var i:int = 0; i < 4; i++){ // creates 4 instances of a class with 6 frames, each having a different colored rectangle.
var gamePiece:MovieClip = new backGround();
addChild(gamePiece);
gamePiece.x = 50 * i + 200; // space out the game pieces.
gamePiece.y = stage.stageHeight/2; // center game pieces.
pieceArray.push(gamePiece);// add piece to array.
for (var j:int = 0; j < 5; j++){
var components:MovieClip = new MovieClip();
components.graphics.lineStyle();
components.graphics.beginFill(0x00ffcc * j * 200000); //gives different color to each component.
components.graphics.drawRect(0,0,5, 10);
components.graphics.endFill();
gamePiece.addChild(components);
components.y = j * 5;
}
gamePiece.gotoAndStop(Math.ceil(Math.random()*10)); // give each piece a random frame to go to.
}
}
function selectPiece(e:MouseEvent):void{ // sends game piece frame to random frame.
for (var i:int = 0; i < pieceArray.length; i++){
e.target.gotoAndStop(Math.ceil(Math.random()*10));
}
}
}
}
and I have an mc in the GUI library with the linkage name of "backGround". When I click on the pieces, the backgrounds change color, and everything else stays on top. Here is a picture:
and after I click the 2nd piece:
can you see from my simple code what you might be doing differently?
edit: 6-10-16
//move the borders in z-order to behind ship counter, so they show looking like a border
border.parent.setChildIndex(border, border.parent.getChildIndex(border) - 5);
borderCombat.parent.setChildIndex(borderCombat, borderCombat.parent.getChildIndex(borderCombat) - 6);
wouldn't this be less confusing/prone to strange behavior?:
//move the borders in z-order to behind ship counter, so they show looking like a border
border.parent.setChildIndex(border, 0);
borderCombat.parent.setChildIndex(borderCombat, 0);
Would this not give the same result?
At first I thought it was a z order problem but it isn't,
Actually this is probably exactly your problem.
I walked the selected ship playing piece background in the z index until they disappeared behind the ocean
Really? How? Moving the z-order of display objects in a container can't change the z-order of the container. But if you are moving the ship itself (the container of all your other symbols), then yes, the open ocean will appear. But just shifting things around within the ship won't do that. How to shift things around in the ship container? Go here.
Example
If your game piece (pieceMc) is a child of the ocean background (oceanMc) and the the flag background (flagMc) is a child of the piece then
oceanMc.gamePieceMc.setChildIndex(flagMc,0);
should put the flag to the bottom
Edit 6/11/16
One quick and dirty way to change z-order at runtime is to re add the child; it will be put on top of the stack. You could do
piece[i].addChild(ship);
piece[i].addChild(guns);
piece[i].addChild(nameField);
the result will be that the ship will come to the top, then the guns will be put back on top of that, then the nameField on top of that. If the flag background is also a child of "piece" it will below, like you want.
One quick and dirty way to change z-order at runtime is to re add the child; it will be put on top of the stack. You could do piece[1].addChild(ship); piece[1].addChild(guns); piece[1].addChild(nameField); the result will be that the ship will come to the top, then the guns will be put back on top of that, then the nameField on top of that. If the flag background is also a child of "piece" it will below, like you want. – Neal Davis yesterday
Ok, this is the closest to the correct answer I'm going with. As you can see in the update to my original question, I tried to fix the z order problem by either moving the children up or the background down, but had no luck even though the code executes fine.
So I changed my solution to this:
//Change playing piece background of the selected ship to selected, highlighted color frame
currShip.gotoAndStop(currShip.country+"_sel");
//move the children of the playing piece back above the playing piece graphic. When parent changes frame as above it goes to the top of the z order for some stupid reason
var shipChildrenArray:Array = new Array("textShipName","textShipTurnAllowance","textShipSailSpeed","sailStateIndicator", "currShipGraphic");
for each(var childItem:String in shipChildrenArray) {
//currShip.setChildIndex(currShip.getChildByName(childItem), 5);
var childObject = currShip.getChildByName(childItem);
currShip.removeChild(childObject);
currShip.addChild(childObject);
}
It seems very hacky to me, I'd rather correctly manipulate the z order but unless someone has other ideas on how to do that, we'll have to go with this solution. Re-adding the children does indeed move them back to the top of the current z order array.
So:
1) If you have nested movieclips and you change the frame of the parent, it will go to the top of the z order array for reasons I can't begin to fathom. I don't see a way to prevent it either.
2) If you know how to manipulate the z order of the child movieclips better than I do, that would probably be the best solution.
3) A sledgehammer solution is removing and adding all the children back.
...and it won't let me post a screenshot of it working properly because I "need at least 10 reputation points to post more than two links." Makes no sense as this attachment is the SECOND link, not third or more. Oh well.
Responding to Neal's post.
Looking at the code, only difference that I see is that you're adding the pieces as children of the stage, while mine are one nested level down by being children of the ocean graphic.
Since you're interested and spending time with it, I'll post the entire ship creation function below. It gets called iteratively and loops through the side1 master array of ships and then side2, back to back. That's one reason I'm so confused by the two sides' z orders being consistently different, maybe alphabetical is being applied- only z order manipulation I do in the creation is pushing the border children (one normal select one combat) behind the playing piece.
BTW, please also look for another question from me involving a different issue I am having where a dialog is refusing to disappear on removeChild even though the associated code hasn't been touched in a couple years.
This is ship creation. This is a simulation, not a game, so it's reasonably complex with large numbers of properties set. One somewhat unusual thing I do you will see is cast my Ship_1 classes to a generic object to set all the custom properties and then back to Ship_1 once that's done. I always thought that was a little risky but have seen zero problems (unless this issue is tied to that somehow)
//create ship objects, set properties, add to core arrays
function createShip(currShip) {
// create Ship_1 obj and cast it temporarily as parent class (which is dynamic) to set custom properties
var finalShip: Ship_1 = new Ship_1();
var temp_Ship: Object = finalShip as Object;
//set basic stats
temp_Ship.selected = currShip.selected;
temp_Ship.combatSelected = currShip.combatSelected;
temp_Ship.name = currShip.name;
//rigging & rigging damage
temp_Ship.rigging = currShip.rigging;
temp_Ship.riggingSlots = currShip.riggingSlots;
temp_Ship.rigging_1 = currShip.rigging_1;
temp_Ship.rigging_2 = currShip.rigging_2;
temp_Ship.rigging_3 = currShip.rigging_3;
temp_Ship.rigging_4 = currShip.rigging_4;
temp_Ship.riggingDamage = currShip.riggingDamage;
temp_Ship.riggingDamage_1 = currShip.riggingDamage_1;
temp_Ship.riggingDamage_2 = currShip.riggingDamage_2;
temp_Ship.riggingDamage_3 = currShip.riggingDamage_3;
temp_Ship.riggingDamage_4 = currShip.riggingDamage_4;
//hull & hull damage
temp_Ship.hull = currShip.hull;
temp_Ship.hull_1 = currShip.hull_1;
temp_Ship.hull_2 = currShip.hull_2;
temp_Ship.hull_3 = currShip.hull_3;
temp_Ship.hullDamage = currShip.hullDamage;
temp_Ship.hullDamage_1 = currShip.hullDamage_1;
temp_Ship.hullDamage_2 = currShip.hullDamage_2;
temp_Ship.hullDamage_3 = currShip.hullDamage_3;
//guns & guns damage
temp_Ship.guns = currShip.guns;
temp_Ship.gunsDamage = currShip.gunsDamage;
temp_Ship.guns_1 = currShip.guns_1;
temp_Ship.guns_2 = currShip.guns_2;
temp_Ship.guns_3 = currShip.guns_3;
temp_Ship.guns_4 = currShip.guns_4;
temp_Ship.gunsDamageLeftBow = currShip.gunsDamageLeftBow;
temp_Ship.gunsDamageLeftBowInitial = currShip.gunsDamageLeftBowInitial;
temp_Ship.gunsDamageRightBow = currShip.gunsDamageRightBow;
temp_Ship.gunsDamageRightBowInitial = currShip.gunsDamageRightBowInitial;
temp_Ship.gunsDamageLeftStern = currShip.gunsDamageLeftStern;
temp_Ship.gunsDamageLeftSternInitial = currShip.gunsDamageLeftSternInitial;
temp_Ship.gunsDamageRightStern = currShip.gunsDamageRightStern;
temp_Ship.gunsDamageRightSternInitial = currShip.gunsDamageRightSternInitial;
//carronades & carronades damage
temp_Ship.carronades = currShip.carronades;
temp_Ship.carronades_1 = currShip.carronades_1;
temp_Ship.carronades_2 = currShip.carronades_2;
temp_Ship.carronades_3 = currShip.carronades_3;
temp_Ship.carronades_4 = currShip.carronades_4;
temp_Ship.carronadesDamageLeftBow = currShip.carronadesDamageLeftBow;
temp_Ship.carronadesDamageLeftBowInitial = currShip.carronadesDamageLeftBowInitial;
temp_Ship.carronadesDamageRightBow = currShip.carronadesDamageRightBow;
temp_Ship.carronadesDamageRightBowInitial = currShip.carronadesDamageRightBowInitial;
temp_Ship.carronadesDamageLeftStern = currShip.carronadesDamageLeftStern;
temp_Ship.carronadesDamageLeftSternInitial = currShip.carronadesDamageLeftSternInitial;
temp_Ship.carronadesDamageRightStern = currShip.carronadesDamageRightStern;
temp_Ship.carronadesDamageRightSternInitial = currShip.carronadesDamageRightSternInitial;
//crew and crew damage
temp_Ship.crewQuality = currShip.crewQuality;
temp_Ship.crewDamage = currShip.crewDamage;
temp_Ship.crew_1 = currShip.crew_1;
temp_Ship.crew_1_damage = currShip.crew_1_damage;
temp_Ship.crew_1_lost = currShip.crew_1_lost;
temp_Ship.crew_1_lostInitial = currShip.crew_1_lostInitial;
temp_Ship.crew_2 = currShip.crew_2;
temp_Ship.crew_2_damage = currShip.crew_2_damage;
temp_Ship.crew_2_lost = currShip.crew_2_lost;
temp_Ship.crew_2_lostInitial = currShip.crew_2_lostInitial;
temp_Ship.crew_3 = currShip.crew_3;
temp_Ship.crew_3_damage = currShip.crew_3_damage;
temp_Ship.crew_3_lost = currShip.crew_3_lost;
temp_Ship.crew_3_lostInitial = currShip.crew_3_lostInitial;
//initial positions, used in plotted movement
temp_Ship.initialColumn = currShip.initialColumn;
temp_Ship.initialRow = currShip.initialRow;
temp_Ship.initialColumn2 = currShip.initialColumn2;
temp_Ship.initialRow2 = currShip.initialRow2;
temp_Ship.initialDirection = currShip.initialDirection;
//movement properties
temp_Ship.fullSailSpeed = currShip.fullSailSpeed;
temp_Ship.fullSailSpeedArray = currShip.fullSailSpeedArray;
temp_Ship.maxFullSailSpeed = currShip.maxFullSailSpeed;
temp_Ship.initialFullSailSpeed = currShip.initialFullSailSpeed;
temp_Ship.battleSailSpeed = currShip.battleSailSpeed;
temp_Ship.battleSailSpeedArray = currShip.battleSailSpeedArray;
temp_Ship.maxBattleSailSpeed = currShip.maxBattleSailSpeed;
temp_Ship.initialBattleSailSpeed = currShip.initialBattleSailSpeed;
//point of sailing (close reach, broad reach, etc.)
temp_Ship.shipOrientation = currShip.shipOrientation;
temp_Ship.movementAllowanceUsed = currShip.movementAllowanceUsed;
temp_Ship.moveLog = currShip.moveLog;
//turn properties
temp_Ship.turnAllowanceBase = currShip.turnAllowanceBase;
temp_Ship.turnAllowance = currShip.turnAllowance;
//used in movement
temp_Ship.turnAllowed = currShip.turnAllowed;
temp_Ship.moveAllowed = currShip.moveAllowed;
//special conditions (anchored, grappled, etc.) can block movement/turning
temp_Ship.canMove = currShip.canMove;
temp_Ship.fouled = currShip.fouled;
temp_Ship.anchored = currShip.anchored;
temp_Ship.grappled = currShip.grappled;
temp_Ship.onFire = currShip.onFire;
//dismasted
temp_Ship.dismasted = currShip.dismasted;
temp_Ship.initialDismasted = currShip.initialDismasted;
temp_Ship.dismastedPreviousValue = currShip.dismastedPreviousValue;
//weapons status
temp_Ship.loadedLeft = currShip.loadedLeft;
temp_Ship.loadedRight = currShip.loadedRight;
temp_Ship.shotType = currShip.shotType;
//position
temp_Ship.column = currShip.column;
temp_Ship.row = currShip.row;
//stern hex
temp_Ship.column2 = currShip.column2;
temp_Ship.row2 = currShip.row2;
temp_Ship.direction = currShip.direction;
//country
temp_Ship.country = currShip.country;
//class and rating
temp_Ship.shipClassName = currShip.shipClassName;
temp_Ship.shipClassNumber = currShip.shipClassNumber;
temp_Ship.shipRate = currShip.shipRate;
temp_Ship.originalGuns = currShip.originalGuns;
//HACK need to find a better solution
temp_Ship.combatBorderFixed = currShip.combatBorderFixed;
//value will be frame label of the ship portrait we will use for this ship
//these will be used by the info screens
temp_Ship.portraitLabel = "";
// <--- begin select ship portrait for Info screens ---->
//number of options per country + number of guns combo
var portraitRandLimit:int = 1;
//actual class that contains all of the ship portrait bitmaps
var shipPortraitSource:Ship_Portrait = new Ship_Portrait;
//pull list of all frame labels in shipPortraitSource
var labelList:Array = shipPortraitSource.currentLabels;
//iterate through list of frame labels to see if we have one that matches this ship's name
for each (var frameObject:FrameLabel in labelList) {
//we have a name match in our list of ship portraits, use specific bitmap for that individual ship
if (frameObject.name == currShip.name) {
temp_Ship.portraitLabel = currShip.name;
//LOGGING
if (log_shipPortraitSelection) {
trace("==================================================");
trace("framObject.name: "+frameObject.name+" matched currShip.name: "+currShip.name);
trace("temp_Ship.portraitLabel set to: "+temp_Ship.portraitLabel);
trace("==================================================");
trace("");
}
}
}
//we didn't find a name match, select a ship portrait from available options that match the ship country + number of guns it really carried
//Trying to have 3-4 accurate options in each gun number + country combo
if ("" == temp_Ship.portraitLabel) {
//configure the number of options for each country + number of guns combo
switch(currShip.country) {
case "US":
switch(currShip.originalGuns) {
case 44:
portraitRandLimit = 4;
break;
case 38:
portraitRandLimit = 4;
break;
case 36:
break;
case 32:
portraitRandLimit = 2;
break;
case 28:
portraitRandLimit = 2;
break;
case 16:
break;
case 12:
portraitRandLimit = 2;
break;
}
break;
case "GB":
switch(currShip.originalGuns) {
case 38:
portraitRandLimit = 4;
break;
case 36:
break;
case 32:
portraitRandLimit = 2;
break;
case 28:
portraitRandLimit = 3;
break;
}
break;
case "FR":
case "ES":
case "NL":
break;
}
//now that we know how many options we have for this gun number + country combo, select one randomly
var portraitNumber:int = Math.ceil(Math.random() * portraitRandLimit);
//build the label name for us in the info screens, E.G., "GB_38_3", being the third portrait for 38 gun British ships
temp_Ship.portraitLabel = currShip.country+"_"+currShip.originalGuns+"_"+portraitNumber;
//LOGGING
if (log_shipPortraitSelection) {
trace("==================================================");
trace("There was no name match selecting a portrait, so building label name");
trace("currShip.name: "+currShip.name);
trace("portraitRandLimit: "+portraitRandLimit);
trace("portraitNumber: "+portraitNumber);
trace("temp_Ship.portraitLabel set to: "+temp_Ship.portraitLabel);
trace("==================================================");
trace("");
}
}
// <--- end select ship portrait for Info screens ---->
//used for movement rules, ship can only turn once per hex. 1 = straight, 2 = turn
temp_Ship.lastMove = currShip.lastMove;
//is ship fulll or battle sail
temp_Ship.sailState = currShip.sailState;
//designates which sdie ship is on
temp_Ship.side1 = currShip.side1;
temp_Ship.starboardHitZone = currShip.starboardHitZone;
temp_Ship.portHitZone = currShip.portHitZone;
temp_Ship.initialBroadside = currShip.initialBroadside;
//ship going down
temp_Ship.isSinking = currShip.isSinking;
temp_Ship.isExploding = currShip.isExploding;
//ship surrender
temp_Ship.isSurrendered = currShip.isSurrendered;
temp_Ship.strikeColors = currShip.strikeColors;
temp_Ship.strikeFirePower = currShip.strikeFirePower;
temp_Ship.strikeMobility = currShip.strikeMobility;
//recast back to ship type. This seems risky but it works
finalShip = temp_Ship as Ship_1;
//calc initial positions based on column/row properties and a hex-based grid
finalShip.x = (62 * (finalShip.column - 1)) + 17;
//y setting is annoying
finalShip.y = 5 + ((finalShip.row - 1) * 70) + ((finalShip.row - 1) * 1) - 71;
//odd columns must compensate for half hexes
if (1 == finalShip.column % 2) {
finalShip.y += 35;
}
//rotate based on ship direction and correct for top left registration point
switch (finalShip.direction) {
case 1:
//do nothing
break;
case 2:
finalShip.rotation = 60;
finalShip.x += 99;
finalShip.y += 27;
break;
case 3:
finalShip.rotation = 120;
finalShip.x += 124;
finalShip.y += 129;
break;
case 4:
finalShip.rotation = -180;
finalShip.x += 50;
finalShip.y += 202;
break;
case 5:
finalShip.rotation = -120;
finalShip.x -= 51;
finalShip.y += 172;
break;
case 6:
finalShip.rotation = -60;
finalShip.x -= 76;
finalShip.y += 72;
break;
}
//create ship graphics object. Numerous ship graphics representing all countries and all rates (1st-7th). There are multiple options in some country/rate cases
var currShipGraphic:WSIM_Ship_Graphics = new WSIM_Ship_Graphics();
//select correct background and ship graphics. Counter backgrounds are selected by ship country and ship rate sets the correct ship image to place on that background
switch (finalShip.country) {
//United States
case "US":
//set US background
finalShip.gotoAndStop("US_def");
//Select correct ship overlay based on ship rating (1st-7th)
switch (finalShip.shipRate) {
//US had no ships of the line. Well there was America but she saw no action and was given to the French
//everything gets frigate for now
case 5:
case 6:
case 7:
currShipGraphic.gotoAndStop("US_5_1");
break;
}
break;
//Great Britain
case "GB":
//set GB background
finalShip.gotoAndStop("GB_def");
switch (finalShip.shipRate) {
case 1:
currShipGraphic.gotoAndStop("GB_1_1");
break;
case 2:
currShipGraphic.gotoAndStop("GB_2_1");
break;
case 3:
currShipGraphic.gotoAndStop("GB_3_1");
break;
case 4:
currShipGraphic.gotoAndStop("GB_4_1");
break;
//everything gets frigate for now
case 5:
case 6:
case 7:
currShipGraphic.gotoAndStop("GB_5_1");
break;
}
break;
//France
case "FR":
//set FR background
finalShip.gotoAndStop("FR_def");
switch (finalShip.shipRate) {
case 1:
currShipGraphic.gotoAndStop("FR_1_1");
break;
case 2:
case 3:
//we have multiple options for French 3rd rate SoL
var FR_shipGraphicRandom:int = Math.ceil(Math.random() * 2);
switch (FR_shipGraphicRandom) {
case 1:
currShipGraphic.gotoAndStop("FR_3_1");
break;
case 2:
currShipGraphic.gotoAndStop("FR_3_2");
break;
}
break;
case 4:
currShipGraphic.gotoAndStop("FR_4_1");
break;
//everything gets frigate
case 5:
case 6:
case 7:
currShipGraphic.gotoAndStop("FR_5_1");
break;
}
break;
//Spain
case "ES":
//set ES background
finalShip.gotoAndStop("ES_def");
switch (finalShip.shipRate) {
case 1:
currShipGraphic.gotoAndStop("ES_1_1");
break;
case 2:
case 3:
case 4:
currShipGraphic.gotoAndStop("ES_3_1");
break;
//everything gets frigate
case 5:
case 6:
case 7:
currShipGraphic.gotoAndStop("ES_5_1");
break;
}
break;
//Netherlands
case "NL":
//set NL background
finalShip.gotoAndStop("NL_def");
switch (finalShip.shipRate) {
case 1:
case 2:
case 3:
case 4:
currShipGraphic.gotoAndStop("NL_3_1");
break;
//everything gets frigate
case 5:
case 6:
case 7:
currShipGraphic.gotoAndStop("NL_5_1");
break;
}
break;
}
currShipGraphic.x = 0;
currShipGraphic.y = 0;
currShipGraphic.name = "currShipGraphic";
//add correct ship graphic to the counter background
finalShip.addChild(currShipGraphic);
//font and format for counter text fields
var arialFont = new Arial();
var lucidaFont = new Lucida_Cal();
var textShipNameFormat: TextFormat = new TextFormat();
textShipNameFormat.size = 11;
textShipNameFormat.font = lucidaFont.fontName;
//ship name text field
var textShipName: TextField = new TextField();
textShipName.defaultTextFormat = textShipNameFormat;
textShipName.name = "textShipName";
textShipName.width = 80;
textShipName.height = 13;
textShipName.x = 34;
textShipName.y = 105;
textShipName.embedFonts = true;
textShipName.textColor = 0xFFFFFF;
textShipName.rotation -= 90;
textShipName.sharpness = 200;
textShipName.htmlText = "<p align='center'>" + finalShip.name + "</p>";
//font format for movement and turn allowance
var textShipNumbersFormat: TextFormat = new TextFormat();
textShipNumbersFormat.size = 12;
textShipNumbersFormat.font = arialFont.fontName;
//ship turn allowance
var textShipTurnAllowance: TextField = new TextField();
textShipTurnAllowance.defaultTextFormat = textShipNumbersFormat;
textShipTurnAllowance.name = "textShipTurnAllowance";
textShipTurnAllowance.width = 20;
textShipTurnAllowance.height = 13;
textShipTurnAllowance.x = 33;
textShipTurnAllowance.y = 127;
textShipTurnAllowance.embedFonts = true;
textShipTurnAllowance.textColor = 0xFFFFFF;
textShipTurnAllowance.rotation -= 90;
textShipTurnAllowance.text = finalShip.turnAllowance;
//ship movement allowance AS DISPLAYED ON THE COUNTER - display either battle sails speed or full sails speed depending on ship state
var textShipSailSpeed: TextField = new TextField();
textShipSailSpeed.defaultTextFormat = textShipNumbersFormat;
textShipSailSpeed.name = "textShipSailSpeed";
textShipSailSpeed.width = 20;
textShipSailSpeed.height = 13;
textShipSailSpeed.x = 33;
textShipSailSpeed.y = 14;
textShipSailSpeed.embedFonts = true;
textShipSailSpeed.textColor = 0xFFFFFF;
textShipSailSpeed.rotation -= 90;
//full sails set
if ("full" == finalShip.sailState) {
textShipSailSpeed.text = finalShip.fullSailSpeed;
}
//battle sails set, which are reduced sails to improve visibility and reduce sail damage in combat
else {
textShipSailSpeed.text = finalShip.battleSailSpeed;
}
// textShipBattleSailSpeed and textShipFullSailSpeed no longer used on counters, but still used in Info screens
var textShipBattleSailSpeed: TextField = new TextField();
textShipBattleSailSpeed.name = "textShipBattleSailSpeed";
textShipBattleSailSpeed.text = finalShip.battleSailSpeed;
textShipBattleSailSpeed.visible = false;
var textShipFullSailSpeed: TextField = new TextField();
textShipFullSailSpeed.name = "textShipFullSailSpeed";
textShipFullSailSpeed.text = finalShip.fullSailSpeed;
textShipFullSailSpeed.visible = false;
//create sailState (battle/full) indicator
var sailStateIndicator: WSIM_Counters_SailtState_Indicator = new WSIM_Counters_SailtState_Indicator();
//set indicator to correct sailState background graphic
sailStateIndicator.gotoAndStop("battle");
if ("full" == finalShip.sailState) {
sailStateIndicator.gotoAndStop("full");
}
sailStateIndicator.name = "sailStateIndicator";
finalShip.addChild(sailStateIndicator);
//add ship and attach text fields
gridBG1.addChild(finalShip);
finalShip.addChild(textShipName);
finalShip.addChild(textShipSailSpeed);
finalShip.addChild(textShipTurnAllowance);
finalShip.addChild(textShipBattleSailSpeed);
finalShip.addChild(textShipFullSailSpeed);
finalShip.parent.setChildIndex(finalShip, 1);
//logging
if (log_shipCreation) {
trace(finalShip.name + " added added as child of background in createShip()");
}
//create background sprite "ship is selected" border
var border: Sprite = new Sprite();
border.name = "shipBorder";
border.graphics.beginFill(0xFFCC00, 1);
border.graphics.drawRect(-1, -1, 52, 132)
border.graphics.endFill();
border.visible = false;
//create background sprite combat border
var borderCombat: Sprite = new Sprite();
borderCombat.name = "borderCombat";
//Great Britain ships are bright red, need to make combat border white
if ("GB" == finalShip.country) {
borderCombat.graphics.beginFill(0xFFFFFF, 1);
}
else {
borderCombat.graphics.beginFill(0xFF0000, 1);
}
borderCombat.graphics.drawRect(-1, -1, 52, 132)
borderCombat.graphics.endFill();
borderCombat.visible = false;
//add the borders as children of ship
finalShip.addChild(border);
finalShip.addChild(borderCombat);
//move the borders in z-order to behind ship counter, so they show looking like a border
border.parent.setChildIndex(border, border.parent.getChildIndex(border) - 5);
borderCombat.parent.setChildIndex(borderCombat, borderCombat.parent.getChildIndex(borderCombat) - 6);
//PUSH TO MASTER SHIP ARRAYS
//finalShip is Side 1, add to master list of ship objects for Side 1
if (sideList[0] == finalShip.country) {
shipListSide1.push(finalShip);
//logging
if (log_shipCreation) {
trace(finalShip.name + " added to Shiplist1 in createShip()");
}
}
//Side 2, add to master list of ship objects for Side 2
else {
shipListSide2.push(finalShip);
//logging
if (log_shipCreation) {
trace(finalShip.name + " added to Shiplist2 in createShip()");
}
}
//disable events on all children
finalShip.mouseChildren = false;
//ship selection event handler
finalShip.addEventListener(MouseEvent.CLICK, selectShip);
}

How could i make an array of removed tiles?

So i have a procedural generated game that loads in chunks, i need a way for my code to remember if i cut down a tree or broke a rock so it doesnt replace it when leaving and entering a new area. I got it almost working except instead of putting them back in the correct place, it moves them to fill in the blanks. (if that makes since)
this is the slimmed down function of what adds the removed tiles to my array of removed tiles
public function removeAndAddTile(tileRemoved:Function, tileAdded:Function, i:int)
{
world.removedTiles.push(world.tilesInWorld[i]);
}
This is what loads after the tiles get placed when entering an area. In other words, whats suppose to be replacing the tiles that have already been destroyed
protected function usedTiles()
{
for (var i:int = world.tilesInWorld.length - 1; i >= 0; --i)
{
for (var c:int = world.removedTiles.length - 1; c >= 0; --c)
{
if (world.tilesInWorld[i].x == world.removedTiles[c].x && world.tilesInWorld[i].y == world.removedTiles[c].y)
{
var ti:String = world.tilesInWorld[i].onTile;
var tx:int = world.removedTiles[c].x;
var ty:int = world.removedTiles[c].y;
world.worldTiles.removeChild(world.tilesInWorld[i]);
switch (ti)
{
case "grass" :
world.tilePool.returnSprite(world.tilesInWorld[i]);
break;
case "stone" :
world.rockPool.returnSprite(world.tilesInWorld[i]);
break;
}
world.tilesInWorld.splice(i, 1);
clicked = true;
switch (ti)
{
case "grass" :
world.tile = world.tilePool.getSprite();
break;
case "stone" :
world.tile = world.stonePool.getSprite();
break;
}
world.tile.width = world.TILE_SIZE;
world.tile.height = world.TILE_SIZE;
world.tile.x = tx;
world.tile.y = ty;
world.tilesInWorld.push(world.tile);
world.worldTiles.addChildAt(world.tile, i);
}
}
}
}
My question simply is, how can i get my tiles to remember when they have been destroyed and to delete and replace those tiles when entering an area?
http://www.fastswf.com/PJyyXsc
You could use two layers. One bottom layer for the map surface, and another detail layer contains trees, rocks. When your role moves and new area tiles appear, try to get the new area tiles data and add the trees, rocks to the new tile positions.
//the key may be tileX_tileY, the value will be the object type
//if a rock or a tree been broke,delete detailDic[tileX_tileY]
var detailDic:Dictionary;
When your role moves and enter a new area
var newTiles:Array;//the new appeared tiles
for each (var tile:Tile in newTiles)
{
var key:String = tile.tileX + "_" + tile.tileY;
var objectType:String = detailDic[key];
if (check ojectType is valid)
{
add the wanted tree, rock to target position.
}
}
//here you should remove the trees and rocks that disappear from your map's ViewPort

Using createjs, preoloading and caching, why is my canvas still so slow?

I am trying to create a small RPG for class. I create one Bitmap image, cache it, and then every time I need that same Bitmap, I clone it, and finally add them to the stage. However, despite my efforts, my canvas is still extremely slow since I am drawing all of these bushes.
I would put them in a container, however, I need to know the X and Y position that way I know if the player is trying to step over their boundaries.
Here is my function:
parseRoom: function(mapObject, room, obj, image){
var letter = 'X';
//var object = obj;
var object = null;
var img = new createjs.Bitmap(image);
for(var m=0; m < mapObject.length; m++){
for(var j=0; j< mapObject[m].length; j++){
letter = mapObject[j][m];
switch (letter){
case 'X':
//do nothing
break;
case 'O':
//object = this.createObject();
//object.image = img.clone();
img.cache();
object = img.clone();
room.AddObstacle(object, m, j);
break;
}
}
}
}
and this is my function when I actually add them to the stage:
addObstacle: function(imgObj, x, y){
imgObj.x = x ||imgObj.x || 0;
imgObj.y = y ||imgObj.y || 0;
imgObj.setVisible = function(visible){
this.visible = visible;
};
imgObj.update = function(){
if(this.visible)this.visible= true;
else this.visible = false;
};
objects.push(imgObj);
stage.addChild(imgObj);
},
as you can see, I extend the Bitmap class and also add and update and a setVisible method to it. That way I can turn them all off or on depending on the screen. Any ideas that could help me and make my game smoother? Thank you!
I was constantly updating every object, including the bushes, and there was no need to update the bushes every tick. I simply removed logic from checking the bushes and now it runs really fast.

Prevent Movie Clip Overlapsing

I'm creating a screen saver which requires a movie clip to be loaded to the stage at a random position based on the size of the screen, then fade out (which I have all of the animation within a movie clip as tweens)
I've hit a road block and can't figure out how to prevent the movie clips from overlapsing on top of each other. If anything, I'd like for them to appear at another random spot that does not cause the overlapse.
here is all of the code for my project:
stop();
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.Event;
import flash.display.Stage;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
var greystoneLogos:Array = new Array ;
var countTimeArray:Array = new Array ;
var previousLogos:Array = new Array ;
var xpoint:int;
var ypoint:int;
function getNewSymbols()
{
previousLogos = new Array ;
greystoneLogos = new Array ;
var i:int;
for (i=0; i < 3; i++)
{
greystoneLogos[i] = new GreystoneLogo1();
greystoneLogos[i].width = 100;
greystoneLogos[i].height = 60;
addSymbolToStage(greystoneLogos[i],i*2000);
}
}
getNewSymbols();
function addSymbolToStage(currentLogo:MovieClip,waitTime:int)
{
var i3:int;
var i4:int;
var logoBoundaries:Array = new Array()
var XandY:Array = new Array()
for (i3=0; i3 < greystoneLogos.length; i3++)
{
if (greystoneLogos[i3] !== currentLogo)
{
xpoint = randomRange(this.stage.stageWidth - (currentLogo.width * 4.8));
ypoint = randomRange(this.stage.stageHeight - (currentLogo.height * 6.9));
logoBoundaries = getOffDimensions(currentLogo)
for (i4=0; i4 < logoBoundaries.length; i4++)
{
XandY = logoBoundaries[i4].split(":")
while ((xpoint <= (Number(XandY[0]) + Number(currentLogo.width * 4.8)) && xpoint >= (Number(XandY[0]) - Number(currentLogo.width * 4.8))) && (ypoint <= (Number(XandY[1]) + Number(currentLogo.height * 6.9)) && ypoint >= (Number(XandY[1]) - Number(currentLogo.height * 6.9)))){
xpoint = randomRange(this.stage.stageWidth - (currentLogo.width * 4.8));
trace(XandY[0] + " And " + (Number(currentLogo.width * 4.8)))
trace(xpoint + " And " + (Number(XandY[0]) + Number(currentLogo.width * 4.8)))
ypoint = randomRange(this.stage.stageHeight - (currentLogo.height * 6.9));
}
}
}
else
{
continue;
}
}
previousLogos.push(currentLogo);
currentLogo.x = xpoint;
currentLogo.y = ypoint;
stage.addChild(currentLogo);
currentLogo.gotoAndStop(1);
var countTime:Timer = new Timer(waitTime,1);
countTime.addEventListener(TimerEvent.TIMER, function(){
currentLogo.gotoAndPlay(1);
currentLogo.addFrameScript ( currentLogo.totalFrames - 1 , function(){
currentLogo.stop()
stage.removeChild(currentLogo)
if(stage.numChildren <= 1){
getNewSymbols();
}
}) ;
});
countTime.start();
}
function getOffDimensions(currentLogo:MovieClip){
var i3:int;
var tempArr:Array = new Array()
for (i3=0; i3 < greystoneLogos.length; i3++)
{
if (greystoneLogos[i3] !== currentLogo){
tempArr[i3]=greystoneLogos[i3].x +":"+ greystoneLogos[i3].y
}
}
return tempArr
}
function randomRange(max:Number, min:Number = 0):Number
{
return Math.random() * (max - min) + min;
}
There are also may be a handful of unused variables from multiple things I've been trying out.
The code that I posted, will make the movie clip appear at a random spot based on the last movie clip that came up. So let's say we have 3 movie clips (the user will be able to change how many of the clips get displayed) 1 appears at 0,0 the other at 400,400 and the last one appears at 10,10 because I have no way of saving the previous values to compare in the while loop.
I hope this clarifies it a tad more
EDIT:
Based on a function shown below, I've added this:
for (i3=0; i3 < greystoneLogos.length; i3++)
{
if (greystoneLogos[i3] !== currentLogo && greystoneLogos[i3] != null)
{
while(currentLogo.hitTestObject(greystoneLogos[i3]) == true){
xpoint = randomRange(this.stage.stageWidth - (currentLogo.width));
ypoint = randomRange(this.stage.stageHeight - (currentLogo.height));
i3 = 0
}
}else{
continue;
}
}
Which results in a rather bad loop as well as the logo's still overlap above each other
The quickest way I can think to solve this is to do a hit test (http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html#hitTestObject()) on the new MovieClip and if it returns true, run the placement code again
Ok, here's the implementation of this quickest way.
You can track your present displayObject by the .numChildren property. You don't even need an array of your logos or things. Let's say you have a function that adds new movieClip to your screen. It knows how many clips you can have (MovieClipDummy is just my testing class - it draws a circle with a specified radius. It should be replaced by your objects).
private function addAnotherMovieClip(): void {
if (_currentDummmiesCount < _dummmiesCount) {
var newDummy: MovieClipDummy = new MovieClipDummy(90);
addChild(newDummy);
//If we get a stackoverflow error (see below)
//we just remove our object from the screen as it will most likely just won't fit
if (checkForEmptySpace(newDummy) != "") {
removeChild(newDummy);
return;
}
} else {
//Do nothing or do something
}
}
It calls another function, checkForEmptySpace, which tries to place your movieclip so it won't overlap with other objects. Here it is:
private function checkForEmptySpace(newClip: Sprite): String {
//you should store your screen width somewhere.
//you can also call stage.stageWidth instead, but first make sure that you
//always have a link to the stage or it will throw an error
newClip.x = Math.random() * _screenWidth;
newClip.y = Math.random() * _screenHeight;
//===========================
//Important part - we try to check all the present children of our container
//numChildren is a property of the DisplayObjectContainer
for (var i: int; i < numChildren; i++) {
//We need a try here because we will get a StackOverflow error if there's no empty space left
try {
//We need to check if our current display object, received with getChildAt()
//is not the same as the one we've just added to the screen
//And if our new object intersects with ANY other object on the stage - we
//call THIS function once again.
//We do recursion because we can easily catch an error and remove this object from
//the screen
if (newClip != getChildAt(i) && newClip.hitTestObject(getChildAt(i))) {
//If our recursive function returns an error - we should pass it further
if (checkForEmptySpace(newClip) != "") {
return "error";
}
}
//The only error that can go here is stackoverflow error. So when we get one
//we return this error string
} catch (error: Error) {
trace(error);
return "error";
}
}
//We only return this empty string if we don't have stackoverflow error
//so there's possibly no space left for another movieclip
return "";
}
You can do it without recursion, but you will have to check for empty space with another logic.
And, you can do it more "professionally" by using Minkowski addition. You should consider storing an array of "boundary" points of your movieclips (let's say every movieclip is a rectangle) and when you add a new object to the screen, you calculate this Minkowsky addition. It will have some "free" spots on your screen which represent any possible coordinates of your new movieclip. It's pretty interesting to implement something like that because the accuracy will be phenomenal. But if you don't have time - just use that recursive placement function

Flash AS3 Collision detection to outer walls

I'm new on here and needing a little help. Basically I'm designing a Pac-man like game which it has to be based on Wind in the Willows, so Mole-man it is!!
Anyway, I've done the basics of it, I've made my 2d mole, made him move, made him react to button presses etc. and now trying to get the walls to work, starting with the outer walls.
I made 4 rectangles around the edge, merged them to one shape and called it "outerWalls". I've been using hitTestObject to try and get it to work but with no success.
I did a test to make it work with moleman.xIncrement = -5 which makes him immediately move backwards without touching any walls. I am curious as to if this is because he is inside of the walls and it classes 4 outer walls as a square overall and as he is already inside the theoretical square moves him out? I am unsure. Have some code!!
Actions layer - frame 1:
import flash.events.KeyboardEvent;
var moleman = this.addChild(new Moleman_mc());
moleman.x = 100;
moleman.y = 200;
moleman.width = 24;
moleman.height = 24;
moleman.xIncrement = 5;
moleman.yIncrement = 0;
stage.addEventListener(KeyboardEvent.KEY_DOWN, doKeyDown);
function doKeyDown (e:KeyboardEvent):void
{
switch(e.keyCode)
{
case Keyboard.UP:
moleman.xIncrement = 0;
moleman.yIncrement = -5;
moleman.rotation = -90;
break;
case Keyboard.DOWN:
moleman.xIncrement = 0;
moleman.yIncrement = 5;
moleman.rotation = 90;
break;
case Keyboard.LEFT:
moleman.xIncrement = -5;
moleman.yIncrement = 0;
moleman.rotation = 180;
break;
case Keyboard.RIGHT:
moleman.xIncrement = 5;
moleman.yIncrement = 0;
moleman.rotation = 0;
break;
}
}
Actions layer - frame 2:
import flash.events.Event;
var collectCounter:int = 0;
moleman.x += moleman.xIncrement;
moleman.y += moleman.yIncrement;
if(moleman.hitTestObject(collect))
{
collectCounter ++;
collect.visible = false;
}
moleman.addEventListener(Event.ENTER_FRAME, wallHit);
function wallHit(event:Event):void
{
if(moleman.hitTestObject(outerWalls))
{
moleman.stop();
}
}
Actions layer - frame 3:
gotoAndPlay(2);
In addition, I cannot get the collect (e.g. collectables) to work, the plan would be to make it so each time you collect one "collect" item, that one disappears, you add one to collectCounter but all others stay visible. Currently if you collect one "collect" item, moleman just stops and stays where he is while another moleman appears and continues, not very useful. Any help on this would also be appreciated, not sure where to take it from there.
Any help is much appreciated, I am new at this but hoping it can go well :)
All help is much appreciated.
John.
In your case to detect collision you should use hitTestPoint method instead of hitTestObject. hitTestPoint method has the signature:
public function hitTestPoint(x:Number, y:Number, shapeFlag:Boolean = false):Boolean
so, when shapeFlag is set to true, it is possible to detect collision with the point (your hero) and maze shape (or any other arbitrary shape). This method is very powerful because the intersection with the real shape, not its bounding box is calculated. Modified wallHit method may look like this:
moleman.addEventListener(Event.ENTER_FRAME, wallHit);
function wallHit(event:Event):void
{
if(outerWalls.hitTestPoint(moleman.x, moleman.y, true))
{
// collision
moleman.x += -moleman.xIncrement;
moleman.y += -moleman.yIncrement;
moleman.xIncrement=0;
moleman.yIncrement=0;
}
moleman.x += moleman.xIncrement;
moleman.y += moleman.yIncrement;
if(moleman.hitTestObject(collect))
{
collectCounter ++;
collect.visible = false;
}
}
you may also remove frame 3 and "gotoAndPlay(2);" call because it is better to put the code which controls hero's position into ENTER_FRAME handler either.