Game Development Community

Help needed - Spriter Implementation

by Doc308 · in Torque 2D Beginner · 02/22/2013 (5:13 pm) · 19 replies

Ok, I've blown up my head trying to get it to work.. so I'm asking for help.

I believe I have commited and pushed the appropriate files to my GitHub fork:
github.com/Doc308/Torque2D/tree/master/modules/SpriterToy

First, let me state the logistics:
I am loading up an SCML file (that which is created from Spriter) and reading it though SimXML, I have all the necessary tags read and what not... The problem I am facing is in setting up my Sprites.
I have to finish up the SpriterEntity.cs file (as it still houses a lot of Legacy commands from the original), but what I'm looking to accomplish is to simply figure out how to set a Sprite based upon the information gathered to this point.

It's a bit confusing, but all the hard work lies in SpriterData.cs
around line 160-200, I have the ImageAsset setup, which is returned back in main.cs

I have tried multiple avenues, and my brain is simply racked and can't figure out why/what I might have did wrong.

I will be in IRC for a while tonight to comment if anyone chooses to help.

Many thanks, and hopefully can figure out what's going on, so I can get get this working properly.

#1
02/22/2013 (6:02 pm)
I just quickly glanced at your repo, but to me it looks like your sprite positioning is way off.

is %object.x/y the stored local positioning in your spriter file? You need to transform that into scene space.

You are then offsetting that positioning with half the height/width of your raw image size (which is not in scene space).

And of course lastly, make sure your camera is looking at wherever your sprites end up.

You should consider using a CompositeSprite with layout set to none, and no stride set. You can then write your own position space translation and offset it by the CompositeSprite position to build a batch sprite container.

#2
02/22/2013 (6:19 pm)
I haven't even set a Sprite position. The problem I'm having.. is well, complex. Nothing will show up on launch of the repo except some console spam. What I'm trying to do is set the image stored from the Asset Declaration to a Sprite, I'll worry about size and what not after the fact, but first and foremost I need to actually get the sprite to accept the Image Asset. Every attempt I have made so far has produced errors, unable to find asset, etc, etc..
#3
02/22/2013 (6:27 pm)
// Query the Database for our asset
               %query = new AssetQuery();
               %count = AssetDatabase.findAssetName(%query, fileBase(%path));
               %newAsset = %query.getAsset(0);
               %obj = AssetDatabase.acquireAsset(%newAsset);
               %asset.size = %obj.getImageSize();
               echo("Size: " @ %obj.getImageSize());
               AssetDatabase.releaseAsset(%newAsset);
               
               // Store the full information into an array for access
               %this.image[%folderId, %fileObject.id] = %asset;

your asset id is stored at %newAsset. Change it to this:
%this.image[%folderId, %fileObject.id] = %newAsset


I'm really not sure why you are trying to dynamically create an image asset taml to disk, and then load it back in via taml.

later you have this:
// Look up the image
            %map = %this.data.imageMap[%obj.folder, %obj.file]; // Legacy format, should be Image
            
            // Get the bitmap size (LEGACY CALLS!! Verify)
            %bitmapSize = %map.getSrcBitmapSize();
            echo("bitmapSize =" SPC %bitmapSize);
            %bitmapCenter = (getWord(%bitmapSize, 0) * 0.5) SPC (getWord(%bitmapSize, 1) * 0.5);
            echo("bitmapCenter =" SPC %bitmapCenter);
            %pivotOffset = ((getWord(%bitmapSize, 0) * %obj.pivot_x) - getWord(%bitmapCenter, 0)) SPC (getWord(%bitmapSize, 1) * %obj.pivot_y - getWord(%bitmapCenter, 1));
            echo("pivotOffset =" SPC %pivotOffset);

which will need to be changed. imageMap will now store an AssetID, which if you need to get image size info, you'll need to acquire/release to get the ImageAsset instance.

But, what's important is that a Sprite.Image property wants an AssetID, not an ImageAsset instance.


#4
02/22/2013 (6:47 pm)
I can't use %newAsset, as once I release the asset it's no longer available to call upon.

As for the SpriterEntity.cs file, it's not loaded or finalized for MiT yet, and I have comments indicating Legacy format stuff.

What's happening though is that the Taml write is writing out the new Image Asset based off of the images stored in the SCML database (to make it universally capable for anyone using any SCML).

I believe that somehow the reference is being lost on my TamlWrite, as it gets stored to SpriterToy:torso_0 (etc, etc..), and I believe it is not seeign it, due to the depth of file structure.. but I may be wrong.

