Using a Numeric Stepper from one Flash file to affect gamespeed in an external Flash file? Actionscript 3.0 - actionscript-3

Currently I have an intro screen to my flash file which has two objects.
A button which will load an external flash file using:
var myLoader:Loader = new Loader();
var url:URLRequest = new URLRequest("flashgame.swf");
The second thing is a Numeric Stepper, which will be from 1 to 10. If the user selects a number e.g. 3 then the game speed I have set in the flashgame.swf should be changed
Such as:
var gameSpeed:uint = 10 * numericStepper.value;
But I think my problem is coming into place because the stepper and gamespeed are from different files.
Anyone got any idea please?
I have also tried creating a stepper in the game file and used this code:
var gameLevel:NumericStepper = new NumericStepper();
gameLevel.maximum = 10;
gameLevel.minimum = 1;
addChild(gameLevel);
var gameSpeed:uint = 10 * gameLevel.value;
For some reason the stepper just flashes on the stage, no errors come up and the game doesn't work

When you execute you code, the stepper has no chance to wait for user input.
There is no time between theese two instructions.
addChild(gameLevel);
var gameSpeed:uint = 10 * gameLevel.value;
You should wait for user input in your NumericStepper, and then, on user event, set the game speed.

Edit: Yeah I know it's kinda sad to type out all this code (especially since some people wouldn't even be grateful enough to say thanks) but I think this question is important enough to justify the code as it may be helpful to others in future also.
Hi,
You were close. In your game file you could have put a var _setgameSpeed and then from Intro you could adjust it by flashgame._setgameSpeed = gameSpeed; It's a bit more complicated though since you also have to setup a reference to flashgame in the first place. Let me explain...
Ideally you want to put all your code in one place (an .as file would be best but...) if you would rather use timeline then you should create a new empty layer called "actions" and put all your code in the first frame of that.
Also change your button to a movieClip type and remove any code within it since everything will be controlled by the code in "actions" layer. In the example I have that movieclip on the stage with instance name of "btn_load_SWF"
Intro.swf (Parent SWF file)
var my_Game_Swf:MovieClip; //reference name when accessing "flashgame.swf"
var _SWF_is_loaded:Boolean = false; //initial value
var set_gameSpeed:int; //temp value holder for speed
var swf_loader:Loader = new Loader();
btn_load_SWF.buttonMode = true; //instance name of movieclip used as "load" button
btn_load_SWF.addEventListener(MouseEvent.CLICK, load_Game_SWF);
function load_Game_SWF (event:MouseEvent) : void
{
//set_gameSpeed = 10 * numericStepper.value;
set_gameSpeed = 100; //manual set cos I dont have the above numericStepper
if ( _SWF_is_loaded == true)
{
stage.removeChild(swf_loader);
swf_loader.load ( new URLRequest ("flashgame.swf") );
}
else
{ swf_loader.load ( new URLRequest ("flashgame.swf") ); }
swf_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, Game_SWF_ready);
}
function Game_SWF_ready (evt:Event) : void
{
swf_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, Game_SWF_ready);
//Treat the Loader contents (flashgame.swf) as a MovieClip named "my_Game_Swf"
my_Game_Swf = swf_loader.content as MovieClip;
my_Game_Swf.gameSpeed = set_gameSpeed; //update gameSpeed variable in flashgame.swf
//also adjust SWF placement (.x and .y positions etc) here if necessary
stage.addChild(my_Game_Swf);
_SWF_is_loaded = true;
}
Now in you flashgame file make sure the there's also an actions layers and put in code like this below then compile it first before debugging the Intro/Parent file. When your Intro loads the flashgame.swf it should load an swf that already has the code below compiled.
flashgame.swf
var gameSpeed:int;
gameSpeed = 0; //initial value & will be changed by parent
addEventListener(Event.ADDED_TO_STAGE, onAdded_toStage);
function onAdded_toStage (e:Event):void
{
trace("trace gameSpeed is.." + String(gameSpeed)); //confirm speed in Debugger
//*** Example usage ***
var my_shape:Shape = new Shape();
my_shape.graphics.lineStyle(5, 0xFF0000, 5);
my_shape.graphics.moveTo(10, 50);
my_shape.graphics.lineTo(gameSpeed * 10, 50); //this line length is affected by gameSpeed as set in parent SWF
addChild(my_shape);
}
The key line in intro.swf is this: my_Game_Swf.gameSpeed = set_gameSpeed; as it updates a variable in flashgame.swf (referred as my_Game_Swf) with an amount that is taken from a variable in the Parent SWF.
This is just one way you can access information between two separate SWF files. Hope it helps out.

