Flash/AS3 noobie here.
I'm attempting to display text letter-by-letter (which is working great). However, I want the animation to delay ~500 milliseconds each time a period/end of sentence is encountered. So far the relevant part of my code looks like this:
public function displayLoop(e:Event):void
{
if (pos == textToDisplay.length - 1)
{
stop();
return;
}
firstParagraph.appendText(textToDisplay.charAt(pos));
if (textToDisplay.charAt(pos) == String.fromCharCode(46))
{
//here's where I want to delay??
}
pos++;
}
In this case, firstParagraph is the name of my dynamic text object, textToDisplay is the String of text that is going to be displayed letter-by-letter, and pos is simply the position we're at when displaying the text, so we can keep track of it.
I'm guessing there's a simple solution to this problem, perhaps using a Timer EventHandler?
I appreciate any help anyone has to offer, thanks!
I think the following will be helpful for coding up what you want:
String.split() - This method will help you split up your paragraph into sentences and store them in an array. (Keep in mind that not all periods are full stops, so perhaps you will need to use some regular expressions to deal with special cases like when they are used as elipsis, or decimals.):
e.g.
textToDisplay.split('.');
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/String.html#split()
Array.shift() - This method will return to you the first element in the array, and then remove it from the array. If you have your sentences stored in an array, you can keep calling shift() to get the next sentence that needs to be shown:
e.g.
var sentences:Array = textToDisplay('.');
var next_sentence:String = sentences.shift();
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Array.html#shift()
Timer - This object, like you mentioned, will help you create those delay intervals between appending the sentences:
e.g.
var myTimer:Timer = new Timer(1000, sentences.length);
myTimer.addEventListener(TimerEvent.TIMER, timerHandler);
myTimer.start();
function timerHandler(e:Event) {
firstParagraph.appendText(sentences.shift());
}
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/Timer.html
No need to track position since the timer has a counter built into it.
import flash.text.TextField;
import flash.utils.Timer;
import flash.events.TimerEvent;
var textToDisplay:String = 'AB.CDE.FGHI.JKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
var tf:TextField = new TextField()
tf.width = 500
tf.wordWrap = true
tf.height = 400
addChild(tf)
var timer:Timer = new Timer(100)
timer.addEventListener(TimerEvent.TIMER, onTimer)
timer.start()
function onTimer(e:TimerEvent):void{
timer.delay = 100
tf.appendText(textToDisplay.slice(timer.currentCount-1,timer.currentCount))
if(timer.currentCount == textToDisplay.length){
timer.stop()
}
if(textToDisplay.slice(timer.currentCount-1,timer.currentCount) == '.'){
timer.delay = 500
}
}
Related
Im new to ActionScript 3 and am trying to get a number to deplete when i start a timer
So far ive got it so you click the button 'btngo' and a timer begins whilst the ball object moves.
I also want a dynamic text that starts at 100 to deplete down to 0 in 10 seconds when this button is clicked, but unfortunately i have no clue how to do it
Any help will be greatly appreciated, thank you :)
import flash.utils.Timer;
import flash.events.TimerEvent;
stop();
var timer1:Timer = new Timer (10,10000);
var timer2:Timer = new Timer (10,10000);
timer1.addEventListener(TimerEvent.TIMER, forward);
timer2.addEventListener(TimerEvent.TIMER, back);
btngo.addEventListener(MouseEvent.CLICK, green);
btnstop.addEventListener(MouseEvent.CLICK, red);
function green(e:MouseEvent):void {
timer2.stop();
timer1.start();
trace("timer started");
}
function red(e:MouseEvent):void {
timer1.stop();
timer2.start();
trace("timer started");
}
function forward(e:TimerEvent):void {
ball.x += 2;
}
function back(e:TimerEvent):void {
ball.x -= 2;
}
Well, here are two functions which will get you what you are looking for. This first one is the creation of the text:
import flash.text.TextField;
import flash.text.TextFieldType;
var dynamic_text:TextField;
function CreateText()
{
// You can also replace this part with code that creates a textfield that you have in your library,
// in that case just make sure the textfield is set to dynamic in the textfield properties
// Create a new textfield.
dynamic_text = new TextField();
// Make sure its type is set to Dynamic.
dynamic_text.type = TextFieldType.DYNAMIC;
// Position it somewhere on the screen.
dynamic_text.x = 10;
dynamic_text.y = 10;
// Set a default text for now.
dynamic_text.text = "Time: " + time_left;
// Make sure the players cannot select the text.
dynamic_text.selectable = false;
// Add it to your stage (or other parent, take your pick)
stage.addChild(dynamic_text);
}
This second one is called every TimerEvent:
function OnTimerChange()
{
// Update the text based on the new time.
dynamic_text.text = "Time: " + time_left;
}
You will have to call this OnTimerChange function inside your own "forward" and "backward" functions, and in those two functions you will have to calculate how much time has passed.
For an example how to keep track of time that has passed since you pressed a button:
actionscript 3 how to keep track of time elapsed?
Hope this helped.
Hey everyone cant really figure out the easiest approach to this problem.
Basically I have a timer that starts in the beginning of the game like so:
//Create new timer object
tEggTimer = new Timer (nTimerSpeed);
//Listen for timer intervals
tEggTimer.addEventListener(TimerEvent.TIMER, addEggs, false, 0, true);
//start timer
tEggTimer.start();
The nTimerSpeed is equal to (800);
Then I add the eggs like so:
private function addEggs(e:TimerEvent):void
{
//var eggGlobalPosition:Point = _Egg.localToGlobal(new Point(_Bunny.x, _Bunny.y));
_Egg = new mcEgg();
stage.addChild(_Egg);
_Egg.x = _Bunny.x;
_Egg.y = _Bunny.y + 30;
aEggArray.push(_Egg);
trace(aEggArray.length);
}
So in another enter frame function I want to change the value of the timer to (500), but whenever I try like so:
tEggTimer = new Timer (500);
tEggTimer.start();
like So:
private function updateDifficulty():void
{
if (difficultyUpdate) return;
if (nScore >= 2)
{
tEggTimer.removeEventListener(TimerEvent.TIMER, addEggs);
tEggTimer.stop();
tEggTimer = new Timer(200);
tEggTimer.addEventListener(TimerEvent.TIMER, addEggs);
tEggTimer.start();
But this doesnt do anything but stop the timer entirely.
What can I do in order to decrease the timer correctly?
Thanks guys.
If you just want to change the timer speed, while keeping everything else the same, you could just change the delay property in the timer object.
Sample here:
import flash.utils.getTimer;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.MouseEvent;
var speeds:Vector.<int> = new <int>[1000, 2000, 5000];
var currentSpeed:int = 0;
var timer:Timer = new Timer(speeds[currentSpeed]);
function timerTick(inputEvent:TimerEvent):void {
trace("Timer ticking: "+ getTimer());
}
timer.addEventListener(TimerEvent.TIMER, timerTick, false, 0, true);
timer.start();
function clickedStage(inputEvent:MouseEvent):void {
currentSpeed = ++currentSpeed % speeds.length;
timer.delay = speeds[currentSpeed];
trace("Timer delay set to "+ timer.delay);
}
this.stage.addEventListener(MouseEvent.CLICK, clickedStage, false, 0, true);
Clicking on the stage will change the timer delay from 1 second, 2 seconds, 5 seconds and cycle. I'm just using getTimer() to show the rate of which the timer is ticking.
Note that it seems from the output, every time the value is changed, the timer will automatically restart.
timer.reset();
timer.delay = 2000;
timer.start();
May no be the best way but, instead using nTimerSpeed, make it run through every millisecond:
tEggTimer = new Timer (1);
Then in your AddEggs function use nTimerSpeed and a counter variable. counter is initialize to 0. Incase all your logic in an if statement, increment counter every time through function. if counter equals nTimerSpeed, allow for them inside the if statement and reset counter.
function AddEggs()
{
if(counter == nTimerSpeed)
{
//adding eggs logic
counter = 0;
}
counter++;
}
Did you try saying: tEggTimer.stop() just before re-instantiating with the 500 ms version? I'm guessing that your first Timer instance will just keep firing as your new one starts, unless you deliberately stop it.
How do i add a new element only after the previous one has passed the stage.stageWidth / 2
except by my way (the code below ,where i create a zone that the element will pass only one time)
PS:I dont want to do it like this cause the speed of movement will be different in time (it will slowly go up and down). Like from 3 to 6 by a easing factor of 0.005
so far i have this
import flash.display.MovieClip;
import flash.events.Event;
public class Main extends MovieClip
{
private var myArray:Array = new Array();
public function Main()
{
stage.addEventListener(Event.ENTER_FRAME, everyFrame)
var item:Box = new Box();
item.x = stage.stageWidth - 100
item.y = 40
addChild(item)
myArray.push(item)
}
private function everyFrame(ev:Event):void
{
var myBox:Box
for(var i:int = 0; i< myArray.length; i++)
{
myBox = myArray[i]
myBox.x -=3
if(myBox.x <= stage.stageWidth/2 && myBox.x >= stage.stageWidth/2 - 3)
{
trace("new Box")
var myNewBox:Box = new Box()
myNewBox.x = stage.stageWidth - 100
myNewBox.y = 40
addChild(myNewBox)
myArray.push(myNewBox)
}
if(myBox.x < 0 )
{
removeChild(myBox)
myArray.splice(i, 1)
trace(myArray.length)
}
}
}
}
Your code is already working and do things as you required.
The code looks like document class, but there is one little mistake that prevent it from execution. You forget package{...} wrap.
But you compiler should say you about this, didn't it?
You are right, using range can provide you bunch of problems then objects didn't get in it, or get several times.
To solve this you could not check area but only myBox.x<= stage.stageWidth/2 condition. After object met this condition, just remove element from array you use for checking and add it to array of objects which you check for leaving stage to delete them.
If you don't want make another array, you could add some property to every new Box.
For example - passedCenter and set it to false. Then change if statement for
if(myBox.x <= stage.stageWidth/2 && !myBox.passedCenter){
myBox.passedCenter=true;
//you stuff
}
I need help with a timer. I’d like to create a bomb-like digital countdown timer for a game.
Using a digital font
always double digits e.g. 10, 09...01, 00 (to look like a bomb timer).
And finally during the last few seconds, turning the font red to increase the drama.
What I currently have below is a basic countdown timer, 20-0. The countdown variable starts at 20, is reduced by one every 1000ms and this number is shown in the text field.
But the font is generic, once the count gets below ten the numbers don’t have a zero in front of them, and I have no idea how to change the font colour in the final seconds.
public class UsingATimer extends Sprite
{
//The Timer object
public var timer:Timer= new Timer(1000, countdown);
public var countdown:Number = 20;
//The Text objects
public var output:TextField = new TextField();
public var format:TextFormat = new TextFormat();
public function UsingATimer()
{
//Initialize the timer
output.text = countdown.toString();
timer.addEventListener(TimerEvent.TIMER, countdownHandler);
timer.start();
//Set the text format object
format.font = "Helvetica";
format.size = 200;
format.color = 0x000000;
format.align = TextFormatAlign.RIGHT;
//Configure the output text field
output.defaultTextFormat = format;
output.autoSize = TextFieldAutoSize.RIGHT;
output.border = false;
output.text = "20";
//Display and position the output text field
stage.addChild(output);
output.x = 200;
output.y = 100;
}
public function countdownHandler(event:TimerEvent):void
{
countdown--;
output.text = countdown.toString();
}
}
If there are no basic digital fonts I’ll have to embed one, which I should be okay with but any help with the other two problems would be greatly appreciated.
Sorry if the code is all over the place, I’m a beginner.
Thanks for your time.
I think you've mostly got it already. What you can do is inside your countdown handler, just check if the value is less then 10, if so append a 0 in front before displaying.
countdown--;
if(countdown < 10){
output.text = "0" + countdown.toString();
} else {
output.text = countdown.toString();
}
Then to change the colour, it would be the same logic, check for what number you want it to change colour on, then change the colour in your TextFormat object and apply it to your TextField.
For a digital font, you could search for and embed one in to flash, but if all you need are numbers/limited characters, you could also make one as well with movie clips/graphics since they are relatively straight forward. Depends on how fancy you need it I guess as well as how flexible.
I am trying to reveal this movie clip image which is originally a bitmap but needs to be used as a bitmap for this purpose. for some reason it's not working ...
It's not throwing any errors... I need this image to be masked as the user presses on it... and later be compared with another bitmap to carry out a function. but for some reason as I mentioned before it's not working out. can somebody please help me?? this is the code for it...
import flash.display.Graphics;
import flash.display.MovieClip;
import flash.display.BitmapData;
var mouseclick:Number=0;
var maskedbg_mc:maskedbg = new maskedbg ();
var masking:Sprite = new Sprite()
addChild (maskedbg_mc);
maskedbg_mc.x = 18;
maskedbg_mc.y = 343;
var bitmapDataCopy:BitmapData = new BitmapData(742,165,true,0x00FFFFFF);
var b:Bitmap = new Bitmap(bitmapDataCopy);
bitmapDataCopy.draw(maskedbg_mc);
b.mask = masking;
var Testing:BitmapData = new BitmapData(maskedbg_mc.width, maskedbg_mc.height, true, 0x00000000);
addChild(masking);
stage.addEventListener(MouseEvent.MOUSE_DOWN, Pressing);
stage.addEventListener(MouseEvent.MOUSE_MOVE, Moving);
stage.addEventListener(MouseEvent.MOUSE_UP, Lifting);
function Pressing(event:MouseEvent):void {
mouseclick = 1;
}
function Moving(event:MouseEvent):void {
if (mouseclick == 1) {
masking.graphics.beginFill(0x000000);
masking.graphics.drawEllipse(mouseX, mouseY, 70, 60);
masking.graphics.endFill();
}
}
function Lifting(event:MouseEvent):void {
mouseclick = 0;
}
if ( bitmapDataCopy.compare(Testing) ==0 )
{
trace ("Awesomness")
}
Overlooking your code, I notice you are not adding "b" (the masked DisplayObject) to the display list, while you are adding "maskedbg_mc" which actually isn't being masked in your code. Do you have a reason for having these 2 display objects?
I would recommend you following actionscript coding conventions:
http://sourceforge.net/adobe/flexsdk/wiki/Coding%20Conventions/
Your code looks quite confusing when you have both variables and functions with initial letter in uppercase, they look like classes.