as3 animation with multiple images - actionscript-3

I have only 3 images that I'm working with for animating a running animal:
1: animal standing
2: animal in stride/jumping
3: animal on its back dead
Currently, I'm embedding them into the main class as sprites and changing their .alpha properties whenever I want one and not the other 2. Is there a better way to do what I'm doing? One of the annoying things is updating the properties for each sprite individually. It would be ideal to have one object and being able to change the image on the object so I would only have to change one object's properties.

For this it would be best to handle your animation in its own Class!
Something like this, let's say your animal is a horse so that's what I'll call the class
package {
import flash.display.Sprite;
public class Horse extends Sprite{
private var holder:Sprite = new Sprite();
public function Horse() {
var img1:Image1 = new Image1();// ur images from library
var img2:Image2 = new Image2();
var img3:Image2 = new Image3();
holder.addChild(img1);
holder.addChild(img2);
holder.addChild(img3);
addChild(holder);
setImage(0);// set 1st image visible
}
public function setImage(nr:uint):void
{
for(var i:int = 0; i < holder.length;i++;)
holder[i].visible = false;
holder[nr].visible = true;
}
}
}
then you would use it like this for example!
var horse:Horse = new Horse();
addChild(horse);
horse.x = 25;
horse.y = 25; // move the whole object(all 3 images)
horse.setImage(2);// or to whatever frame you need
Use the visible attribute instead of the alpha value. If u just set alpha to 0 it will still be rendered and cost cpu. if you set visible to false it will not be rendered!
EDIT: As Amy pointed out, blitting is a possibilty here to, although the fastest aproach would be BitmapData Frame Assignment!
Here you keep all your Frames as BitmapData in a Vector, which you load from a SpriteSheet and just assign the new BitmapData to your Bitmap instead of using copyPixels. It's faster then blitting and you still have all your builtin methods availible!!

Related

How Can I Make AS3 Var Loop move speed on the Y Axis on repeat my university project

I'm tring to get the car image to move down the screen on the y Axis and make it a repeat and colide with another object
//creates the new Car
for (var c:int=0; c<8; c++){
var newcar = new car();
newcar.x = 55*c;
newcar.y = 100;
EntityArray.push(newcar);
stage.addChild(newcar);
trace("Car Created"+c)
}
How to make it colide with the following and remove it from screen
//creates the new Frog
for (var f:int=0; f<1; f++){
var newfrog = new frog();
newfrog.x = 210;
newfrog.y = 498;
EntityArray.push(newfrog);
stage.addChild(newfrog);
trace("Frog Created"+f)
}
[image][1][1]: https://i.stack.imgur.com/Ihsfx.png
Though I'm quite pleased to hear that today they still tell you about ActionScript at college, it's a bit hard
to give you advice here since I don't know what they've covered yet.
Generally speaking, you could realize this with a simple game loop, that runs periodically and in it's most simple
form:
checks user input (in your case most likely pressing left/right to move the frog)
update game state (move the cars & the frog ; check for collision)
draw everything to screen
For creating the periodical loop, Flash/ActionScript offers a powerful event called ENTER_FRAME. Once started, it
will fire with the framerate of the movie. So if you set your movie to 60fps, it will execute it's callback function
roughly every 17ms.
I assume your instances of Frog and Car extend Flash's Sprite or MovieClip class - so collision detection is also pretty
easy since you can use the inherited hitTestObject() method.
To make things a bit easier though I'd recommend that you don't put the reference to the frog instance inside the EntityArray.
Better use a global reference. (Also, you don't need a for-loop because there's just one frog)
As another sidenote, it's quite common that classnames start with a capital letter.
private var newfrog:frog; // defines a class variable we can access anywhere inside our class
//Later on instantiate new cars and the frog:
for (var c:int=0; c<8; c++){
var newcar = new car();
newcar.x = 55*c;
newcar.y = 100;
EntityArray.push(newcar);
stage.addChild(newcar);
}
newfrog = new frog();
newfrog.x = 210;
newfrog.y = 498;
stage.addChild(newfrog);
addEventListener(Event.ENTER_FRAME, loop); // register an ENTER_FRAME listener for the main game loop
private function loop(e:Event):void
{
var tempCar:car;
for(var a:int=0;a<EntityArray.length;a++)
{
tempCar=EntityArray[a]; // get a car from the EntityArray
tempCar.y++; // move it down on screen
if(tempCar.y>600) // if it's vertical position is greater than 600...
{
tempCar.y=0; // ...move it back to the top
}
if(newfrog.hitTestObject(tempCar)) // evaluates to true, if a car and the frog's bounding boxes overlap
{
trace("there's a collision!"); // do something
}
}
}

Using an instance more than once when creating a MovieClip through composition

