I ran into a problem while working with Flare3D on a game. I was making a racing game, and the player drives through five areas. The problem was that each area the user drives through was a very detailed envirnment. About 4-10 megabytes a piece. Far too large for player to download up front.
So I decided to build a progressive preloader, that loads the levels as the player plays. At first I tried this using the Flare3DLoader class. In using it I encountered two problems, one of which was a fatal problem for the approach:
Problem 1:
The Flare3DLoader class will never fire a Complete event unless it is attached to a scene. It makes sense in a way, in that your model is not ready to be accessed through the Flare3D api until it has been parsed. But the downside is that you can’t know the load is complete unless add the loaded resource to the scene.
While I got this to work, it could easily cause problems as all these items get unpacked into your limited OpenGL memory. Another drawback is that you cannot re-load the asset either. Once you call dispose() on the loaded asset, its gone.
Problem 2:
When the asset finishes loading, the entire flash plugin freezes for a second or more while your model is parsed and written to the GPU. This was the deal-breaker for me, as the end result was that the game would hang for one or more seconds at an arbitrary point in time. I needed to have specific control over when the model gets parsed so that the user experience is not disrupted.
The solution:
The solution was two part. I realized that underneath the Flare3DLoader there must be a URLLoader that was loading the model file and then parsing it. So I loaded one up and tried to pass it to the Flare3DLoader constructor. After some trial and error I found that by setting the URLLoader dataFormat to Binary, this worked.
var loader:URLLoader = new URLLoader(); loader.dataFormat = URLLoaderDataFormat.BINARY; loader.addEventListener(ProgressEvent.PROGRESS, onLoadProgress); loader.addEventListener(Event.COMPLETE, onLoadComplete); |
The second part was using ByteArray to make a copy of the loaded data so that the level could be loaded more than once. This was crucial to being able to click “replay” on the game.
var data:ByteArray = new ByteArray(); // This line copies the loader.data. data.writeObject(loader.data); // reset the byte array to be read. data.position = 0; // pass the copy of the data into flare 3D as a loader. var model:Flare3DLoader = new Flare3DLoader(data.readObject()); // Add the loader to the scene. scene.addChild(model); // You may want to listen for when you model is parsed and ready. // In that case just add: model.addEventListener(Scene3D.COMPLETE_EVENT, onModelLoaded); |