Related

How to make a score in a dynamic textfield display on another frame?

I'am trying to make a scoring system by using a timer so that it work on the basis that as the player keeps on going the timer/score keeps on going up and I got that to work with this code.
var nCount:Number = 0;
var myScore:Timer = new Timer(10, nCount);
score_txt.text = nCount.toString();
myScore.start();
myScore.addEventListener(TimerEvent.TIMER, countdown);
function countdown(e:TimerEvent):void{
nCount++;
score_txt.text = nCount.toString();
}
However say for example the player crashes I want the game to remember the score and then display it on another frame where I have a game over screen so that it shows the final score to the player and this is the part that I have no idea how to do. Any help would be appreciated.
Many Thanks
You can't modify objects on "another frame". You can only modify objects on the current frame. The frames simply represent state that is baked into the SWF to be actualized when the timeline reaches those frames; you cannot change SWF frame data at runtime. You can only change the resulting objects once those frames are constructed by the player.
What you can do is store your score in a variable (available across all frames) and simply set the correct text objects when you are on those frames.
For your code, you simply need to only set the nCount to 0 when the SWF loads (or you want to reset it), and set the score_txt immediately on the frame it exists. For example, you could do it like this:
// Don't initialize a value, that would overwrite
// it every time this frame is visited
var nCount:Number;
// Only the first time, when the value is NaN, set the score to 0
if(isNaN(nCount)){
nCount = 0;
}
// Immediately show the current score text
score_txt.text = nCount.toString();
// The rest stays the same
var myScore:Timer = new Timer(10, nCount);
score_txt.text = nCount.toString();
myScore.start();
myScore.addEventListener(TimerEvent.TIMER, countdown);
function countdown(e:TimerEvent):void{
nCount++;
score_txt.text = nCount.toString();
}

Compositing the stage's last frame