FURTHER EDIT: Added second parameter to clarify that TreeGenerator is using pre-created parts from the Sprites passed through the parameter, not generating them.
EDIT: I've attempted to change the code away from using "shapes" and "MovieClips" as that was kind of confusing and obscuring the issue I was having.
I'm trying to create a Sprite by using that parts of other Sprites. I've posted some code that illustrates what I'm trying to do:
public class TreeGenerator extends Sprite
{
private var _leaf:Sprite
private var _branch:Sprite
private var _trunk:Sprite
//these are separately drawn and instantiated in other sprites,
//one of which will be passed through in the parameters
public var thumbnail:Sprite
public function TreeGenerator($preCreatedTreeOne:Sprite, $preCreatedTreeTwo:Sprite)
{
_leaf = $preCreatedTreeOne.leaf;
_branch = $preCreatedTreeTwo.branch;
_trunk = $preCreatedTreeOne.trunk;
thumbnail = $preCreatedTreeOne.leaf;
//just uses the leaf for this example
this.addchild(_leaf);
_leaf.y = 30;
this.addchild(_branch);
_branch.y = 20;
this.addchild(_trunk);
_trunk.y = 10;
//this "puts together" the tree image (though very
//simply with just y for example purposes)
this.addchild(thumbnail);
thumbnail.y = 40;
//this thumbnail is supposed to be a separate object that can also
//be interacted with but this example neglects the event listeners.
//the important thing here is the setting of the y to 40, which
//overwrites the y of 30 for _leaf.
}
}
I'm passing through two Sprites already instantiated to $preCreatedTreeOne and $preCreatedTreeTwo that were created through an assortment of tree parts to choose from (large green leaf, small red leaf, thin branch, thick branch, etc.). Those sprites are drawn images, not images generated in code (say from a .swc library). When the user clicks a button after clicking on two trees on the stage, TreeGenerator will create another image of a tree, complete with leaf, branch, and trunk but this time using the parts from the two pre-created trees (and it would be dynamic, one click would generate a tree with green leaves from tree one, thick branches from tree two, and a thin trunk from tree one, whichever combination of two trees chosen as "one" or "two"). There would also be a separate thumbnail that could be interacted with independently (though that code is omitted in the example).
However, when I run the code, I see that the y coordinate value for _leaf gets overridden by thumbnail, because I now realize that both are now $preCreatedTreeOne.leaf.
How do I "take" additional instances (or copies) of $preCreatedTreeOne.leaf from $preCreatedTreeOne so that I can independently manipulate them when I store them in different variables?
IGraphicsData
You can create objects that correspond to calls to methods of the drawing API. They all implement the above interface. You can then group them in a Vector.<IGraphicsData> and shove them into drawGraphicsData() to get your stuff drawn in a Graphics object.
You are not passing around the meal, but its recipe. You can then cook as many meals according to the recipe as you like.
Since FP 11.6 you can also query Vector.<IGraphicsData> from a Graphics object via readGraphicsData()
disclaimer: I hacked together a modified version of your example code in wonder.fl because I don't have a compiler installed, please implement this properly with separate class files and not internal classes.
My Flash Player is from back in the day when it was still cool to have it and thus a little old (11.2), which means I couldn't actually test the code with readGraphicsData(), which is why I pass the triangle list to all 3 parameters.
package
{
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.IGraphicsData;
import flash.display.GraphicsPath;
import flash.display.GraphicsSolidFill;
import flash.display.GraphicsEndFill;
public class Main extends Sprite
{
public function Main()
{
// assemble Vector.<IGraphicsData> manually for triangle
var triangle:GraphicsPath = new GraphicsPath();
var triangleHeight:uint = 30;
triangle.moveTo(triangleHeight / 2, 0);
triangle.lineTo(triangleHeight, triangleHeight);
triangle.lineTo(0, triangleHeight);
triangle.lineTo(triangleHeight / 2, 0);
var commands:Vector.<IGraphicsData> = new <IGraphicsData>[new GraphicsSolidFill(0xff0000), triangle, new GraphicsEndFill()];
addChild(new ShapeSet(commands, commands, commands));
// since FP 11.6 the following is also possible
// assemble Vector.<IGraphicsData> from existing Graphics object in Shape
var square:Shape = new Shape();
square.graphics.beginFill(0xff00);
square.graphics.drawRect(0, 0, 30, 30);
square.graphics.endFill();
addChild(new ShapeSet(square.graphics.readGraphicsData(), commands, commands));
}
}
}
import flash.display.Sprite;
import flash.display.Shape;
import flash.display.IGraphicsData;
internal class ShapeSet extends Sprite
{
private var _square:Shape;
private var _triangle:Shape;
private var _thumbnail:Shape;
public function ShapeSet(square:Vector.<IGraphicsData>, triangle:Vector.<IGraphicsData>, thumbnail:Vector.<IGraphicsData>)
{
_square = new Shape();
_triangle = new Shape();
_thumbnail = new Shape();
addChild(_square);
_square.x = 10;
addChild(_triangle);
_triangle.x = 60;
addChild(_thumbnail);
_thumbnail.x = 90;
_square.graphics.drawGraphicsData(square);
_triangle.graphics.drawGraphicsData(triangle);
_thumbnail.graphics.drawGraphicsData(thumbnail);
}
}
If you want to pass only triangles to triangles, you should write a triangle class that encapsulates a Vector.<IGraphicsData> and ensures that it only contains data that represents a triangle. How to do this is out of the scope of this question.

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 a Numeric Stepper from one Flash file to affect gamespeed in an external Flash file? Actionscript 3.0

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.

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