We have a new release of OpenFL, with minor releases of Away3D and Starling to match, as well as updated OpenFL and Away3D samples. You can get them all now on Haxelib, or OpenFL and Starling on NPM.
Here’s the OpenFL changelog:
8.4.0 (08/08/2018)
Updated to Lime 7.0.0 (with backward support for Lime 6.4)
Merged doc sources into runtime sources for better display server support
Removed generated documentation from NPM releases to make them smaller
Added support for readObject and writeObject in openfl.net.Socket
Improved native font auto-hinting (disabled when sharpness = 400)
Improved performance by dispatching mouse move events more sparingly
Improved state management between Stage3D and display list rendering
Improved object cleanup when removing children and using DOM rendering
Improved OpenGL rendering when mask objects are on a half-pixel
Fixed support for multiple BitmapData inputs in a custom shader
Fixed GL cacheAsBitmap and bitmapData.draw rendering that uses masks
Fixed openfl.net.Socket to not block while connecting
Fixed support for MouseEvent.ROLL_OVER events when not using ROLL_OUT
Fixed renderer support for bitmap.opaqueBackground
Fixed FullScreenEvent to dispatch with the proper boolean value
Fixed the behavior of copyColumn and copyRow in Matrix
Fixed a small memory leak when using multiple textures in GL Tilemap
Fixed ability to preventDefault on TextEvent.TEXT_INPUT events
Fixed missing dispatch of TextEvent.TEXT_INPUT in some cases
Fixed minor issues in textField.getFirstCharInParagraph
Fixed minor issues in textField.getParagraphLength
Fixed optimizations in EventDispatcher if dispatch is re-entrant
Fixed missing Event.ADDED_TO_STAGE event for SWF-based children
Fixed fullscreen exit event to properly dispatch on HTML5 target
Fixed minor issues in the behavior of bitmapData.draw
Fixed -Dtelemetry to properly enabled advanced-telemetry on Flash
Fixed loader.loaderInfo.width and height values when loading bitmaps
Fixed a regression in setting stage.color to 0
Fixed the orientation of cube textures in Stage3D
Fixed “JPEG-XR+LZMA” warning to output instead of causing an error
If the movie clip class adds a stop command in the last frame, as long as the frame rate changes greatly, it will cause a stop command error. I added a new decision to fix this in the example below.:
public override function __enterFrame (deltaTime:Int):Void {
// if(deltaTime != 0)
// deltaTime = 120;
// // deltaTime = Std.int(1000/60);
if (__symbol != null && __playing) {
var nextFrame = __getNextFrame (deltaTime);
trace("nextFrame="+nextFrame);
if (__lastFrameScriptEval == nextFrame) {
super.__enterFrame (deltaTime);
return;
}
if (__frameScripts != null) {
if (nextFrame < __currentFrame) {
if (!__evaluateFrameScripts (__totalFrames)) {
super.__enterFrame (deltaTime);
return;
}
//If there is a stop command, it should stay until the last frame
if(__playing)
__currentFrame = 1;
}
if (!__evaluateFrameScripts (nextFrame)) {
super.__enterFrame (deltaTime);
return;
}
} else {
__currentFrame = nextFrame;
}
}
...
I also found that the implementation of the frame action is to execute the script and then render. If I use the callback event, it may cause the render object to be unreachable. Again, do some of the following optimizations: Delay the callback event.
//回调事件延迟处理
private var _dispatchEvents:Array<Event> = [];
//是否在__enterFrame事件中进行回调处理,如果是,需要延迟
private var _isEnterFrameDispatch:Bool = false;
override public function dispatchEvent(e:Event):Bool{
if(_isEnterFrameDispatch)
{
_dispatchEvents.push(e);
return false;
}
else
return super.dispatchEvent(e);
}
/**
* 延迟调用
*/
private function enterFrameDispatchEvent():Void
{
_isEnterFrameDispatch = false;
if(_dispatchEvents.length > 0)
{
for(event in _dispatchEvents)
{
this.dispatchEvent(event);
}
_dispatchEvents = [];
}
}
public override function __enterFrame (deltaTime:Int):Void {
// if(deltaTime != 0)
// deltaTime = 120;
_isEnterFrameDispatch = true;
if (__symbol != null && __playing) {
var nextFrame = __getNextFrame (deltaTime);
if (__lastFrameScriptEval == nextFrame) {
enterFrameDispatchEvent();
super.__enterFrame (deltaTime);
return;
}
if (__frameScripts != null) {
if (nextFrame < __currentFrame) {
if (!__evaluateFrameScripts (__totalFrames)) {
enterFrameDispatchEvent();
super.__enterFrame (deltaTime);
return;
}
if(__playing)
__currentFrame = 1;
}
if (!__evaluateFrameScripts (nextFrame)) {
enterFrameDispatchEvent();
super.__enterFrame (deltaTime);
return;
}
} else {
__currentFrame = nextFrame;
}
}
if (__symbol != null && __currentFrame != __lastFrameUpdate) {
__updateFrameLabel ();
var currentInstancesByFrameObjectID = new Map<Int, FrameSymbolInstance> ();
var frame:Int;
var frameData:Frame;
var instance:FrameSymbolInstance;
// TODO: Handle updates only from previous frame?
for (i in 0...__currentFrame) {
frame = i + 1;
frameData = __symbol.frames[i];
if (frameData.objects == null) continue;
for (frameObject in frameData.objects) {
switch (frameObject.type) {
case CREATE:
instance = __activeInstancesByFrameObjectID.get (frameObject.id);
if (instance != null) {
currentInstancesByFrameObjectID.set (frameObject.id, instance);
__updateDisplayObject (instance.displayObject, frameObject, true);
}
case UPDATE:
instance = currentInstancesByFrameObjectID.get (frameObject.id);
if (instance != null && instance.displayObject != null) {
__updateDisplayObject (instance.displayObject, frameObject);
}
case DESTROY:
currentInstancesByFrameObjectID.remove (frameObject.id);
}
}
}
// TODO: Less garbage?
var currentInstances = new Array<FrameSymbolInstance> ();
var currentMasks = new Array<FrameSymbolInstance> ();
for (instance in currentInstancesByFrameObjectID) {
if (currentInstances.indexOf (instance) == -1) {
currentInstances.push (instance);
if (instance.clipDepth > 0) {
currentMasks.push (instance);
}
}
}
currentInstances.sort (__sortDepths);
var existingChild:DisplayObject;
var targetDepth:Int;
var targetChild:DisplayObject;
var child:DisplayObject;
var maskApplied:Bool;
for (i in 0...currentInstances.length) {
existingChild = __children[i];
instance = currentInstances[i];
targetDepth = instance.depth;
targetChild = instance.displayObject;
if (existingChild != targetChild) {
child = targetChild;
addChildAt (targetChild, i);
} else {
child = __children[i];
}
maskApplied = false;
for (mask in currentMasks) {
if (targetDepth > mask.depth && targetDepth <= mask.clipDepth) {
child.mask = mask.displayObject;
maskApplied = true;
break;
}
}
if (currentMasks.length > 0 && !maskApplied && child.mask != null) {
child.mask = null;
}
}
var child;
var i = currentInstances.length;
var length = __children.length;
while (i < length) {
child = __children[i];
// TODO: Faster method of determining if this was automatically added?
for (instance in __activeInstances) {
if (instance.displayObject == child) {
//set MovieClips back to initial state (autoplay)
if (Std.is(child, MovieClip))
{
var movie : MovieClip = cast child;
movie.gotoAndPlay(1);
}
removeChild (child);
i--;
length--;
}
}
i++;
}
__lastFrameUpdate = __currentFrame;
}
enterFrameDispatchEvent();
super.__enterFrame (deltaTime);
}
It seems that this scheme is not feasible. If there is a jump frame, it will lead to an infinite loop. I don’t know if there is a better way, let me get a way to render the script first.