%asset is the ImageAsset itself, which would work... however, it apparently doesn't. And Sprite.Image can accept under normal circumstance the ImageAsset.
Ex: %background.setImage( "AquariumToy:background" );

I got the reference correct, but I think the reference structure is hiccuping/unreferenced somehow.
#5
02/22/2013 (7:08 pm)
You should be setting up your image assets ahead of time with your module. You can query for an asset by loose file name (image name), which you can use to look up the asset based on the spriter information.

the output from acquireAsset() is an Asset object, and not an assetId. Sprite.Image requires an assetId, not an Asset object.

Either query for assetIds or build up the assetId string manually.
#6
02/22/2013 (7:39 pm)
I'm not entirely clear on how to obtain loose assets.

I would save some hassle by simply Declaring the assets ahead of time, but like I stated, I'm trying to make a universal system. Maybe it's just easier to tell people to write out the .taml files for all the images, and make sure that they are declared initially. Thus saving the "hassle" of loading them up dynamically, as I have done.

I was thinking in terms of a designer perspective: All they want to do is create their SCML data, and copy it (with reference images) to the assets folder, and have it be recognized.

I think my primary issue would be resolved by Declared Assets, however I was trying to do it in a way to skip the manual taml creation step.

I thank you for the input, I thought I was close to correct, but once I got to the data and tried to assign a Sprite to it, I started having issues. Whether that be due to needing a new query (which I tried, and it failed to load what "should be" right, and complained on trying to read it over again using TamlRead.)

I guess for now I will create the .taml's manually, and just state that as a setup step. Hopefully I can get it to work that way.
#7
02/22/2013 (7:46 pm)
Every game system/engine has it's own asset pipeline. Anyone trying to use 3rd party assets into that system needs to manipulate it the pipeline.

Most will convert the 3rd party asset data into a format that can be consumed by that engine pipeline directly. For T2D that would mean converting any image references to assetIds, etc.
#8
02/22/2013 (8:33 pm)
Thank you William, I had orginally thought to make the asset.taml's, but I thought it would be a nice gift to dynamically create them. All it did was give me a headache by trying to do something... that I probably shouldn't have been doing.

In the end, I learned a lot more about the AssetManager, queries, and Taml too.. So it wasn't a total loss. I have manually created the .asset.taml files, and I am now able to create Sprites based off of my new method.

Now I can finish up SpriterEntity.cs, and hopefully can get this finished over the weekend!
#9
02/23/2013 (11:29 am)
I wanted to highlight that it is actually possible to generate assets dynamically and use them without the restriction of having them loaded via an asset definition. Whether this helps at this point or not I don't know but I thought it'd still worth mentioning.

Anyhow, if you were to generate a new asset in memory like this:
%asset = new ImageAsset()
{
   ImageFile="/some/where/on/disk/foo.png";
};
... you can ask for this to be a private asset like this:
AssetDatabase.addPrivateAsset( %asset );
When you do this, you pass in an asset object and the asset system generates a temporary asset Id you can use. You can get this with:
%assetId = %asset.getAssetId();
... but also it's returned from the "addPrivateAsset()" call for convenience.

You should not persist references to this asset Id as it's completely volatile and obviously there is not an asset definition for the next session and it's not guaranteed to tbe the same. You can however use this on anything that takes an asset Id for an ImageAsset like sprites etc but just don't persist them.

If you wanted to make this asset permanent then you can simply assign an asset name like so:
%asset = new ImageAsset
{
   AssetName="FooThing";
   ImageFile="/some/where/on/disk/foo.png";
};
... then you could persist it to an asset definition...
TamlWrite( %asset, "foo.asset.taml" );
You can then immediately register it against a specific module definition with:
AssetDatabase.addSingleDeclaredAsset( %module, "foo.asset.taml" );
... or alternately it'll just load as expected with the module from which it resides.

You can find a specific module definition (passed in to the function above) by name with the module system like so:
%module = ModuleDatabase.findModule( "SomeModule", %version );
Not sure if this helps but maybe it's useful.
#10
02/25/2013 (6:51 am)
I believed it was possible, but I encountered a slew of errors in my attempts, either due to a bug, or just me doing something incorrectly.
I probably should have documented out more my issues as they came along, but I found ways around things, and just kept moving forward.
I tried PrivateAssets, but wound up having issues finding them in AssetManager (to access the image size), perhaps I didn't search correctly. I did do the permanent step outline, but the reference failed somehow. I'm not sure if it has to do with directory structure referencing or just a quirk.
Here's what my error was on that: I created a structure that produced something like: SpriterToy:head_0
Which was actually in a folder: SpriterToy/1/assets/images/mon_head/head_0.png
Even though I was able to declare the asset properly, and query out the information for the size, it couldn't find it later on.

