Action Script 3. How to count game time? - actionscript-3

I'm creating Flash "memory" game, Idea to discover 2 equal cards. I need to add "Timer" in top of window which count in how many seconds all cards will be descovered.
Here is my code:
package
{
import flash.display.MovieClip;
import Card;
import Boarder;
import BlueBoard;
import flash.events.MouseEvent;
import RedBoard;
import Snow;
public class MemoryGame extends MovieClip
{
private var _card:Card;
private var _boarder:Boarder;
private var _blueBoard:BlueBoard;
private var _cardX:Number;
private var _cardY:Number;
private var _firstCard:*;
private var _totalMatches:Number;
private var _currentMatches:Number;
private var _redBoard:RedBoard;
private var _snow:Snow;
private var _cards:Array;
public var _message:String;
public function MemoryGame()
{
_cards = new Array();
_totalMatches = 4;
_currentMatches = 0;
createCards();
}
private function createCards():void
{
_cardX = 45;
_cardY = 10;
for(var i:Number = 0; i < 2; i++)
{
_card = new Card();
addChild(_card);
_boarder = new Boarder();
_card.setType(_boarder);
_card.x = _cardX;
_card.y = _cardY;
_cardX += _card.width + 50;
_card.addEventListener(MouseEvent.CLICK, checkCards);
_cards.push(_card);
}
for(var j:Number = 0; j < 2; j++)
{
_card = new Card();
addChild(_card);
_blueBoard = new BlueBoard();
_card.setType(_blueBoard);
_card.x = _cardX;
_card.y = _cardY;
_cardX += _card.width + 50;
_card.addEventListener(MouseEvent.CLICK, checkCards);
_cards.push(_card);
}
_cardX = 45;
_cardY = _card.height + 30;
for(var k:Number = 0; k < 2; k++)
{
_card = new Card();
addChild(_card);
_redBoard = new RedBoard();
_card.setType(_redBoard);
_card.x = _cardX;
_card.y = _cardY;
_cardX += _card.width + 50;
_card.addEventListener(MouseEvent.CLICK, checkCards);
_cards.push(_card);
}
for(var l:Number = 0; l < 2; l++)
{
_card = new Card();
addChild(_card);
_snow = new Snow();
_card.setType(_snow);
_card.x = _cardX;
_card.y = _cardY;
_cardX += _card.width + 50;
_card.addEventListener(MouseEvent.CLICK, checkCards);
_cards.push(_card);
}
randomizeCards(_cards);
}
private function checkCards(event:MouseEvent):void
{
event.currentTarget.removeEventListener(MouseEvent.CLICK, checkCards);
if(_firstCard == undefined)
{
_firstCard = event.currentTarget;
}
else if(String(_firstCard._type) == String(event.currentTarget._type))
{
trace("match");
_message = "match";
message_txt.text = _message;
_firstCard = undefined;
_currentMatches ++;
if(_currentMatches >= _totalMatches)
{
trace("YOU WIN !!!");
_message = "YOU WIN !!!";
message_txt.text = _message;
}
}
else
{
trace("wrong");
_message = "wrong";
message_txt.text = _message;
_firstCard.gotoAndPlay("flipBack");
event.currentTarget.gotoAndPlay("flipBack");
_firstCard.addEventListener(MouseEvent.CLICK, checkCards);
event.currentTarget.addEventListener(MouseEvent.CLICK, checkCards);
_firstCard = undefined;
}
}
private function randomizeCards(cards:Array):void
{
var randomCard1:Number;
var randomCard2:Number;
var card1X:Number;
var card1Y:Number;
for(var i:Number = 0; i < 10; i++)
{
randomCard1 = Math.floor(Math.random() * cards.length);
randomCard2 = Math.floor(Math.random() * cards.length);
card1X = cards[randomCard1].x;
card1Y = cards[randomCard1].y;
cards[randomCard1].x = cards[randomCard2].x;
cards[randomCard1].y = cards[randomCard2].y
cards[randomCard2].x = card1X;
cards[randomCard2].y = card1Y;
}
}
}
}
EDIT:
And I have one more question. When I will add this game to PHP, how can I add username and his time to database? I need write code in Action Script (swf file) or I can do it in php later? I mean in php can I use any method to get time from swf file and write it to database?
Could you help me? Thank you very much.