I've created a series of classes that can be used to generate and render images. I want to store a copy of the last frame displayed so I can mix it with the current frame to create a video sustain effect. A brief overview of the classes involved in this example:
MasterContainer: a subclass of Sprite used as the main display object. Generative classes are placed in the MasterContainer, and redrawn when the container is told to render
CustomWave: a subclass of Shape used to contain, draw, and manipulate a GraphicsPath object. One of the aforementioned 'generative classes'
My current attempt involves the use of two MasterContainer objects - one for the current frame, and one for the last frame. If I'm not mistaken, the current appearance of one MasterContainer (and its children) can be copied to the other with a command like lastMaster.graphics.copyFrom(master.graphics);. Consider the following code:
var time:Number;
var master:MasterContainer = new MasterContainer(); //current frame
var lastMaster:MasterContainer = new MasterContainer(); // last frame
var wave:CustomWave = new CustomWave(new <Number>[0,0,0,0],0xffffff,5); //generator for current frame
master.RegisterComponent(wave); //adds CustomWave and registers with the rendering loop
addChild(lastMaster); //add last frame to stage
addChild(master); //add current frame to stage
addEventListener(Event.ENTER_FRAME, perFrame);
function perFrame(event:Event):void{
time = 0.001 * getTimer();
lastMaster.graphics.copyFrom(master.graphics); //copy previous frame's graphics
UpdatePoints(); //update the path of the CustomWave
UpdateColor(); //update the color of the CustomWave
master.fireRenderCannon(); //redraw objects registered to master
}
This seems to work in theory, but as far as I can tell lastMaster ends up with no visible graphics content even though master renders as expected. I've tried several times to test whether this is the case, and am pretty convinced that that it is, but am newish to AS3 and am concerned I am overlooking something - the code looks like it should work. Does anyone have suggestions on how to test this properly? Are there obvious defects within this code that would cause lastMaster to be visually blank? Is there an better way of accomplishing my goal?
I think I'm in over my head on this... I would love any input. Thanks!
After you copied graphics, what do you try to do with it?
Method copyFrom works as clocks, without any problems. Isn't here logic bug in your code?
function perFrame(event:Event):void{
time = 0.001 * getTimer();
lastMaster.graphics.copyFrom(master.graphics); //Here
//master.graphics.copyFrom(lastMaster.graphics);
UpdatePoints();
UpdateColor();
master.fireRenderCannon();
}
Example of copyFrom, it works fine with any complexity of graphics:
var complex: Shape = new Shape();
adobeExample(complex.graphics);
var test2: Shape = new Shape();
test2.graphics.copyFrom(complex.graphics);
addChild(test2);
private function adobeExample(graphics: Graphics):void{
// define the line style
graphics.lineStyle(2,0x000000);
// define the fill
graphics.beginFill(0x666699);//set the color
// establish a new Vector object for the commands parameter
var star_commands:Vector.<int> = new Vector.<int>();
// use the Vector array push() method to add moveTo() and lineTo() values
// 1 moveTo command followed by 3 lineTo commands
star_commands.push(1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2);
// establish a new Vector object for the data parameter
var star_coord:Vector.<Number> = new Vector.<Number>();
// use the Vector array push() method to add a set of coordinate pairs
star_coord.push(0,0, 75,50, 100,0, 125,50, 200,0, 150,75, 200,100, 150,125, 200,200, 125,150, 100,200, 75,150, 0,200, 50,125, 0,100, 50,75, 0,0);
graphics.drawPath(star_commands, star_coord);
}
After the comments made by Bennet and Nicolas, it became obvious that my requirements were (nearly) impossible without a fair amount of redesign. The changes made are as follows:
Generators are no longer DisplayObjects. They are only used to calculate vectors containing the IGraphicsData objects necessary to draw the generated graphic with the drawGraphicsData method.
MasterContainer is now a shape subclass that retrieves the Vector.<IGraphicsData> from each registered generator in order to draw the output.
A bitmap subclass is used to render the contents of the MasterContainer, combining it with a color-dampened version of the previous frame.
An abridged version of the bitmap subclass:
private var constantSustain:Number;
private var linearSustain:Number;
private var sustain:ColorTransform;
private var lastFrame:BitmapData;
public function BitmapManipulator(constantSustain:Number = 0.998, linearSustain:Number = 0.98) {
this.constantSustain = Math.min(Math.max(constantSustain, 0), 1);
this.linearSustain = Math.min(Math.max(linearSustain, 0), 1);
this.UpdateSustain();
this.addEventListener(Event.ADDED_TO_STAGE, OnAddedToStage)
}
private function UpdateSustain():void {
var constantRelease:Number = 255 * (this.constantSustain - 1);
this.sustain = new ColorTransform(this.linearSustain, this.linearSustain, this.linearSustain, 1,
constantRelease, constantRelease, constantRelease, 0);
}
private function OnAddedToStage(event:Event) {
this.lastFrame = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0);
}
public function DrawFrame(container:MasterContainer):void {
this.lastFrame.draw(container);
this.bitmapData = lastFrame;
this.lastFrame = this.bitmapData
this.lastFrame.colorTransform(getBounds(this), this.sustain);
}
...and finally the results #60fps when using an indigo sine wave of shifting phase as the input for the CustomWave:

Using an array to load in multiple images in Actionscript

