I'm trying to create a drag and drop game in Actionscript 3 using mostly arrays. I'm doing it on a simpler game first before going to the main game because I need to know how the codes work first.
The simpler game is just there are two squares and two circles. The two squares are on a different array while the two circles are in the same one. What should happen is that when either circles hit (hitTestPoint) the right square, their x and y becomes the center of the square. (like it clicks to the center). And when either circles hit the left square, it should return the circles to their last position (doesn't have to be their original position).
Here's the code:
package
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.display.DisplayObject;
import flash.geom.Point;
import flash.events.Event;
public class MC_MAIN extends MovieClip
{
var mc1:mc_circle;
var mc2:mc_circle;
var mc3:mc_square;
var mc4:mc_square;
var Shapes:Array;
var Target:Array;
var WTarget:Array;
var newPlace:Point;
public function MC_MAIN()
{
// constructor code
init();
}
function init():void
{
Shapes = new Array ;
Target = new Array ;
WTarget = new Array ;
mc3 = new mc_square();
mc3.height = 75;
mc3.width = 75;
mc3.x = 400;
mc3.y = 200;
Target.push(mc3);
addChild(mc3);
mc4 = new mc_square();
mc4.height = 75;
mc4.width = 75;
mc4.x = 150;
mc4.y = 200;
WTarget.push(mc4);
addChild(mc4);
mc1 = new mc_circle();
mc1.height = 25;
mc1.width = 25;
mc1.x = 100;
mc1.y = 100;
Shapes.push(mc1);
addChild(mc1);
mc2 = new mc_circle();
mc2.height = 25;
mc2.width = 25;
mc2.x = 200;
mc2.y = 200;
Shapes.push(mc2);
addChild(mc2);
for (var i:int = 0; i<Shapes.length; i++)
{
Shapes[i].addEventListener(MouseEvent.MOUSE_DOWN, DRG);
Shapes[i].addEventListener(MouseEvent.MOUSE_UP, SDRG);
}
}
function DRG(e:MouseEvent):void
{
e.currentTarget.startDrag();
}
function SDRG(e:MouseEvent):void
{
e.currentTarget.stopDrag();
for (var m:int = 0; m<Shapes.length; m++)
{
newPlace = new Point(Shapes[m].x,Shapes[m].y);
}
trace(newPlace);
for (var a:int = 0; a<Target.length; a++)
{
for (var b:int = 0; b<Shapes.length; b++)
{
if (Target[a].hitTestPoint(Shapes[b].x,Shapes[b].y))
{
Shapes[b].x = Target[a].x;
Shapes[b].y = Target[a].y;
}
}
}
for (var c:int = 0; c<WTarget.length; c++)
{
for (var d:int = 0; d<Shapes.length; d++)
{
if (WTarget[c].hitTestPoint(Shapes[d].x,Shapes[d].y))
{
Shapes[d].x = newPlace.x;
Shapes[d].y = newPlace.y;
}
}
}
}
}
}
What happens is that the code for the left square doesn't work but their are no syntax errors. Nothing happens when either circles hit the left square.
And when I'm trying to trace the position of the circles, It just shows the x & y coordinate of only one of them. (I guess it's tracing the first object of the array which is at index 0. I'm just asking if I guessed right for this part.)
I is a bit difficult to follow the logic and there are some points that doesn't make much sense like:
for (var m:int = 0; m<Shapes.length; m++)
{
newPlace = new Point(Shapes[m].x,Shapes[m].y);
}
newPlace will be the position of the last shape in Shapes, so the loop is fairly useless.
I guess what you need is something like that:
public class MC_MAIN extends MovieClip
{
private leftSquares:Array;
private rightSquares:Array;
//more of the members from above
private startPos:Point;
//init the thing and add left and right squares
//to there respective Array
function DRG(e:MouseEvent):void
{
var t:DisplayObject = e.currentTarget;
//save the starting position
startPos = new Point(t.x,t.y);
t.startDrag();
}
function SDRG(e:MouseEvent):void {
var t:DisplayObject = e.currentTarget;
//find all squares from the left
//the target »hits«
var leftHits:Array = leftSquares.filter(
function (square:DisplayObject) {
return square.hitTestPoint(t.x, t.y);
});
//same for the right
var leftHits:Array = rightSquares.filter(
function (square:DisplayObject) {
return square.hitTestPoint(t.x, t.y);
});
//now you can apply the logic
//based on the hit Test result
//this way you can handle the case
//if it hits both, to throw an error
//or alike
if(leftHits.length > 0) {
//reset position
t.x = startPos.x;
t.y = startPos.y;
}
else if (rightHits.length > 0) {
//set the position tp the desired item in rightHits
}
else {
}
}
}
Please not that my Action Script skills haven't been used for a long time, so the code above might not compile. It is meant to illustrate the idea. Important are the following steps:
1. Save the starting position, to be able to reset it
2. Sort the `squares` in respective lists for left and right
3. Hit test both and apply the logic.
Related
For a yearly Christmas event for an organization I'm a part of, we usually hold a raffle where people have the opportunity to win free prizes by just attending and getting a number ticket at the door. We use a program written in Flash (Using ActionScript 2.0) that selects a random number utilizing math.random, with some parameters attached to it, as shown below:
//maxNr = 999999999999999;
initRandom = function(){
var nr = Math.ceil(Math.ceil(Math.random()*(maxNr));
var nrString = "";
for( var j=0; j<(maxNr.toString().length-nr.toString().length); j++){
nrString += "0";
}
nrString += nr.toString();
var holder = this.createEmptyMovieClip("holder",1);
for( i=0; i<maxNr.toString().length; i++ ){
var mc = holder.attachMovie("number","n"+i,i+10);
mc._x = i*350;
mc.anim_mc.gotoAndPlay( Math.floor(Math.random()*9) + 1 );
this["iv"+i] = setInterval( this, "revealNumber", 2000 + (500*i), nrString.substr(i,1), i );
}
// scale (if needed) and center
if( holder._width > Stage.width ){
holder._width = Stage.width;
holder._yscale = holder._xscale;
}
holder._x = Stage.width/2 - holder._width/2;
holder._y = 100;
// buttons
back_btn.onRelease = function(){
for(item in holder){
holder[item].removeMovieClip();
}
gotoAndStop("intro");
}
}
revealNumber = function( digit, i ){
clearInterval( this["iv"+i] );
holder["n"+i].gotoAndStop("done");
holder["n"+i]["number_txt"].text = digit;
}
initRandom();
stop();
It's meant to return a random number between 1 and 1000, as defined by:
go_btn.onRelease = function(){
maxNr = Math.max( 1000 , 1 );
gotoAndStop("random");
}
stop();
It was written by a member of our organization who unfortunately passed away during the year, and I have little to no programming knowledge but I am a quick learner and have actually modified some of the code to get to the point it is currently. However, I'm trying to add in a parameter that would disallow the function from repeating a number, ie, excluding an already generated number from being reselected.
I've spent days scouring any resource possible and have only met dead ends.
With the approach currently taken, is it possible to add in this parameter to this existing code, and how can I go about doing that?
Any help, suggestion or reply would be very greatly appreciated!
package
{
public class RandomGenerator
{
private var _st:Number;
private var _en:Number;
private var _len:Number;
private var _pos:Number;
private var _numPos:Number;
private var _myNums:Array;
private var _randNums:Array;
public function RandomGenerator(en:Number, st:Number = 0)
{
_st = st;
_en = en;
// just in case if params order mixup:
if(en < st){
_st = en;
_en = st;
}
_len = _en - _st + 1;
shuffle();
}
public function getNum():Number
{
// if passed last item:
if(_numPos == _len)shuffle();
var myResult:Number = _randNums[_numPos];
_numPos++;
return myResult;
}
private function shuffle():void
{
_numPos = 0;
_randNums = [];
_myNums = [];
// Creating Numbers Array:
var i:Number;
for(i = 0; i<_len; i++){ _myNums[i] = _st + i; }
// Creating shuffled Numbers Array:
i = 0;
while(_myNums.length > 0){
_pos = Math.round(Math.random()*(_myNums.length-1));
_randNums[i] = _myNums[_pos];
i++;
_myNums.splice(_pos,1);
}
}
public function get len():Number
{
return _len;
}
}
}
make an object from this class for example cardGenerator:RandomGenerator = new RandomGenerator(51, 0) and finally you can get random number without repeat with this codes:
for (var i:int = 0; i < cardGenerator.len; i++) {
trace(cardGenerator.getNum());
}
My AS2 is a bit rusty, but I think the following script explains the general idea. You need some registry to record generated numbers so you can skip them next time you generate one. I used the _global object so that this logic transcends even multiple instances of the following script.
// Create an Array to record generated numbers.
// The _global object is always present and can be accessed from anywhere.
if (_global.uniqueNr == undefined)
{
_global.uniqueNr = [];
}
function initRandom()
{
var nr;
do
{
nr = Math.ceil(Math.ceil(Math.random()*(maxNr));
}
while (_global.uniqueNr[nr] == true);
// Record the newly generated number so it would never drop again.
_global.uniqueNr[nr] = true;
// At this point you can be sure that "nr" contains a unique value.
So i am adding some elements to a map control like this
foreach (var res in results)
{
if (res.geometry.location != null)
{
var pushpin = new Image();
pushpin.Name = "a";
BasicGeoposition bs = new BasicGeoposition { Latitude = res.geometry.location.lat, Longitude = res.geometry.location.lng };
pushpin.Source = new BitmapImage(uri);
pushpin.Height = 50;
pushpin.Width = 50;
myMap.Children.Add(pushpin);
MapControl.SetLocation(pushpin, new Geopoint(bs));
}
}
Now i want to remove elements names "a" form the control and i am using following code
int c = myMap.Children.Count;
for (int i = 0; i < c; i++)
{
if(myMap.Children.ElementAt(i) is Image)
{
var z = myMap.Children.ElementAt(i) as Image;
if(z.Name.Equals("a"))
{
myMap.Children.Remove(myMap.Children.ElementAt(i));
}
}
}
But always some elements are not getting removed ,for example the count of children is coming 21,but the loop is looping only 10 time.
How can i solve this problem?
try it with looping backwards so you dont mess up your collection during the loop.
int c = myMap.Children.Count - 1;
for (int i = c; i >= 0; i--)
{
if (myMap.Children.ElementAt(i) is Image)
{
var z = myMap.Children.ElementAt(i) as Image;
if(z.Name.Equals("a"))
{
myMap.Children.Remove(myMap.Children.ElementAt(i));
}
}
}
Im making a game and i complete the level1 at frame1.
When im trying to make the level2 to frame2 i dont know how to transfer my Arrays
to frame2.All the other buttons and functions are working(i copy the eventListeners to frame2)but my enemies wich are in Arrays does nothing!!
Thanks a lot!!!
import flash.events.Event;
stop();
//variables the helicopters
var enemy1Array:Array = new Array();
for (var e1:int = numChildren - 1; e1 >= 0; e1--)
{
var child:DisplayObject = getChildAt(e1);
if (child.name == "enemy1")
{
enemy1Array.push(child);
}
}
stage.addEventListener(Event.ENTER_FRAME, allloop);
function allloop(event:Event):void
{
//move the helicopters
for each(var enemy1:Sprite in enemy1Array)
{
enemy1.x = enemy1.x -= enemy1speed;
if(enemy1.hitTestObject(defense))
{
addChild(explotionbonus3);
explotionbonus3.gotoAndPlay(2);
explotionbonus3.x = enemy1.x;
explotionbonus3.y = enemy1.y;
enemy1.y = 1000;
score -=5;
scoretxt.text = String (score);
}
}
}
I'm using a tutorial I found on Google - which works well. However, I have a few issues to make it work how I would like. This code uses a MovieClip for the card faces with the back of the card on frame1 and 2-17 different pictures or movieclips.
The questions are - Is there a way to get the ActionScript to choose from the whole array? But still produce pairs to choose from. As it stands now - If I select the game to be 4 across by 2 down (8 cards in total) It has the back of card (frame1) and will then randomly select, but only from frames 2-5 . If I modify these lines...
public function MatchingGameObject10():void {
// make a list of card numbers
var cardlist:Array = new Array();
for(var i:uint=0;i<boardWidth*boardHeight/2;i++) {
cardlist.push(i);
cardlist.push(i);
}
to
public function MatchingGameObject10():void {
// make a list of card numbers
var cardlist:Array = new Array(0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16,17,17);
}
I get random cards - but no pairs...
If I can ask another question here - it is - how to add a seperate sound to each card..So if it shows a Bee - the Bee.mp3 is played.. Here's the whole code..
package {
import flash.display.*;
import flash.events.*;
import flash.text.*;
import flash.utils.getTimer;
import flash.utils.Timer;
import flash.media.Sound;
import flash.media.SoundChannel;
public class MatchingGameObject10 extends MovieClip {
// game constants
private static const boardWidth:uint = 4;
private static const boardHeight:uint = 2;
private static const cardHorizontalSpacing:Number = 500;
private static const cardVerticalSpacing:Number = 700;
private static const boardOffsetX:Number = 50;
private static const boardOffsetY:Number = 70;
private static const pointsForMatch:int = 10;
private static const pointsForMiss:int = -1;
// variables
private var firstCard:Card10;
private var secondCard:Card10;
private var cardsLeft:uint;
private var gameScore:int;
private var gameStartTime:uint;
private var gameTime:uint;
// text fields
private var gameScoreField:TextField;
private var gameTimeField:TextField;
// timer to return cards to face-down
private var flipBackTimer:Timer;
// set up sounds
var theFirstCardSound:FirstCardSound = new FirstCardSound();
var theMissSound:MissSound = new MissSound();
var theMatchSound:MatchSound = new MatchSound();
// initialization function
public function MatchingGameObject10():void {
// make a list of card numbers
var cardlist:Array = new Array();
for(var i:uint=0;i<boardWidth*boardHeight/2;i++) {
cardlist.push(i);
cardlist.push(i);
}
// create all the cards, position them, and assign a randomcard face to each
cardsLeft = 0;
for (var x:uint=0; x<boardWidth; x++) {// horizontal
for (var y:uint=0; y<boardHeight; y++) {// vertical
var c:Card10 = new Card10();// copy the movie clip
c.stop();// stop on first frame
c.x = x*cardHorizontalSpacing+boardOffsetX;// set position
c.y = y*cardVerticalSpacing+boardOffsetY;
var r:uint = Math.floor(Math.random()*cardlist.length);// get a random face
c.cardface = cardlist[r];// assign face to card
cardlist.splice(r,1);// remove face from list
c.addEventListener(MouseEvent.CLICK,clickCard);// have it listen for clicks
c.buttonMode = true;
addChild(c);// show the card
cardsLeft++;
}
}
// set up the score
gameScoreField = new TextField();
addChild(gameScoreField);
gameScore = 0;
showGameScore();
// set up the clock
gameTimeField = new TextField();
gameTimeField.x = 450;
addChild(gameTimeField);
gameStartTime = getTimer();
gameTime = 0;
addEventListener(Event.ENTER_FRAME,showTime);
}
// player clicked on a card
public function clickCard(event:MouseEvent) {
var thisCard:Card10 = (event.target as Card10); // what card?
if (firstCard == null) { // first card in a pair
firstCard = thisCard; // note it
thisCard.startFlip(thisCard.cardface+2);
playSound(theFirstCardSound);
} else if (firstCard == thisCard) { // clicked first card again
firstCard.startFlip(1);
firstCard = null;
playSound(theMissSound);
} else if (secondCard == null) { // second card in a pair
secondCard = thisCard; // note it
thisCard.startFlip(thisCard.cardface+2);
// compare two cards
if (firstCard.cardface == secondCard.cardface) {
// remove a match
removeChild(firstCard);
removeChild(secondCard);
// reset selection
firstCard = null;
secondCard = null;
// add points
gameScore += pointsForMatch;
showGameScore();
playSound(theMatchSound);
// check for game over
cardsLeft -= 2; // 2 less cards
if (cardsLeft == 0) {
MovieClip(root).gameScore = gameScore;
MovieClip(root).gameTime = clockTime(gameTime);
MovieClip(root).gotoAndStop("gameover");
}
} else {
gameScore += pointsForMiss;
showGameScore();
playSound(theMissSound);
flipBackTimer = new Timer(2000,1);
flipBackTimer.addEventListener(TimerEvent.TIMER_COMPLETE,returnCards);
flipBackTimer.start();
}
} else { // starting to pick another pair
returnCards(null);
playSound(theFirstCardSound);
// select first card in next pair
firstCard = thisCard;
firstCard.startFlip(thisCard.cardface+2);
}
}
// return cards to face-down
public function returnCards(event:TimerEvent) {
firstCard.startFlip(1);
secondCard.startFlip(1);
firstCard = null;
secondCard = null;
flipBackTimer.removeEventListener(TimerEvent.TIMER_COMPLETE,returnCards);
}
public function showGameScore() {
gameScoreField.text = "Score: "+String(gameScore);
}
public function showTime(event:Event) {
gameTime = getTimer()-gameStartTime;
gameTimeField.text = "Time: "+clockTime(gameTime);
}
public function clockTime(ms:int) {
var seconds:int = Math.floor(ms/1000);
var minutes:int = Math.floor(seconds/60);
seconds -= minutes*60;
var timeString:String = minutes+":"+String(seconds+100).substr(1,2);
return timeString;
}
public function playSound(soundObject:Object) {
var channel:SoundChannel = soundObject.play();
}
}
}
Here's Card10 class
package {
import flash.display.*;
import flash.events.*;
public dynamic class Card extends MovieClip {
private var flipStep:uint;
private var isFlipping:Boolean = false;
private var flipToFrame:uint;
// begin the flip, remember which frame to jump to
public function startFlip(flipToWhichFrame:uint) {
isFlipping = true;
flipStep = 10;
flipToFrame = flipToWhichFrame;
this.addEventListener(Event.ENTER_FRAME, flip);
}
// take 10 steps to flip
public function flip(event:Event) {
flipStep--; // next step
if (flipStep > 5) { // first half of flip
this.scaleX = .20*(flipStep-6);
} else { // second half of flip
this.scaleX = .20*(5-flipStep);
}
// when it is the middle of the flip, go to new frame
if (flipStep == 5) {
gotoAndStop(flipToFrame);
}
// at the end of the flip, stop the animation
if (flipStep == 0) {
this.removeEventListener(Event.ENTER_FRAME, flip);
}
}
}
}
So without completely re-factoring how this game works, the best way to make it dynamic based off the amount of frames (card faces) in your Card10 Clip, is change this code:
var cardlist:Array = new Array();
for(var i:uint=0;i<boardWidth*boardHeight/2;i++) {
cardlist.push(i);
cardlist.push(i);
}
To the following:
var allCards:Array = new Array(); //an array of all available frame numbers
var cardlist:Array = new Array(); //an array of just those cards to show
var tmpCard:Card10 = new Card10(); //create a temporary card for the sole purpose of counting how many frames it has
var i:int;
//populate the array with all the frames from the Card MC
for (i = 0; i < tmpCard.totalFrames;i++) {
allCards.push(i);//add card frame to allCards array
}
//now create the list of cards to show (since the amount of cards may be more than the amount you want to show
for (i = 0; i < (boardWidth * boardHeight) / 2; i++) {
var cardIndex:int = Math.floor(Math.random() * allCards.length);// get a random card from the all card list
//add the card twice (so there is a pair) in the list of cards to show
cardlist.push(cardIndex);
cardlist.push(cardIndex);
//remove it from the all cards array so it doesn't come up again in the random bit above
allCards.splice(cardIndex,1);
}
Time for a really nooby question, but I can't find a satisfying answer.. Everytime I search for array tutorials, they are about how you put different strings of text into an array and accessing them again.
Here is what I have:
When you start the game, you are able to press lets just say 5 buttons. When you press button 1 flash (simplified) goes:
addChild(backGround)
addChild(world)
world.gotoAndStop(1)
addChild(character)
And so on with the other buttons, changing which world you're in.
Here is what I want:
I want to be able to add the same enemy movieclip specific places, according to which button the player presses.
So let's say the player presses button 3, and in world 3 I want there to be an enemy at x 200, y 300, and an enemy at x 600, y 450 and one more enemy some other specific place. All enemies are the same movieclip.
So how can add enemies like that???
I know I need an array, but how do i access the movieclip like I want to?
My code:
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class Main extends MovieClip {
public var character:Character;
public var backGround:BackGround;
public var world:World;
public var worldMap:WorldMap;
public var monster1:Monster1;
public var worldLevel:int;
public var currentLevel:int;
public function Main() {
backGround = new BackGround;
world = new World;
monster1 = new Monster1
character = new Character();
worldMap = new WorldMap;
// Every world lies in a different frame in the "world" movieclip
world.worldDangers.gotoAndStop(currentLevel);
world.SafeGround.gotoAndStop(currentLevel);
world.GroundViz.gotoAndStop(currentLevel);
world.PortaltoNew.gotoAndStop(currentLevel);
//----- on the world map is the different world buttons ---
addChild(worldMap);
addEventListener(Event.ENTER_FRAME, moveWorld)
//------------------- world buttons --------------------
worldMap.buttonWorld1.addEventListener(MouseEvent.CLICK, gotoWorld1)
worldMap.buttonWorld2.addEventListener(MouseEvent.CLICK, gotoWorld2)
worldMap.buttonWorld3.addEventListener(MouseEvent.CLICK, gotoWorld3)
worldMap.buttonWorld4.addEventListener(MouseEvent.CLICK, gotoWorld4)
}
function gotoWorld1 (m:MouseEvent):void
{
currentLevel = 1;
addChild(backGround);
addChild(world);
world.x = 0;
world.y = 0;
isinWorld = true
addChild(character);
character.x = 300;
character.y = 650;
character.gotoAndStop(3);
worldMap.parent.removeChild(worldMap);
}
//----------------- function world 2 ---------------------
function gotoWorld2 (m:MouseEvent):void
{
currentLevel = 2;
addChild(backGround);
addChild(world);
world.x = 0;
world.y = 0;
isinWorld = true
addChild(character);
character.x = 300;
character.y = 650;
character.gotoAndStop(3);
worldMap.parent.removeChild(worldMap);
}
//----------------- function world 3 -----------------------
function gotoWorld3 (m:MouseEvent):void
{
currentLevel = 3;
addChild(backGround);
addChild(world);
world.x = 0;
world.y = 0;
isinWorld = true
addChild(character);
character.x = 300;
character.y = 650;
character.gotoAndStop(3);
worldMap.parent.removeChild(worldMap);
}
function gotoWorld4 (m:MouseEvent):void
{
currentLevel = 4;
addChild(backGround);
addChild(world);
world.x = 0;
world.y = 0;
isinWorld = true
addChild(character);
character.x = 300;
character.y = 650;
character.gotoAndStop(3);
worldMap.parent.removeChild(worldMap);
}
function moveWorld (e:Event)
{
if (isinWorld)
{
world.y = world.y + 5;
if (character.hitTestObject(monster1))
{
world.parent.removeChild(world);
backGround.parent.removeChild(backGround);
character.parent.removeChild(character);
isinWorld = false
}
}
}
}
}
Something like the following should do the trick:
// Define a bunch of positions for this world
var positions:Array = [
new Point(200, 300),
new Point(600, 450),
new Point(50, 350)
];
// Probably makes sense to store your enemies on
// an array for access later in your game
var enemies:Array = [];
// Temporary variables for the loop
var enemy:Enemy;
var position:Point;
// Iterate over the positions array
for (var i:int = 0; i < positions.length; i ++)
{
// Get the position
position = positions[i] as Point;
// Create a new enemy and position him
enemy = new Enemy();
enemy.x = position.x;
enemy.y = position.y;
// Add child and store it on an array
addChild(enemy);
enemies.push(enemy);
}