Here is an example of how to use the Timer class (flash.utils.Timer) to accomplished what you're asking:
var timer:Timer; //import flash.utils.Timer;
var txtTime:TextField;
var tmpTime:Number; //this will store the time when the game is started
//your constructor:
public function MemoryGame()
{
timer = new Timer(1000); //create a new timer that ticks every second.
timer.addEventListener(TimerEvent.TIMER, tick, false, 0, true); //listen for the timer tick
txtTime = new TextField();
addChild(txtTime);
tmpTime = flash.utils.getTimer();
timer.start(); //start the timer
//....the rest of your code
}
private function tick(e:Event):void {
txtTime.text = showTimePassed(flash.utils.getTimer() - tmpTime);
}
//this function will format your time like a stopwatch
function showTimePassed(startTime:int):String {
var leadingZeroMS:String = ""; //how many leading 0's to put in front of the miliseconds
var leadingZeroS:String = ""; //how many leading 0's to put in front of the seconds
var time = getTimer() - startTime; //this gets the amount of miliseconds elapsed
var miliseconds = (time % 1000); // modulus (%) gives you the remainder after dividing,
if (miliseconds < 10) { //if less than two digits, add a leading 0
leadingZeroMS = "0";
}
var seconds = Math.floor((time / 1000) % 60); //this gets the amount of seconds
if (seconds < 10) { //if seconds are less than two digits, add the leading zero
leadingZeroS = "0";
}
var minutes = Math.floor( (time / (60 * 1000) ) ); //60 seconds times 1000 miliseocnds gets the minutes
return minutes + ":" + leadingZeroS + seconds + "." + leadingZeroMS + miliseconds;
}
//in your you-win block of code:
var score = flash.utils.getTimer() - tmpTime; //this store how many milliseconds it took them to complete the game.
This creates a timer that will tick every second, and update a text field with the current amount of seconds elapsed
As per the second part of your request, here is a way you can do this (the database work needs to be done in PHP, this shows you how to send the data to a php page)
var urlLoader:URLLoader = new URLLoader();
urlLoader.addEventListener(Event.COMPLETE, scoreSaveResponse,false,0,true);
var request:URLRequest = new URLRequest("http://mysite.com/score.php");
var urlVars:URLVariables = new URLVariables();
urlVars.time = flash.utils.getTimer() - tmpTime;
urlVars.userName = "yourUserName";
//add any other parameters you want to pass to your PHP page
request.method = URLRequestMethod.POST;
urlLoader.data = urlVars;
urlLoader.load(request);
function scoreSaveResponse(e:Event):void {
//whatever you return from the php page is found in urlLoader.data
}

Related

Actionscript Double Buffer Audio playback by upscaling

