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

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

Related

Collision detection kit with FlashPunk

I start creating my flash game using Flashpunk, for collisions i didn't want to use hitboxes because i had images (PNG) with transparent parts in them so i decided to use Collision Detection Kit, i have a problem when creating the collision list, it takes a display object as a parameter and doesn't accept flash punk spritemaps, i tried to cast the spritemap to a flash display object but it's not working, is there a way to use the CDK with flashpunk ?
override public function begin():void
{
_player = new Player(100, 100);// Entity
initCollision(_player.sprPlayer);// The Entity Spritemap
}
private function initCollision(player:Spritemap):void {
collisionChecker = new CollisionList(player); // Problem here
}
Well, you could create an empty BitmapData with the same width & height of your Spritemap and then "render" it to that BitmapData, like so:
var bmd:BitmapData = new BitmapData(64, 64, true, 0);
var sprite:Spritemap = _player.sprPlayer;
sprite.render(bmd, new Point(0,0), new Point(0,0));
collisionChecker = new CollisionList(bmd);
That should draw the spritemap's current frame to a BitmapData which you could then use for the CollisionList. The code above is an example that only demonstrates how to do this. For your actual code, it would be better to avoid constantly initializing new variables during your collision detection.

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.

load an external swf (FlashPaper pdf) into a flash project

I have to do a very simple swf application able to show a series of pdf files.
Actually I was able to create on a single layer the menu interface (some buttons on frame 0 which redirect the user to other frames where the pdf should be showed).
Here my question:
I need a way to read the pdf inside the flash frame.
I've found a possible solution converting the pdf into an swf with FlashPaper 2
Now I wish to know how import the swf into the frame.
Reading some actionscript 3 guides I was able to create a container movieclip (a simple rectangle) into which I have loaded the swf with this code:
var swf:MovieClip;
var loader:Loader = new Loader();
var defaultSWF:URLRequest = new URLRequest("test.swf"); //test.swf is my converted pdf
loader.load(defaultSWF);
screen_01.addChild(loader); //screen_01 is the container rectangle converted to movieclip
I've used a container movieclip to mantain the other objects (menu buttons) on the frame, and ecause it helps with the swf positioning.
I seen it is possible also using loader.x and loader.y and it works.
Unfortunately I wasn't able to control width and height of the swf/pdf file (loader.width and loader.height exists but if used cause the swf will not loaded at all)
Solution:
I've found a possible solution at this page. The idea is to change swf scale only after the load process is complete (positioning can be done even before).
Anyway I had to use Actionscript 2 for this project because FlashPaper converted pdf doesn't work properly with AS3, I don't know why...
here the code:
//insert an emplty movieclip to load the swf, I've called it screen_01
var movLoad:MovieClipLoader = new MovieClipLoader();
var myListener:Object = new Object();
myListener.onLoadInit = function(thisMc:MovieClip) {
thisMc._height = 600;
thisMc._width = 900;
thisMc._x = 50;
thisMc._y = 30;
};
movLoad.addListener(myListener);
movLoad.loadClip("folder/flashpaper_converted_pdf.swf.swf",screen_01);
You can modify the size of the loader using scaleX and scaleY properties.
Keep them equals so the swf isn't stretched.
You may also want to listen to the COMPLETE event to do such a thing :
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
function onComplete(e:Event)
{
var loader:Loader = e.currentTarget.loader;
loader.scaleX = loader.scaleY = 2; //Double the size of the loaded swf
}

Use bitmapData.hitTest on two bitmapData with centered registration point

I've spent all the day on this, it's time to ask for your help :)
I'm trying to do collision detection of two display objects, both have centered registration point.
On my stage I have fixed elements that when added to stage are pushed in an Array called "zoneUsed". All the displayObject in my project have the registration point in the center.
My goal is to click on the stage, and check if in the clicking coords I could create a circle. My plan was to create a Sprite for the new object, cycle on the zoneUsed array, and check if the new sprite have enough space to live.
Here my code so far:
private function checkSpaceForNewMarker (markerToCheck:Sprite):Boolean {
var isPossible:Boolean = true;
var bmdataToCheck:BitmapData = new BitmapData (markerToCheck.width, markerToCheck.height, true, 0);
var m:Matrix = new Matrix ();
m.tx = markerToCheck.width/2;
m.ty = markerToCheck.height/2;
bmdataToCheck.draw (markerToCheck, m);
for (var i:int = 0; i<zoneUsed.length; i++) {
trace ("*** CHECKING ****");
var bmddataOnTheTable:BitmapData = new BitmapData (zoneUsed[i].width, zoneUsed[i].height, true, 0);
var tableMatrix:Matrix = new Matrix ();
tableMatrix.tx = zoneUsed[i].width/2;
tableMatrix.ty = zoneUsed[i].height/2;
bmddataOnTheTable.draw(zoneUsed[i], tableMatrix);
if (bmdataToCheck.hitTest(new Point(markerToCheck.x, markerToCheck.y), 255, bmddataOnTheTable, new Point (zoneUsed[i].x, zoneUsed[i].y), 255)) {
trace ("COLLISION");
isPossible = false;
} else {
trace ("NO COLLISION");
isPossible = true;
}
}
return isPossible;
}
....But right now the results are weird. Depending on the zones, my traces work or not. What am I doing wrong?
The problem is , you are drawing 1/4 (quarter) part of every object.
BitmapData is not like a Shape, Sprite, MovieClip, and it crops all the pixels, when the drawing bounds is out of the bounds of (0,0,bitmapdata.width, bitmapdata.height) rectangle.
Just remove this lines:
m.tx = markerToCheck.width/2;
m.ty = markerToCheck.height/2;
and also
tableMatrix.tx = zoneUsed[i].width/2;
tableMatrix.ty = zoneUsed[i].height/2;
You don't need this translations.
Also your code may be cause for memory leak. You are creating bitmapdata, but do not dispose it. The garbage collector will not release the memory you have allocated.You must release memory explicitly. Call bitmapdata.dispose() every time you have no need of that bitmapdata.
I'm not sure that the origin of the bitmap has anything to do with the test itself. The very nature of the test would seem to imply that the hittest is based on the RGBA value of the two supplied bitmaps. Anyway rather than picking apart your own implementation I'll just refer you to a tutorial by Mike Chambers (adobe platform evangelist). http://www.mikechambers.com/blog/2009/06/24/using-bitmapdata-hittest-for-collision-detection/
Also for more flash tutorials check out www.gotoandlearn.com.