I Zach Foley, can you help me?
I’m beginner in flare3d using FlashBuilder, this ActionScript project have a main file importing the file solution above (your solution in this page), my question is? where i put the name file .f3d to load it
// I put your solution inside a package but i think maybe not be correct
// ActionScript file
package
{
import flare.basic.Scene3D;
import flare.basic.Viewer3D;
import flare.core.Pivot3D;
import flare.loaders.Flare3DLoader;
import flash.display.Loader;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.utils.ByteArray;
public class solution extends MovieClip
{
private var scene:Scene3D;// i have a scene in my main.as – there is necessary to have it again???
private var loader:URLLoader;
private var box:Pivot3D;
private var model:Flare3DLoader;
// class constructor
public function solution ()
{
// The first part
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
loader.addEventListener(Event.COMPLETE, onLoadComplete);
// The second part
var data:ByteArray = new ByteArray();
// This line copies the loader.data.
data.writeObject(loader.data);
// reset the byte array to be read.
data.position = 0;
// pass the copy of the data into flare 3D as a loader.
model = new Flare3DLoader(data.readObject());
// Add the loader to the scene.
scene.addChild(model);
// You may want to listen for when you model is parsed and ready.
// In that case just add:
model.addEventListener(Scene3D.COMPLETE_EVENT, onModelLoaded);
}
//
public function onLoadProgress(event:ProgressEvent):void
{
var loaded:Number = event.bytesLoaded / event.bytesTotal;
trace(loaded);
}
public function onLoadComplete(event:Event):void
{
trace(“Loading Complete”)
}
public function onModelLoaded(event:Event):void
{
}
}
}
P.S. I read your profile and i glad to see you work with Flash since version 3 and play with Arduino like me, sorry about my English and 1M thanks in advanced.
Awesome, this will come in handy. Thanks.
To the above commenter – I’m pretty sure it would be like this (as with any other URLLoader):
// class constructor
public function solution ()
{
// The first part
var request:URLRequest = new URLRequest("my 3d file.f3d")
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
loader.addEventListener(Event.COMPLETE, onLoadComplete);
loader.load(request)
@Tim B thanks for your post but the file .f3d to trying load not appears on stage
I make this new code, no errors result and onLoadComplete funtion tell us loading complete but file not appears on stage and onModelLoaded function not fired, why?
If any person want load the two f3d files i use in project can load it from:
http://flash4all.no.sapo.pt/flare3d/box.f3d
http://flash4all.no.sapo.pt/flare3d/plane.f3d
And base.as:
http://flash4all.no.sapo.pt/flare3d/base.zip
package
{
import base.*;
import flare.basic.*;
import flare.core.*;
import flare.loaders.Flare3DLoader;
import flash.display.*;
import flash.display.Loader;
import flash.events.*;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.utils.ByteArray;
[SWF(frameRate = 60, width = 1200, height = 600, backgroundColor = 0x000000)]
public class load_multiple_files extends Base
{
private var scene:Scene3D;
private var terrain:Pivot3D;
private var axis:Pivot3D;
// vars for solution load .f3d files
private var loader:URLLoader;
private var request:URLRequest;
private var data:ByteArray;
private var model:Flare3DLoader;
// for output traces
private var displayField:TextField;
private var defaultTextFormat:TextFormat;
// shape for button
private var shape01:Sprite;
public function load_multiple_files()
{
super( “Try load multiple .f3d files” );
// stage configuration.
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
// creates a new 3d scene.
scene = new Viewer3D( this );
scene.camera = new Camera3D( “myOwnCamera” );
// we can manipulate the camera just like any 3d object.
scene.camera.setPosition( 0, 50, -100 );
scene.camera.lookAt( 0, 0, 0 );
// add global scene progress and complete events.
scene.addEventListener( Scene3D.PROGRESS_EVENT, progressEvent );
scene.addEventListener( Scene3D.COMPLETE_EVENT, completeEvent );
// loads the initial objects.
terrain = scene.addChildFromFile( “plane.f3d” );
axis = scene.addChildFromFile( “http://wiki.flare3d.com/demos/resources/axis.f3d” );
// this prevents to flare3d to start render before the objects are completly loaded.
scene.pause();
// call function for textfield output
displayOutput();
//
createShapes();
listenerShapes();
}
// create textfield for output traces
public function displayOutput():void {
displayField = new TextField();
displayField.selectable = false;
displayField.defaultTextFormat = new TextFormat( “arial”, 16, 0xff0000 );
displayField.border = true;
displayField.wordWrap = true;
displayField.width = 400;
displayField.height = 50;
displayField.multiline = true;
displayField.text = “click on Red button to cal function solution to load other file .f3d “;
displayField.x = 400;
displayField.y = 0;
addChild( displayField );
}
// listeners for button shape
public function listenerShapes():void {
shape01.addEventListener(MouseEvent.MOUSE_UP,shape01UpHandler);
}
public function shape01UpHandler(event:MouseEvent):void {
// call function solution
solution();
}
// create shape
public function createShapes():void {
shape01 = new Sprite();
shape01.graphics.beginFill(0xff0000,1);
shape01.graphics.drawRoundRect(50, 50, 50, 50, 10);
shape01.graphics.endFill();
shape01.x = 100;
shape01.y = 10
shape01.buttonMode = true;
addChild( shape01 );
}
private function progressEvent(e:Event):void
{
// gets the global loading progress.
trace( scene.loadProgress );
}
private function completeEvent(e:Event):void
{
// once the scene has been loaded, resume the render.
scene.resume();
// start to update the scene.
// the update event is like the enterFrame of Flare3D, but it is synchronized with the time
// and it is dispatched constantly at scene.frameRate property. (by default is 45).
scene.addEventListener( Scene3D.UPDATE_EVENT, updateEvent );
}
private function updateEvent(e:Event):void
{
// simply rotate the model on ‘y/up’ axis every frame.
terrain.rotateY(2);
}
// SOLUTION – all functions below to try load and preloading .f3d file
public function solution():void
{
// The first part
request = new URLRequest(“box.f3d”)
loader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
loader.addEventListener(Event.COMPLETE, onLoadComplete);
loader.load(request);
// The second part
data = new ByteArray();
// This line copies the loader.data.
data.writeObject(loader.data);
// reset the byte array to be read.
data.position = 0;
// pass the copy of the data into flare 3D as a loader.
model = new Flare3DLoader(data.readObject());
// Add the loader to the scene.
scene.addChild(model);
// You may want to listen for when you model is parsed and ready.
// In that case just add:
model.addEventListener(Scene3D.COMPLETE_EVENT, onModelLoaded);
}
//
public function onLoadProgress(event:ProgressEvent):void
{
var loaded:Number = event.bytesLoaded / event.bytesTotal;
displayField.text = “Loading = “+loaded;
}
public function onLoadComplete(event:Event):void
{
displayField.text = “Inside body onLoadComplete function”;
}
public function onModelLoaded(event:Event):void
{
displayField.text = “Inside body onModelLoaded function”;
}
}
}