I've been working on a way to stream mic data to a server, cycle back to clients, and play back in a packet by packet manner. So far, I have the client connectivity, intercommunication, voice sending, voice receiving, buffer storage, and a broken playback. The voice coming back plays at the proper speed without scratchy noise, but it's only ever playing a % of the voice buffer, recycling, and playing the new first %. I need the client to only play sound data it retreives once (asside from resampling for proper audio speeds) and then never again.
package Voip
{
import flash.events.SampleDataEvent;
import flash.events.TimerEvent;
import flash.media.Sound;
import flash.system.System;
import flash.utils.ByteArray;
import flash.utils.Timer;
public class SoundObj
{
private var ID:int;
public var sound:Sound;
public var buf:ByteArray;
public var _vbuf:ByteArray;
public var _numSamples:int;
public var _phase:Number = 0;
public var killtimer:Timer = null;
public var _delaytimer:Timer = new Timer(1000, 1);
public function SoundObj(id:int)
{
ID = id;
buf = new ByteArray();
_vbuf = new ByteArray();
sound = new Sound();
sound.addEventListener(SampleDataEvent.SAMPLE_DATA, SoundBuffer, false, 0, true);
sound.play();
}
public function receive(bytes:ByteArray):void {
var i:int = _vbuf.position;
_vbuf.position = _vbuf.length;
_vbuf.writeBytes(bytes);
_vbuf.position = i;
_numSamples = _vbuf.length/4;
/*var i:int = buf.position;
buf.position = buf.length; // write to end
buf.writeBytes(bytes);
buf.position = i; // return to origin
if (_delaytimer == null) {
_delaytimer = new Timer(1000, 1);
_delaytimer.addEventListener(TimerEvent.TIMER, finaldata);
_delaytimer.start();
}
if (!_delaytimer.running) {
// timer not running, dump buffer and reset.
//var index:int = _vbuf.position;
//_vbuf.position = _vbuf.length;
//_vbuf.writeBytes(buf);
_vbuf = buf;
_vbuf.position = 0;
buf = new ByteArray();
//_vbuf.position = index;
//sound.extract(_vbuf, int(_vbuf.length * 44.1));
_phase = 0;
_numSamples = _vbuf.length/4;
// reset killtimer to silence timeout
killtimer = new Timer(1000, 1);
killtimer.addEventListener(TimerEvent.TIMER, killtimerEvent);
killtimer.start();
}*/
}
public function killtimerEvent(event:TimerEvent):void {
_delaytimer = null;
}
// send remaining data
public function finaldata(event:TimerEvent):void {
if (buf.length > 0) {
trace("adding final content");
//var _buf:ByteArray = new ByteArray();
//var index:int = int(_phase)*4;
//if (index >= _vbuf.length)
// index = _vbuf.position;
/*_buf.writeBytes(_vbuf, index, _vbuf.length-index);
_buf.writeBytes(buf);
buf = new ByteArray();*/
//_vbuf = _buf;
// add remaining buffer to playback
var index:int = _vbuf.position;
_vbuf.position = _vbuf.length;
_vbuf.writeBytes(buf);
_vbuf.position = index;
// wipe buffer
buf = new ByteArray();
//sound.extract(_vbuf, int(_vbuf.length * 44.1));
_phase = 0;
//_numSamples = _vbuf.length/4;
_numSamples = _vbuf.length/4;
// reset killtimer to silence timeout
killtimer = new Timer(1000, 1);
killtimer.addEventListener(TimerEvent.TIMER, killtimerEvent);
killtimer.start();
}
}
public function SoundBuffer(event:SampleDataEvent):void {
//try {
//trace("[SoundBuffer:"+ID+"]");
//sound.removeEventListener(SampleDataEvent.SAMPLE_DATA, SoundBuffer);
// buffer 4KB of data
for (var i:int = 0; i < 4096; i++)
{
var l:Number = 0;
var r:Number = 0;
if (_vbuf.length > int(_phase)*4) {
_vbuf.position = int(_phase)*4;
l = _vbuf.readFloat();
if (_vbuf.position < _vbuf.length)
r = _vbuf.readFloat();
else
r = l;
}
//if (_vbuf.position == _vbuf.length)
//_vbuf = new ByteArray();
event.data.writeFloat(l);
event.data.writeFloat(r);
_phase += (16/44.1);
if (_phase >= _numSamples) {
_phase -= _numSamples;
}
}
System.gc();
}
}
}
The initial idea was to create a SoundObj in my scene, use obj.receive(bytes) to add data to the buffer to be played back the next time the Sound player needed new data. I've been fiddling around trying to get it to work in one way or another since. The timers were designed to determine when to buffer more data, but never really worked as desired.
Proper double buffer, proper playback.
package VoipOnline
{
import flash.events.SampleDataEvent;
import flash.events.TimerEvent;
import flash.media.Sound;
import flash.system.System;
import flash.utils.ByteArray;
import flash.utils.Timer;
import flashx.textLayout.formats.Float;
public class SoundObj
{
public var ID:int;
public var sound:Sound;
internal var _readBuf:ByteArray;
internal var _writeBuf:ByteArray;
internal var n:Number;
internal var _phase:Number;
internal var _numSamples:int;
internal var myTimer:Timer;
internal var bytes:int;
public function SoundObj(id:int)
{
ID = id;
_readBuf = new ByteArray();
_writeBuf = new ByteArray();
bytes = 0;
myTimer = new Timer(10000, 0);
myTimer.addEventListener(TimerEvent.TIMER, timerHandler);
myTimer.start();
sound = new Sound();
sound.addEventListener(SampleDataEvent.SAMPLE_DATA, SoundBuffer);
sound.play();
}
public function receive(bytes:ByteArray):void
{
var i:int = _writeBuf.position;
_writeBuf.position = _writeBuf.length;
_writeBuf.writeBytes(bytes);
_writeBuf.position = i;
this.bytes += bytes.length;
}
private function timerHandler(e:TimerEvent):void{
trace((bytes/10) + " bytes per second.");
bytes = 0;
}
public function SoundBuffer(event:SampleDataEvent):void
{
//trace((_readBuf.length/8)+" in buffer, and "+(_writeBuf.length/8)+" waiting.");
for (var i:int = 0; i < 4096; i++)
{
var l:Number = 0; // silence
var r:Number = 0; // silence
if (_readBuf.length > int(_phase)*8) {
_readBuf.position = int(_phase)*8;
l = _readBuf.readFloat();
if (_readBuf.position < _readBuf.length)
r = _readBuf.readFloat();
else {
r = l;
Buffer();
}
} else {
Buffer();
}
event.data.writeFloat(l);
event.data.writeFloat(r);
_phase += 0.181;
}
}
private function Buffer():void {
// needs new data
// snip 4096 bytes
var buf:ByteArray = new ByteArray();
var len:int = (_writeBuf.length >= 4096 ? 4096 : _writeBuf.length);
buf.writeBytes(_writeBuf, 0, len);
// remove snippet
var tmp:ByteArray = new ByteArray();
tmp.writeBytes(_writeBuf, len, _writeBuf.length-len);
_writeBuf = tmp;
// plug in snippet
_readBuf = buf;
_writeBuf = new ByteArray();
_readBuf.position = 0;
_phase = 0;
}
}
}
These code snippets are based on this mic setup:
mic = Microphone.getMicrophone();
mic.addEventListener(SampleDataEvent.SAMPLE_DATA, this.micParse); // raw mic data stream handler
mic.codec = SoundCodec.SPEEX;
mic.setUseEchoSuppression(true);
mic.gain = 100;
mic.rate = 44;
mic.setSilenceLevel(voicelimit.value, 1);
After considerable testing, this seems to provide the best results so far. Little grainy, but it IS compressed and filterred. Some of the issues I'm having seem to be the fault of the server. I'm only receiving ~30% of the bytes I'm sending out. That being said, the code above works. You simply adjust the _phase increment to modify speed. (0.181 == 16/44/2) Credit will go where credit is due, even if his sample didn't quite solve the issues at hand, it was still a considerable step forward.
I have prepared some sample data and fed it into your example and got only noise sound. I have simplified your class to only two buffers one for receiving samples and second one for providing them. Hope this will work:
package {
import flash.events.*;
import flash.media.*;
import flash.utils.*;
public class SoundObj
{
private var ID:int;
public var sound:Sound;
public var _readBuf:ByteArray;
public var _writeBuf:ByteArray;
public function SoundObj(id:int)
{
ID = id;
_readBuf = new ByteArray();
_writeBuf = new ByteArray();
sound = new Sound();
sound.addEventListener(SampleDataEvent.SAMPLE_DATA, SoundBuffer);
sound.play();
}
public function receive(bytes:ByteArray):void
{
var i:int = _writeBuf.position;
_writeBuf.position = _writeBuf.length;
_writeBuf.writeBytes(bytes);
_writeBuf.position = i;
sound.play();
}
public function SoundBuffer(event:SampleDataEvent):void
{
for (var i:int = 0; i < 8192; i++)
{
if (_readBuf.position < _readBuf.length)
event.data.writeFloat(_readBuf.readFloat());
else
{
if (_writeBuf.length >= 81920)
{
_readBuf = _writeBuf;
_writeBuf = new ByteArray();
}
if (_readBuf.position < _readBuf.length)
event.data.writeFloat(_readBuf.readFloat());
else
{
//event.data.writeFloat( 0 );
}
}
}
}
}
}
// microphone sample parsing with rate change
function micParse(event:SampleDataEvent):void
{
var soundBytes:ByteArray = new ByteArray();
var i:uint = 0;
var n:Number = event.data.bytesAvailable * 44 / mic.rate * 2; // *2 for stereo
var f:Number = 0;
while(event.data.bytesAvailable)
{
i++;
var sample:Number = event.data.readFloat();
for (; f <= i; f+= mic.rate / 2 / 44)
{
soundBytes.writeFloat(sample);
}
}
snd.receive(soundBytes);
}

