Generated classes from SWF

Hi.

I have a MovieClip exported for ActionScript as SWFWorld that contains a player character and some platforms.

I’m able to use the generate attribute in the project.xml so that I can access this SWFWorld in the Haxe code.

The player inside of this SWFWorld MovieClip is also set to be exported for ActionScript as SWFPlayer. In the Haxe code, I created a class called Player that extends SWFPlayer.

So I want to know how do I reference the player inside of the SWFWorld as Player and not as SWFPlayer because I want to add some properties and methods to the player, like vX or onKeyDown, for example.

I know I could add the player at runtime individually, but I think it defeats the purpose of having all the artwork setup in Adobe Animate.

Regards,
JC

Did you try casting your SWFPlayer as a Player?

var myPlayer = cast ( new SWFPlayer(), Player);
1 Like

Hi.

Thanks for answering.

I did try casting, but the difference is that I need to access the player that is already inside of the SWFWorld Movie Clip as Player and not as SWFPlayer.

This is my code in the Main class so far:
package;

import openfl.display.Sprite;
import openfl.events.Event;
import openfl.events.KeyboardEvent;
import openfl.Lib;

class Main extends Sprite
{
	private var startTime:Int = 0;
	private var world:SWFWorld;
	private var player:Player;

	public function new()
	{
		super();

		stage.frameRate = 60;

		world = new SWFWorld();
		addChild(world);

		player = cast(world.player, Player);
		trace(player);

		stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
		stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
		stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
	}

	public function onKeyDown(e:KeyboardEvent):Void
	{
		//player.onKeyDown(e);
	}

	public function onKeyUp(e:KeyboardEvent):Void
	{
		//player.onKeyUp(e);
	}

	public function onEnterFrame(e:Event):Void
	{
		var currentTime:Int = Lib.getTimer();
		var delta:Float = currentTime - startTime;

		startTime = currentTime;
		//player.onEnterFrame(e, delta);
	}
}

I get a type coercion error:
TypeError: Error #1034: Type Coercion failed: cannot convert [email protected] to Player.
at Main()
at DocumentClass()
at ApplicationMain$/start()
at MethodInfo-101()
at lime.app::_Event_Void_Void/dispatch()
at openfl.display::Preloader/display_onUnload()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at openfl.display::DefaultPreloader/onLoaded()
at openfl.display::DefaultPreloader/this_onComplete()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at openfl.display::Preloader/start()
at MethodInfo-100()
at lime.app::_Event_Void_Void/dispatch()
at lime.utils::Preloader/start()
at lime.utils::Preloader/updateProgress()
at lime.utils::Preloader/loadedAssetLibrary()
at MethodInfo-3474()
at lime.app::Promise/complete()
at MethodInfo-3765()

I know I can instantiate the player at runtime, but I would really like to preserve the SWF layout so I don’t have to recreate all menus and stages again using code.

Can you share your class for Player? It seems there is something that is preventing it from unifying with SWFPlayer. Are you actually extending the class which gets generated from the SWF? Can you share that too?

1 Like

Sure! Here it is:

package;

import openfl.events.Event;
import openfl.events.KeyboardEvent;

class Player extends SWFPlayer
{
	public var friction:Float = 0.85;
	public var keyForce:Int = 50;
	public var vX:Float = 0;
	public var minVX:Float = 20;
	public var leftPressed:Bool = false;
	public var rightPressed:Bool = false;

	public function new()
    {
		super();
        trace("new player");
	}

	public function onKeyDown(e:KeyboardEvent):Void
	{
		if (e.keyCode == 65)
			leftPressed = true;

		if (e.keyCode == 68)
			rightPressed = true;
	}

	public function onKeyUp(e:KeyboardEvent):Void
	{
		if (e.keyCode == 65)
			leftPressed = false;

		if (e.keyCode == 68)
			rightPressed = false;
	}

	public function onEnterFrame(e:Event, delta:Float = 1):Void
	{
		if (leftPressed)
			vX -= keyForce;
		else if (rightPressed)
			vX += keyForce;

		vX *= friction;
		x += vX * delta * 0.001;

		if (Math.abs(vX) > 0 && Math.abs(vX) < minVX)
			vX = 0;
	}
}

And my Library is like this:

What about the SWFPlayer class that gets generated? Is it somewhere in your bin folder after compile? I’m guessing the compiler isn’t complaining that it can’t find that class. At this point I’m not sure what to tell you.

Maybe check that your SWFWorld AS3 class actually has a property/variable for “player” and you’re not just relying on an instance on stage to be properly typed.

The class SWFPlayer and the world.player property exist because when I run:
trace(world.player);

I get [object SWFPlayer].

Is there a place I can download some examples of integration between OpenFL and SWF files and/or some complete documentation on the subject?

Thanks.

You can’t cast SWFPlayer to Player because your SWFPlayer is not a Player object.

I’m not sure if you can directly link your player to your haxe class Player in your FLA instead of SWFPlayer with openFl but you can try.

Otherwise, see Player like a controller and SWFPlayer like a view and inject it somehow in your code.

//in your main
world = new SWFWorld();
addChild(world);
playerview = world.player;
player = new Player(playerview);
//in your player
class Player extends Sprite
{
	public var friction:Float = 0.85;
	public var keyForce:Int = 50;
	public var vX:Float = 0;
	public var minVX:Float = 20;
	public var leftPressed:Bool = false;
	public var rightPressed:Bool = false;
    var view:SWFPlayer;

	public function new(view:SWFPlayer)
    {
        this.view = view;
		super();
        
	}
}
2 Likes

Another pathway which may give you some more control is to run openfl process SWFWorld.swf and then use the .bundle file that gets output. It is a directory, and contains the .hx class that gets generated. https://www.openfl.org/learn/haxelib/docs/tools/ So you could potentially import and extend that.

FWIW, here is my code I use to load a bundle file:

var swflib="assets/mySWF.bundle";
//AssetLibrary.loadFromFile needs a manifest file or bundle, not a swf file
//
var p = pcp.getBasePath()+swflib;
AssetLibrary.loadFromFile (swflib,p).onComplete( function (library:AssetLibrary) {
	Assets.registerLibrary (libName, library);
	trace ("SWF library loaded");
	facade.registerProxy(new AssetLibraryProxy(library,libName));
	commandComplete(); 
});
1 Like

It’s a great solution. This is what a generally do when I want to use OOP in the HTML5 canvas document of Animate CC. I’ll stick with this approach by now while I don’t find an ideal solution.

Thanks again for your help. I’ll explore this path as well.

1 Like

Wow! I think I got it! After reading @joshtynjala’s suggestion on the Discord community, I created a dummy SWFPlayer.as class and set it as the base class. I then set the Class field as Player and now it seems it works the way I was expecting! Thanks a lot, everybody!

1 Like

Congrats! @joshtynjala wins the day again. :slight_smile:

1 Like