My general belief for a better ease of use, would be to do all of my dynamic creation prior to module assignment. That way everything is pre-defined through taml's (which would be created prior to module definition) then read as declared assets.
I'm still working on the entity portion of the code, but once I wrap up a working version, I'd be tempted to go back through and get it working dynamically. It's not a huge step, but I think flushing out the process could be helpful (especially for editors, as it would be the same type of process of reading Assets and defining them for use).
#11
02/25/2013 (6:59 am)
Well be aware that dynamic asset generation is supported and works pretty solid, it was what 3SS was doing as it had editors. Not only that but you can add, remove, configure, rename assets live without issue. All the support is there.

The asset documentation does a deep dive on this stuff.

What I described above works and it's pretty simple. It just sounds like you were perhaps missing some steps or need a particular thing explaining in a clearer way.

You don't use private assets if you intend for them to be permanent as private assets are supposed to be volatile and in-memory only without an asset definition.

Generating a permanent asset couldn't be easier. You just create the asset in script say "new ImageAsset()", give it an asset name, set its fields and save it as an asset definition inside a location of the module you are searching so that next time you load-up the module it'll be found. If you already have the module loaded then you can load it up immediately with the "AssetDatabase.addSingleDeclaredAsset()".

I'd be happy to answer direct questions on it.

#12
03/15/2013 (9:34 am)
Well.. Once again, I'm going to ask for help. I've updated my code base for my git hub module for SpriterToy. github.com/Doc308/Torque2D My module being in modules/SpriterToy...
The problem I am now facing is.. well.. The sprites are not showing up. Everything I have is coded correctly, and in fact if I go to console and use the generate information for a global variable named Sprite it works just as I have it coded. For whatever reason, and I am truly at a loss as to why.. The sprites are not being added/not showing up, or something else is happening that I can't explain.

The bulk of the work is done is SpriterData.cs to generate the information, however the rendering portion is within SpriterEntity.cs specifically around lines 40-100. I have skipped over sending the Sim data holding the sprites and tried to just add them to the scene before it leaves the create function.. but it fails. And as soon as I enter the program I "lose" my newly generated Sprites, it creates the id's, however none of the data persists. I tried generating globals to diagnose the problem, and they returned no value (other than having an id created).

Any additional help would be greatly appreciated. I just got back from a vacation of sorts, and hoped my head would clear up and figure out the problem.. but it still persists.

Thanks :)
#13
03/15/2013 (9:39 am)
@Doc308 - You should look at our newest toy in the development branch, found in the modules/Experiments/WaveCompositeToy directory. This was an experimental module Melv set up to prep the engine for a Spine implementation. The same concept should be used to drive a Spriter implementation. Essentially, I think two main things should happen:

1. Create a Spriter asset type
2. Sub-class CompositeSprite into something like SpriterComposite

Then follow the example in engine/source/2d/experimental/composites/WaveComposite.h/.cc
#14
03/15/2013 (9:56 am)
Thanks for the pointer Mich!
I'll start looking into it. I figured a new Asset Type would eventually be the way to go, and putting into the engine first would be preferable. I wanted to make sure the "test bed" worked first. But in the end, the users need a way to simplify their usage, and really shouldn't have to do excessive steps. Back to the drawing board so to speak.
Spriter is releasing a beta build in a week or so, that should mostly finalize up any changes to their format (tho it is few for the output side), but I will continue to try and make this work.
#15
03/15/2013 (1:02 pm)
Quote:But in the end, the users need a way to simplify their usage, and really shouldn't have to do excessive steps.
I agree but the "users" also need to read the comprehensive documentation, it's all there.
%path = filePath(%this.file) @ "/" @ %fileObject.name;
            if(isFile(%path))
            {      
               %query = new AssetQuery();
               %count = AssetDatabase.findAssetName(%query, fileBase(%path));
               %newAsset = %query.getAsset(0);
               %obj = AssetDatabase.acquireAsset(%newAsset);
               
               // Store Asset id for access
               %this.assetName[%folderId, %fileObject.id] = %newAsset;
               %size = %obj.getImageSize();
               AssetDatabase.releaseAsset(%newAsset);
               
               // Store the source size into an array for access & name for reference
               %this.imageSize[%folderId, %fileObject.id] = %size;
            }
Do you somehow believe that the asset manager just knows about raw images? This code certainly seems to indicate that or did I miss a step?
%count = AssetDatabase.findAssetName(%query, fileBase(%path));
What is this line supposed to do?