Timer related error in flash, TypeError #1009

I used a timer in my flash application, and I have this particular error below:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at FlashGame_fla::MainTimeline/toTimeCode()
at FlashGame_fla::MainTimeline/timerTickHandler()
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
Below is my code for this particular flash game application. It's a game where the player collects as many items as possible within a specific time:
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.utils.Timer;
import flash.geom.Rectangle;
menuButton.addEventListener(MouseEvent.CLICK, evilToMenu);
rulesButton.addEventListener(MouseEvent.CLICK, toggleRule);
gameRules.addEventListener(MouseEvent.CLICK, toggleRule);
gameRules.visible = false;
gameRules.buttonMode = true;
evilGameOverMC.visible = false;
evilWinLose.visible = false;
playAgainBtn.visible = false;
toMenuBtn.visible = false;
var pLives:int = 3;
var pEvilScore:int = 0;
var pItems:int = 10;
var daveMC:MovieClip;
var cGameObjs:Array = new Array();
var timer:Timer = new Timer(100, 300);
timer.start();
timer.addEventListener(TimerEvent.TIMER, timerTickHandler);
var timerCount:int = 15000;
//var cPlayerData:Object;
//var cSavedGameData:SharedObject;
addCharacter();
addBots();
addItems();
scoreDisplay.text = "" + pEvilScore;
livesDisplay.text = pLives + " lives";
function evilToMenu(Event:MouseEvent):void
{
removeLeftovers();
removeChild(daveMC);
timer.stop();
gotoAndStop("menu");
}
function timerTickHandler(Event:TimerEvent):void
{
timerCount -= 100;
toTimeCode(timerCount);
if (timerCount <= 0)
{
gameOver(false);
}
}
function toTimeCode(milliseconds:int): void
{
//creating a date object using the elapsed milliseconds
var time:Date = new Date(milliseconds);
//define minutes/seconds/mseconds
var minutes:String = String(time.minutes);
var seconds:String = String(time.seconds);
var miliseconds:String = String(Math.round(time.milliseconds)/100);
//add zero if neccecary, for example: 2:3.5 becomes 02:03.5
minutes = (minutes.length != 2) ? '0'+minutes : minutes;
seconds = (seconds.length != 2) ? '0'+seconds : seconds;
//display elapsed time on in a textfield on stage
timerDisplay.text = minutes + ":" + seconds;
}
function addCharacter():void
{
trace("Adding the character, Dave")
//set the initial values
var myBorder:Rectangle = new Rectangle(355,145,395,285);
var myXY:Array = [355,430];
var myChar:int = Math.ceil(Math.random() * 3);
var myKeys:Array = [37,39,38,40];
var myDistance:int = 7;
// create and add a new player object to the stage
daveMC = new Character(myBorder,myXY,myKeys,myChar,myDistance);
addChild(daveMC);
}
function addBots():void
{
trace("Adding the bots..");
// set the initial values (adapt to suit your game)
var myBorder:Rectangle = new Rectangle(355,145,395,285);
var myMaxBots:int = 5;// simulation
// add bots one at a time via a loop
for (var i:int = 0; i < myMaxBots; i++)
{
// create a new bot object and name it
var thisBot:Bot = new Bot(myBorder, daveMC);
thisBot.name = "bot" + i;
cGameObjs.push(thisBot);
// add it to the stage
addChild(thisBot);
}
}
function addItems():void
{
trace("Adding the items..");
//set the initial values
for (var i:int = 0; i < 10; i++)
{
// create a new bot object and name it
var thisItem:Item = new Item(daveMC);
thisItem.name = "item" + i;
cGameObjs.push(thisItem);
// add it to the stage
addChild(thisItem);
}
}
function updateLives(myBot:MovieClip):void
{
// update the player's LIVES and score
pLives--;
pEvilScore -= 30;
var myIndex:int = cGameObjs.indexOf(myBot);
cGameObjs.splice(myIndex,1);
// check for a LOST GAME
if (pLives > 0)
{
updateScores();
}
else
{
gameOver(false);
}
}
function updateItems(myItem:MovieClip):void
{
// update the player's LIVES and score
pItems--;
pEvilScore += 20;
var myIndex:int = cGameObjs.indexOf(myItem);
cGameObjs.splice(myIndex,1);
// check for a LOST GAME
if (pItems > 0)
{
updateScores();
}
else
{
gameOver(true);
}
}
function gameOver(myFlag:Boolean):void
{
updateScores();
if (myFlag)
{
// player wins
msgDisplay.text = "YAY! PAPPLE FOR \nEVERYBODY!";
removeLeftovers();
evilWinLose.text = "Weee!! We've got papples for Gru! \nYour Score: " + pEvilScore;
}
else
{
// player loses
msgDisplay.text = "OH NO! NOT \nENOUGH PAPPLES";
removeLeftovers();
evilWinLose.text = "Boo!! Not enough papples for Gru! \nYour Score: " + pEvilScore;
}
timerDisplay.text = "";
removeChild(daveMC);
evilGameOverMC.visible = true;
evilWinLose.visible = true;
toMenuBtn.visible = true;
playAgainBtn.visible = true;
toMenuBtn.addEventListener(MouseEvent.CLICK, Click_backtoMain);
playAgainBtn.addEventListener(MouseEvent.CLICK, backToEvil);
}
function updateScores():void
{
scoreDisplay.text = "" + pEvilScore;
livesDisplay.text = pLives + " lives";
msgDisplay.text = pItems + " papples more to \ncollect..";
}
function removeLeftovers():void
{
// check each BOT/ITEM in array
for each (var myObj in cGameObjs)
{
myObj.hasHitMe();
myObj = null;
}
}
function backToEvil(event:MouseEvent):void
{
pEvilScore = 0;
pLives = 3;
pItems = 3;
gotoAndStop("menu");
gotoAndStop("evil");
}
Anyone can help me out with this? Thank you alot! :)
Replace your toTimeCode function code by :
function toTimeCode(milliseconds:int): void
{
trace(1);
//creating a date object using the elapsed milliseconds
var time:Date = new Date(milliseconds);
trace(2);
//define minutes/seconds/mseconds
var minutes:String = String(time.minutes);
trace(3);
var seconds:String = String(time.seconds);
trace(4);
var miliseconds:String = String(Math.round(time.milliseconds)/100);
trace(5);
//add zero if neccecary, for example: 2:3.5 becomes 02:03.5
minutes = (minutes.length != 2) ? '0'+minutes : minutes;
trace(6);
seconds = (seconds.length != 2) ? '0'+seconds : seconds;
trace(7);
//display elapsed time on in a textfield on stage
timerDisplay.text = minutes + ":" + seconds;
trace(8);
}
Please, change the timerDisplay line to this one... The problem will be in the toTimeCode method. The error say that you are trying to call a method from a var wich is not (yet) an object...
if(null != timerDisplay)
timerDisplay.text = minutes + ":" + seconds;
You have to find an object wich is null! Add this :
function toTimeCode(milliseconds:int): void
{
//creating a date object using the elapsed milliseconds
var time:Date = new Date(milliseconds);
trace("Time: " + time);

error while converting AS2 starfield code to AS3

I've tried to convert a nice AS2 script for starfirld effect to AS3 But i'm still getting strange errors
would really appreciate if any one could help me understand what am i doing wrong
here is the original AS2 code:
var stars = 100;
var maxSpeed = 16;
var minSpeed = 2;
var i = 0;
while (i < stars)
{
var mc = this.attachMovie("star", "star" + i, i);
mc._x = random(Stage.width);
mc._y = random(Stage.height);
mc.speed = random(maxSpeed - minSpeed) + minSpeed;
var size = random(2) + 6.000000E-001 * random(4);
mc._width = size;
mc._height = size;
++i;
} // end while
this.onEnterFrame = function ()
{
for (var _loc3 = 0; _loc3 < stars; ++_loc3)
{
var _loc2 = this["star" + _loc3];
if (_loc2._y > 0)
{
_loc2._y = _loc2._y - _loc2.speed;
continue;
} // end if
_loc2._y = Stage.height;
_loc2.speed = random(maxSpeed - minSpeed) + minSpeed;
_loc2._x = random(Stage.width);
} // end of for
};
and here is my AS3 version:
import flash.events.Event;
import flash.events.MouseEvent;
function starField():void
{
var stars:int = 100;
var maxSpeed:int = 16;
var minSpeed:int = 2;
var i:int = 0;
while (i < stars)
{
var mc = new Star();
addChild(mc)
mc._x = Math.random()(stage.stageWidth);
mc._y = Math.random()(stage.stageHeight);
mc.speed = Math.random()(maxSpeed - minSpeed) + minSpeed;
var size = Math.random()(2) + 6.000000E-001 * Math.random()(4);
mc._width = size;
mc._height = size;
++i;
} // end while
}
addEventListener(Event.ENTER_FRAME, update);
function update(_e:Event):void
{
for (var _loc3 = 0; _loc3 < 100; ++_loc3)
{
var _loc2 = this["star" + _loc3];
if (_loc2._y > 0)
{
_loc2._y = _loc2._y - _loc2.speed;
continue;
} // end if
_loc2._y = stage.stageHeight;
_loc2.speed = Math.random()(maxSpeed - minSpeed) + minSpeed;
_loc2._x = Math.random()(stage.stageWidth);
} // end of for
};
the error message I'm getting is: "TypeError: Error #1010: A term is undefined and has no properties. at _fla::MainTimeline/update()"
I understand it has a problem with the 'update' function but I'm net sure which term it refer to?
I'll bet a can of juice here is your problem:
var _loc2 = this["star" + _loc3];
put these into an associative array and access them from there.
#Discipol is right.
Just wanted to add a few more notes:
You can also use the display list to get the movie clip by name:
var _loc2:MovieClip = MovieClip(getChildByName("star" + _loc3));
You've got untyped variables and your are relying on MovieClip as a dynamic class to add properties (such as speed) at runtime. For a really simple project the impact is barely noticeable, but on the long run, for bigger projects, it's worth extending Sprite if you don't use the timeline and add the properties you need:
package {
import flash.display.Sprite;
import flash.events.Event;
public class Star extends Sprite {
private var speed:Number;
private var minSpeed:Number;
private var maxSpeed:Number;
public function Star(min:Number,max:Number) {
minSpeed = min;
maxSpeed = max;
var size = (Math.random()*2) + 1.82211880039 * (Math.random()*4);
width = size;
height = size;
this.addEventListener(Event.ADDED_TO_STAGE,reset);
}
private function reset(e:Event = null):void{
speed = (Math.random() * (maxSpeed-minSpeed)) + minSpeed;
x = Math.random() * stage.stageWidth;
if(e != null) y = Math.random() * stage.stageHeight;//initialized from added to stage event
else y = stage.stageHeight;//otherwise reset while updating
}
public function update():void{
if (y > 0) y -= speed;
else reset();
}
}
}
and the rest of the code would be as simple as:
var stars:int = 100;
var starClips:Vector.<Star> = new Vector.<Star>(stars,true);//a typed fixed vector is faster than a dynamically resizable untyped Array
for(var i:int = 0 ; i < stars; i++) starClips[i] = addChild(new Star(16,2)) as Star;
this.addEventListener(Event.ENTER_FRAME,updateStars);
function updateStars(e:Event):void{
for(var i:int = 0 ; i < stars; i++) starClips[i].update();
}

Action Script 3. How to add timer?

I'm creating Flash "memory" game, Idea to discover 2 equal cards. But when I choose 1, if second card is wrong It discover only for half second, but this is not enough. I need to make that second card will be shown for 2-3 seconds. How can I add timer?
Here is part of code:
else
{
trace("wrong");
_message = "wrong";
message_txt.text = _message;
_firstCard.gotoAndPlay("flipBack");
event.currentTarget.gotoAndPlay("flipBack");
_firstCard.addEventListener(MouseEvent.CLICK, checkCards);
event.currentTarget.addEventListener(MouseEvent.CLICK, checkCards);
_firstCard = undefined;
}
Thank you for answers.
UPDATED WITH FULL CODE
package
{
import flash.display.MovieClip;
import Card;
import Boarder;
import BlueBoard;
import flash.events.MouseEvent;
import RedBoard;
import Snow;
public class MemoryGame extends MovieClip
{
private var _card:Card;
private var _boarder:Boarder;
private var _blueBoard:BlueBoard;
private var _cardX:Number;
private var _cardY:Number;
private var _firstCard:*;
private var _totalMatches:Number;
private var _currentMatches:Number;
private var _redBoard:RedBoard;
private var _snow:Snow;
private var _cards:Array;
public var _message:String;
public function MemoryGame()
{
_cards = new Array();
_totalMatches = 4;
_currentMatches = 0;
createCards();
}
private function createCards():void
{
_cardX = 45;
_cardY = 10;
for(var i:Number = 0; i < 2; i++)
{
_card = new Card();
addChild(_card);
_boarder = new Boarder();
_card.setType(_boarder);
_card.x = _cardX;
_card.y = _cardY;
_cardX += _card.width + 50;
_card.addEventListener(MouseEvent.CLICK, checkCards);
_cards.push(_card);
}
for(var j:Number = 0; j < 2; j++)
{
_card = new Card();
addChild(_card);
_blueBoard = new BlueBoard();
_card.setType(_blueBoard);
_card.x = _cardX;
_card.y = _cardY;
_cardX += _card.width + 50;
_card.addEventListener(MouseEvent.CLICK, checkCards);
_cards.push(_card);
}
_cardX = 45;
_cardY = _card.height + 30;
for(var k:Number = 0; k < 2; k++)
{
_card = new Card();
addChild(_card);
_redBoard = new RedBoard();
_card.setType(_redBoard);
_card.x = _cardX;
_card.y = _cardY;
_cardX += _card.width + 50;
_card.addEventListener(MouseEvent.CLICK, checkCards);
_cards.push(_card);
}
for(var l:Number = 0; l < 2; l++)
{
_card = new Card();
addChild(_card);
_snow = new Snow();
_card.setType(_snow);
_card.x = _cardX;
_card.y = _cardY;
_cardX += _card.width + 50;
_card.addEventListener(MouseEvent.CLICK, checkCards);
_cards.push(_card);
}
randomizeCards(_cards);
}
private function checkCards(event:MouseEvent):void
{
event.currentTarget.removeEventListener(MouseEvent.CLICK, checkCards);
if(_firstCard == undefined)
{
_firstCard = event.currentTarget;
}
else if(String(_firstCard._type) == String(event.currentTarget._type))
{
trace("match");
_message = "match";
message_txt.text = _message;
_firstCard = undefined;
_currentMatches ++;
if(_currentMatches >= _totalMatches)
{
trace("YOU WIN !!!");
_message = "YOU WIN !!!";
message_txt.text = _message;
}
}
else
{
trace("wrong");
_message = "wrong";
message_txt.text = _message;
_firstCard.gotoAndPlay("flipBack");
event.currentTarget.gotoAndPlay("flipBack");
_firstCard.addEventListener(MouseEvent.CLICK, checkCards);
event.currentTarget.addEventListener(MouseEvent.CLICK, checkCards);
_firstCard = undefined;
}
}
private function randomizeCards(cards:Array):void
{
var randomCard1:Number;
var randomCard2:Number;
var card1X:Number;
var card1Y:Number;
for(var i:Number = 0; i < 10; i++)
{
randomCard1 = Math.floor(Math.random() * cards.length);
randomCard2 = Math.floor(Math.random() * cards.length);
card1X = cards[randomCard1].x;
card1Y = cards[randomCard1].y;
cards[randomCard1].x = cards[randomCard2].x;
cards[randomCard1].y = cards[randomCard2].y
cards[randomCard2].x = card1X;
cards[randomCard2].y = card1Y;
}
}
}
}
You can use http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/Timer.html. BTW, do note that Timer constructor's default 2nd parameter is 0 implying that the timer would run indefinitely. Be sure to mark that as 1 for your case.
You need to move code in your 'else' block to another function and setup the timer instead in the else block.
The final code would look something like this:
else
{
trace("wrong");
_message = "wrong";
message_txt.text = _message;
_secondCard = event.currentTarget;//You need to have this variable defined alongwith _firstCard
var timer:Timer = new Timer(2000, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, flipBack);
timer.start();
}
and the function would have:
protected function flipBack(event:TimerEvent):void
{
_firstCard.gotoAndPlay("flipBack");
_sedondCard.gotoAndPlay("flipBack");
_firstCard.addEventListener(MouseEvent.CLICK, checkCards);
_secondCard.addEventListener(MouseEvent.CLICK, checkCards);
_firstCard = _secondCard = undefined;
}
HTH.
If it's only to wait a certain amount of time, you can use setTimeout (flash.utils)
http://livedocs.adobe.com/flash/9.0_fr/ActionScriptLangRefV3/flash/utils/package.html#setTimeout()

Detect when the Shader is done mixing the audio

so this the code with it i am able to mix several tracks
with a Shader done in pixel bender.
the problem here i don't know when the mixing is finish or all the sound reache their end
to be able to save the bytearray into a file any Event or something like that
help plz ?
package
{
import flash.display.*;
import flash.media.*;
import flash.events.*;
import flash.net.*;
import flash.utils.*;
import fl.controls.Slider;
import org.bytearray.micrecorder.encoder.WaveEncoder;
[SWF(width='500', height='380', frameRate='24')]
public class AudioMixer extends Sprite{
[Embed(source = "sound2.mp3")] private var Track1:Class;
[Embed(source = "sound1.mp3")] private var Track2:Class;
[Embed(source = "mix.pbj",mimeType = "application/octet-stream")]
private var EmbedShader:Class;
private var shader:Shader = new Shader(new EmbedShader());
private var sound:Vector.<Sound> = new Vector.<Sound>();
private var bytes:Vector.<ByteArray> = new Vector.<ByteArray>();
private var sliders:Vector.<Slider> = new Vector.<Slider>();
private var graph:Vector.<Shape> = new Vector.<Shape>();
private var recBA:ByteArray = new ByteArray();
private var BUFFER_SIZE:int = 0x800;
public var playback:Sound = new Sound();
public var container:Sprite = new Sprite();
public var isEvent:Boolean = false;
public function AudioMixer():void{
container.y = stage.stageHeight * .5;
addChild(container);
sound.push(new Track1(), new Track2(),new Track2(),new Track2(),new Track2(),new Track2(),new Track2(),new Track2(),new Track2(),new Track2(),new Track2(),new Track2());
for(var i:int = 0; i < sound.length; i++){
var slider:Slider = new Slider();
slider.maximum = 1;
slider.minimum = 0;
slider.snapInterval = 0.025;
slider.value = 0.8;
slider.rotation += -90;
slider.x = i * 40 + 25;
container.addChild(slider);
sliders.push(slider);
var line:Shape = new Shape();
line.graphics.lineStyle(1, 0x888888);
line.graphics.drawRect(i * 40 + 14, 0, 5, -80);
line.graphics.endFill();
container.addChild(line);
var shape:Shape = new Shape();
shape.graphics.beginFill(0x00cc00);
shape.graphics.drawRect(i * 40 + 15, 0, 3, -80);
shape.graphics.endFill();
container.addChild(shape);
graph.push(shape);
}
playback.addEventListener(SampleDataEvent.SAMPLE_DATA, onSoundData);
playback.play();
}
private function onSoundData(event:SampleDataEvent):void {
for(var i:int = 0; i < sound.length; i++){
bytes[i] = new ByteArray();
bytes[i].length = BUFFER_SIZE * 4 * 2;
sound[i].extract(bytes[i], BUFFER_SIZE);
var volume:Number = 0;
bytes[i].position = 0;
for(var j:int = 0; j < BUFFER_SIZE; j++){
volume += Math.abs(bytes[i].readFloat());
volume += Math.abs(bytes[i].readFloat());
}
volume = (volume / (BUFFER_SIZE * .5)) * sliders[i].value;
shader.data['track' + (i + 1)].width = BUFFER_SIZE / 1024;
shader.data['track' + (i + 1)].height = 512;
shader.data['track' + (i + 1)].input = bytes[i];
shader.data['vol' + (i + 1)].value = [sliders[i].value];
graph[i].scaleY = volume;
}
var shaderJob:ShaderJob = new ShaderJob(shader,event.data,BUFFER_SIZE / 1024,512);
shaderJob.start(true);
var shaderJob2:ShaderJob = new ShaderJob(shader,recBA,BUFFER_SIZE / 1024,512);
shaderJob2.start(true);
}
}
}
You can tell when a shader has completed it's job using the ShaderEvent.COMPLETE listener. Like so:
shaderJob.addEventListener(ShaderEvent.COMPLETE, onShaderComplete);
private function onShaderComplete(e:Event):void
{
//Do Something here
}
See this link for more details.
One thing about your code though. You're doing this shader job inside of a sampleDataEvent and I can see this being problematic (possibly) in the sense that your mixing may be out of sync with your playback (that is, if you plan on mixing live and writing the mixed data back into the sound stream). Anyway that's perhaps an issue for a new question. This should solve your problem with needing to know when the mixing is complete.
Note you also need to add "false" to the shaderJob.start(false) function. From the documentation about the ShaderEvent.COMPLETE:
"Dispatched when a ShaderJob that executes asynchronously finishes processing the data using the shader. A ShaderJob instance executes asynchronously when the start() method is called with a false value for the waitForCompletion parameter."
Update
In response to your inquiry about how to only process inside the sampleDataEvent if the sound isnt being processed:
private var isProcessing:Boolean = false;
private function onSoundData(event:SampleDataEvent):void {
if(isProcessing != true){
for(var i:int = 0; i < sound.length; i++){
bytes[i] = new ByteArray();
bytes[i].length = BUFFER_SIZE * 4 * 2;
sound[i].extract(bytes[i], BUFFER_SIZE);
var volume:Number = 0;
bytes[i].position = 0;
for(var j:int = 0; j < BUFFER_SIZE; j++){
volume += Math.abs(bytes[i].readFloat());
volume += Math.abs(bytes[i].readFloat());
}
volume = (volume / (BUFFER_SIZE * .5)) * sliders[i].value;
shader.data['track' + (i + 1)].width = BUFFER_SIZE / 1024;
shader.data['track' + (i + 1)].height = 512;
shader.data['track' + (i + 1)].input = bytes[i];
shader.data['vol' + (i + 1)].value = [sliders[i].value];
graph[i].scaleY = volume;
}
var shaderJob:ShaderJob = new ShaderJob(shader,event.data,BUFFER_SIZE / 1024,512);
shaderJob.start(false);
shaderJob.addEventListener(ShaderEvent.COMPLETE, onShaderComplete);
var shaderJob2:ShaderJob = new ShaderJob(shader,recBA,BUFFER_SIZE / 1024,512);
shaderJob2.start(false);
}
}
private function onShaderComplete(e:ShaderEvent):void
{
//Do something here
isProcessing = false;
}