I have a class assignment where I have to create a photo gallery and one of the stipulations is that the images need to be loaded from an external source. The reference code from our assignment was:
var myRequest:URLRequest = new URLRequest("bw1.jpg");
myLoader.load(myRequest);
addChild(myLoader);
My specific needs requires me to have up to 2 copies of the images on the screen at once, one as a thumbnail and a second as a fullsized image. I want it so that when a user clicks a thumbnail a new instance of the picture is created scaled to fullsize with 0 alpha and the current selected picture decreases in alpha as the new pic increases in alpha. Once the old pic is no longer visible it is removed from the stage.
I am having trouble figuring out how to create a copy of the image in actionscript and also my for loop seems to not be executing properly as it only ever goes through one iteration even when I have no error messages.
Here is a link to my code via pastebin: http://pastebin.com/iadgKgsk but to save you from having to switch back and forth between I will also past it here
import flash.display.Bitmap;
//creates a loader for each picture to be loaded, I know I could have an empty array
that I add to but created a full array to test.
var loaders:Array = [new Loader(),new Loader(), new Loader(), new Loader(), new
Loader(), new Loader(), new Loader(), new Loader(), new Loader(), new Loader()];
//stores the url request for each image to be loaded
var Requests:Array =[new URLRequest("pic1.jpg"),new URLRequest("pic2.jpg"),new
URLRequest("pic3.jpg"),
new URLRequest("pic4.jpg"),new URLRequest("pic5.jpg"),new URLRequest("pic6.jpg"), new
URLRequest("pic7.jpg"),
new URLRequest("pic8.jpg"), new URLRequest("pic9.jpg"),new URLRequest("pic10.jpg")];
//creates 2 empty arrays one to store the thumbnail sized pics the other fullsized.
Ideally I want one Array holding the bitmap data and the other holding the thumbnail
instances since I only need 2
// fullsized images at a time I can just create a new one and erase the old one in a
single function.
var pics:Array = new Array();
var pics2:Array = new Array();
//defines an empty bitMap variable as a placeholder for which to copy from redefined in
every iteration of the loop
var test:Bitmap;
//loops through every loader
for (var i in loaders);
{
// loads the loader and url request and creates a picture
loaders[i].load(Requests[i]);
//waits for the pic to load
loaders[i].contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);
//after loader is loaded create pic from the data
function loadComplete(evt:Event):void
{
var i = "Test";
trace(i);
test= evt.target.content as Bitmap;
pics2[i] = test;
pics[i] =new Bitmap(test.bitmapData);
pics2[i] =new Bitmap(test.bitmapData);
//creates an image on the stage at runtime to help debug
var pic1 = new Bitmap(test.bitmapData);
addChild(pics[i])
pic1.scaleX = 0.138427734375;
pic1.scaleY = 0.1384114583333333;
pic1.x = 204;
pic1.y = 20.6;
pic1.alpha = .25;
var pic2:Bitmap = new Bitmap(test.bitmapData);
pic2.x =100;
pic2.y =100;
pic2.scaleX =.33;
pic2.scaleY=.33;
addChild(pic2);
loaders[i].contentLoaderInfo.removeEventListener(Event.COMPLETE,
loadComplete)
}
}
Your for loop is setup in a way that it would attempt to iterate for each property of the loaders instance which isn't what you want. You may want to investigate other AS3 bulk loader options too there are already some scripts out there to help take care of this.
Your loop should look like
for(var i=0; i<loaders.length; i++)
{
var curLoader = loaders[i].load(Requests[i]);
You can also see an example I put together that loads a bunch of images flipbook style animation (images generated with blender):
http://www.shaunhusain.com/DrawTextRandomly/
http://www.shaunhusain.com/DrawTextRandomly/srcview/
look in the utils.imageLoader package, I made two classes there that deal with loading the images, since they were output from Blender with sequential file names I just used some loops to load the images based on a numeric counter, in your case you could switch it to use a source array of images to load.
In the BatchImageLoader class I have a variable for how many loaders to allow it to make, I wanted to see the difference in performance in terms of memory vs load time (will depend on runtime environment too but I wanted to get a general idea, ended with leaving it at using 90 loaders at most).

AS#3 loading SWF Multiple

Im loading multiple SWF of the same file
Example:
var movies:Array = new Array ("Symbols/00.swf","Symbols/00.swf","Symbols/00.swf");
My loading method works fine, below im using:
var perc:int = (event.bytesLoaded / event.bytesTotal) * 100;
Loading.text = "loading " +perc + "%";
The Problem im having is the the loading text is at %100 after iv downloaded one item from the Movies:Array.
This would be happening because the remainder files are already in the catch.
The question is:
How would I be able to slow this loading text to determine if all the items are ready.Basically the problem is that the loading text saids complete but all my other files
are not ready yet...
First, why do you ever load one SWF multiple times? You can use the following trick: How to display multiple instances of loaded SWF. And second, you are using your Loader object to load one SWF at a time, and its progress will be related to that single SWF. So, you first load all unique SWFs and store their Loader references somewhere, in order to instantiate more of those if you need to, and second, you are to collect total percentage from progress event listener. The latter is slightly complicated, because you are most likely using a single progress event listener for all the loaders. You, for example, can do something like this:
public static var ALL_LOADERS:Object;
public static var PROGRESS_DATA:Object; // we need associative arrays here
public static var BYTES_LOADED:int=0;
public static var TOTAL_BYTES:int=0;
public static function RegisterLoader(path:String,loader:Loader):void {
if (!ALL_LOADERS) ALL_LOADERS=new Object();
if (!PROGRESS_DATA) PROGRESS_DATA=new Object();
ALL_LOADERS[path]=loader;
PROGRESS_DATA[loader]=new Object();
PROGRESS_DATA[loader].bytesLoaded=0;
PROGRESS_DATA[loader].bytesTotal=-1;
}
// now a listener
public static function progressListener(e:Event):void {
var l:Loader=e.target as Loader;
if (!l) return; // that wasn't a loader that sent the event. Uh oh
var plo:Object=PROGRESS_DATA[l];
if (!plo) return; // unregistered loader. Ignore
if (plo.bytesTotal<0) {
plo.bytesTotal=e.bytesTotal;
TOTAL_BYTES+=e.bytesTotal;
}
var pbl:int=plo.bytesLoaded;
plo.bytesLoaded=e.bytesLoaded;
LOADED_BYTES+=(e.bytesLoaded-pbl);
var perc:int = (LOADED_BYTES / TOTAL_BYTES) * 100;
Loading.text = "loading " +perc + "%";
}
Note, as the loading process is designed to be run only once, all initialization is made once, and this code does not have error handling - you can, however, write it yourself.

How can I load a Papervision/Flex application (SWF) as a material on a Papervision plane?

I am trying to build a portfolio application similar to the used by Whitevoid. I am using Flex 4 and Papervision3D 2. I have everything working except for one issue. When I try to load an external SWF as a material on one of the planes, I can see any native Flex or Flash components in their correct positions, but the papervision objects are not being rendered properly. It looks like the viewport is not being set in the nested swf. I have posted my code for loading the swf below.
private function loadMovie(path:String=""):void
{
loader = new Loader();
request = new URLRequest(path);
loader.contentLoaderInfo.addEventListener(Event.INIT, addMaterial);
loader.load(request);
}
private function addMaterial(e:Event):void
{
movie = new MovieClip();
movie.addChild(e.target.content);
var width:Number = 0;
var height:Number = 0;
width = loader.contentLoaderInfo.width;
height = loader.contentLoaderInfo.height;
//calculate the aspect ratio of the swf
var matAR:Number = width/height;
if (matAR > aspectRatio)
{
plane.scaleY = aspectRatio / matAR;
}
else if (matAR < aspectRatio)
{
plane.scaleX = matAR / aspectRatio;
}
var mat:MovieMaterial = new MovieMaterial(movie, false, true, false, new Rectangle(0, 0, width, height));
mat.interactive = true;
mat.smooth = true;
plane.material = mat;
}
Below I have posted two pictures. The first is a shot of the application running by itself. The second is the application as a MovieMaterial on a Plane. You can see how the button created as a spark object in the mxml stays in the correct position, but papervision sphere (which is rotating) is in the wrong location. Is there something I am missing here?
Man. I haven't seen that site in a while. Still one of the cooler PV projects...
What do you mean by:
I cannot properly see the scene rendered in Papervision
You say you can see the components in their appropriate positions, as in: you have a plane with what looks like the intended file loading up? But I'm guessing that you can't interact with it.
As far as I know, and I've spent a reasonable amount of time trying to make something similar work, the MovieMaterial (which I assume you're using) draws a Bitmap of whatever contents exist in your MovieClip, and if you set it to animated=true, then it will render out a series of bitmaps - equating animation. What it's not doing, is displaying an actual MovieClip (or SWF) on the plane. So you may see your components, but this is how:
MovieMaterial.as line 137
// ______________________________________________________________________ CREATE BITMAP
/**
*
* #param asset
* #return
*/
protected function createBitmapFromSprite( asset:DisplayObject ):BitmapData
{
// Set the new movie reference
movie = asset;
// initialize the bitmap since it's new
initBitmap( movie );
// Draw
drawBitmap();
// Call super.createBitmap to centralize the bitmap specific code.
// Here only MovieClip specific code, all bitmap code (maxUVs, AUTO_MIP_MAP, correctBitmap) in BitmapMaterial.
bitmap = super.createBitmap( bitmap );
return bitmap;
}
Note in the WhiteVoid you never actually interact with a movie until it "lands" = he's very likely swapping in a Movie on top of the bitmap textured plane.
The part that you are interacting with is probably another plane that holds the "button" that simply becomes visible on mouseover.
I think PV1.0 had access to real swfs as a material but this changed in 2.0. Sadly. Hopefully Molehill will.
cheers