I cannot find in your code anything that generates assets. Unless you've omitted the code it's clear you've either not read or have not understood the documentation.

Let's not forget the time I spent giving you a quick overview.

If you think my comments are harsh, I would argue they are simply being honest.
#16
03/15/2013 (1:46 pm)
Okay so I've looked at your code and you need to do the following...

Remove this code as it's nonsense...
%count = AssetDatabase.findAssetName(%query, fileBase(%path));  
%newAsset = %query.getAsset(0);  
%obj = AssetDatabase.acquireAsset(%newAsset);  
                 
// Store Asset id for access  
%this.assetName[%folderId, %fileObject.id] = %newAsset;  
%size = %obj.getImageSize();  
AssetDatabase.releaseAsset(%newAsset);  
                 
// Store the source size into an array for access & name for reference  
%this.imageSize[%folderId, %fileObject.id] = %size;
... and replace it with this...
// Generate an asset.
%obj = new ImageAsset();
%obj.ImageFile =  %path;
                
// Add it as a private asset.
%newAsset = AssetDatabase.addPrivateAsset( %obj );
                    
// Store Asset id for access
%this.assetName[%folderId, %fileObject.id] = %newAsset;
%size = %obj.getImageSize();
               
// Store the source size into an array for access & name for reference
%this.imageSize[%folderId, %fileObject.id] = %size;
This fixes generating private assets.

You next problem is that you've put all your code that calls this in the "function SpriterToy::create( %this )" method then you call "function SpriterToy::reset( %this )" which does this:
// Clear the scene.
SandboxScene.clear();
... obviously clearing all your hard-earned results.

Simply move your code after that line out of the "create" method like so:
function SpriterToy::reset( %this )
{
    // Clear the scene.
    SandboxScene.clear();
    
    //Load in the SCML file(s)
    %dir = getCurrentDirectory(); // Limit search to program directory hub
    %file = findFirstFile(%dir @ "/*.SCML");
    
    if(isFile(%file))
      %Spriter = Spriter::create();
      
    %SpriterData = %Spriter.load(%file);
    
    $SpriterEntity = %Spriter.createEntity(0);

    SpriterEntity::attachToScene($SpriterEntity);    
}

This gives me the following image which shows you've got your Y-Axis inverted somehow:
static.garagegames.com/static/upload/emp-5416/Spriter1.png
#17
03/15/2013 (3:05 pm)
Thanks Melv! My god.. I knew I was doing something silly!
I had forgotten about the reset completely.
In regards to your comments/question.. Firstly, no I do not find it harsh in any way at all, I've been tripping over my heels figuring this out.
I'm not accessing the raw images, instead I chose to manually create the .taml ahead of time, and the initial load of the module finds all of my .taml & associated images, so I skipped over dynamic creation for now until I got a firmer grip of things.
As for %count = ... (I probably was using it for checking, and forgot to omit after I no longer needed the check)

As far as the y-axis invert, that's a known problem meaning you have to do adjustments with the images pre-load, and may indeed have changed from Legacy to MIT somehow, but I can get that fixed now that I can see the actual results!

I understand the mechanics of the Private Asset system, I had problems with it initially, but I'm pretty much positive I was using it incorrectly. I'm thinking that Private Assets wouldn't be the "best" choice for dynamic creation tho. As I believe you have stated yourself, they are a 1-shot activation only, and not meant to be referenced later.

Script wise, the best way I believe to dynamically create would be pre-module load. As I discovered while within the module it was "difficult" to register the assets (by using AddSingleDeclaredAsset).. but again I may have been doing things wrong.

Thank you for pointing out my mistake Melv! I was driving myself bonkers, because I had all the pieces correct... Ah well, forgot to check the source of it all. Do you have any thoughts with regard to dynamic asset creation? In the end, I believe as Mich has stated, and I tend to agree with, the better method would be to create the Spriter as an asset itself. Which would mean to put the SCML reading into the engine, and then have it create the asset information based on that. Not too challenging, but I wanted to work out the bugs before I proceeded, and usually I find it easier to debug my scripts than my source code. (I think I'm actually more Versed in Torque script than I am in C++).
#18
03/15/2013 (3:13 pm)
Fixed the invert y, and just have some positional problems, but at least it's closer, will have to look a bit closer as to why the hands seem to be offset from normal position.
Edit: Fixed positional problems. Error was using a negative angle instead of positive.

It now renders correctly, the next step is hooking in animations. Will do this on a script level first, then transpose to make this a new asset.
#19
07/02/2013 (6:13 am)
Can you provide an updated status on your branch Doc308? I'd be interested in forking and playing around with your latest.

Cheers!