Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

TexturePacker exporters for Codea (Easy sprite sheet import and use!)

edited November 2012 in General Posts: 580

I've created a couple of custom exporters for the marvelous TexturePacker (http://www.codeandweb.com/texturepacker) for Codea. You can find them here: https://github.com/apendley/TPCodea (please read the readme for exporter installation instructions and for some important details about generating Codea-friendly retina-ready sprite sheets and data).

Also, I've created a class (SpriteBatch) that makes it easy to batch render sprites using the data and sprite sheets generated from TexturePacker. It's basic right now, but I plan on adding more to it if I have time over the next few days. An example project including the class can be found here: https://github.com/apendley/TPCodeaExamples

Comments

  • Posts: 257

    Thanks a lot. It's very very interesting. Do you have a small example ?
    Here it's morning :)

  • edited November 2012 Posts: 580

    EDIT: updated original post with link to example project. Mods, you can delete this post if you want.

  • edited November 2012 Posts: 580

    Update: I've finished the SpriteBatch class for batch rendering sprites using exported sprite sheets from Codea. It's super simple to use. Once you've got your sprite sheet imported into your project, you can use it like so:

    function setup()
        -- assumes texture is in "Documents" sprite pack, though
        -- you can specify a different sprite pack name as an
        -- optional second parameter.
        batch = SpriteBatch(tp["SmallWorldSprites"])
    end
     
    function draw()
        background(0)
     
        -- submit a "Beam" sprite from the sprite sheet to the batch renderer.
        batch:sprite("Beam", WIDTH/2, HEIGHT/2)
     
        -- submit all sprites in batch to Codea's renderer
        batch:draw()
    end

    The SpriteBatch:sprite() interface is identical to Codea's sprite() function, with the exception that the first parameter specifies the name of a sprite in the sprite sheet, rather than a sprite in a sprite pack. SpriteBatch:sprite() will add your sprite to the batch using the current model matrix and sprite style settings, so you can even transform a sprite submitted with SpriteBatch:sprite() using translate(), rotate(), scale(), applyMatrix(), and you can change the color and mode using tint() and spriteMode(), just like Codea's sprite() function.

    I've updated the example projects with the latest version of SpriteBatch.

  • SimeonSimeon Admin Mod
    Posts: 4,889

    Very nice, @toadkick. I'm thinking perhaps something like this should be built into Codea in the future.

  • Posts: 502

    Nice! I've used TexturePacker in Moai, and reused the resulting exported file in Codea. But this is much nicer!

  • edited November 2012 Posts: 580

    .@Simeon: That would be great! I think I've optimized the SpriteBatch:sprite() function as much as I can, but a native version of SpriteBatch (perhaps with a better name :D ) would be much more optimal. Feel free to use the SpriteBatch class as a reference, the logic should pretty much be identical in Objective-C.

    .@tnlogy: Thanks! The Moai exporter was actually an inspiration, but there were several things about it that made it cumbersome and inefficient to use for Codea (like the fact that it stores the frames in an array instead of using key/value pairs, and the fact that I needed to write a function in Codea to process the UV coordinate data into a format that works with Codea's mesh() class). Initially I was planning on contacting Andreas Lowe to see if he could add Codea exporters to TexturePacker, until I realized that version 3 provides facilities to create your own custom exporters :)

    As a bonus, Andreas has informed me that he will include the Codea exporters into the next version of TexturePacker, so soon it will not be necessary to add the exporters manually :) There is a bug with version 3.0.1 of TexturePacker (the lastest version) where normalized UV coordinates are output incorrectly. Once that's fixed, I can modify the exporters to not have to calculate the normalized UV coordinates at run-time, and I imagine at that point the exporters will be in a final state. To that end, I will accept any feedback about the format of the exported data and make any changes that would be helpful.

    Another point of potential interest: I am thinking about creating a tile map editor project in Codea, with the ability to create tile maps that can be used by other Codea projects easily. I've got a stressful move to another state coming up, and I'm busy with my "real" job, but I hope to find time to start working on it soon.

  • edited November 2012 Posts: 580

    Some performance stats: Using Codea's sprite() function to render sprites, I was able to get around ~45 sprites displaying and animating using the tween library before performance started to degrade. By using SpriteBatch instead to do the same thing, I was able to get ~360 sprites displaying and animating before performance started to degrade below 60fps. That's an 8x as many sprites! If you aren't sold yet on the benefits of using mesh() (and by extension TexturePacker/SpriteBatch) to render your sprites, that might persuade you :)

  • edited November 2012 Posts: 580

    A small update:

    • renamed tpBatch to SpriteBatch

    • allow using individual sprites (e.g. batch = SpriteBatch("Small World:Church").
      This provides some of the benefits of the SpriteBatch class to "normal" sprites (e.g. you can render lots of the same sprite more cheaply).

    • modified the SpriteBatch:sprite() interface to allow specifying texture coordinates (based on a comment by @Simeon in this discussion: http://twolivesleft.com/Codea/Talk/discussion/comment/10690#Comment_10690).

    An example:

    -- load the sprite "Church" from the "SmallWorld" sprite pack
    batch = SpriteBatch("Small World:Church")
     
    -- draw only the bottom half of the "Church" sprite
    local w, h = batch:spriteSize("Church")
    batch:sprite("Church", WIDTH/2, HEIGHT/2, 0, 0, 1, 0.5, w, h/2)

    This enables some neat tricks, for example texture coordinate scrolling (I'll try to come up with an example soon).

  • Posts: 666

    Did the latest release of texturepacker ever release the Codea stuff? Their site doesn't mention it, and it was 3 updates ago.

  • edited January 2013 Posts: 580

    Oh dang, Andreas emailed me right before the holidays saying the he couldn't repro the issue I was having with the normalized coordinates, so I'm assuming he hasn't added the Codea exporters yet. I've been super busy with work so I haven't had a chance to look at this yet...when I get some time I'll try to narrow down the bug and see if he can reproduce it. If not, the exporters in their current state will still work, so I'll see if he can just add them as they are. In the meantime you'll need to add the exporters manually as per the instructions in the readme on the github repo for TPCodea.

  • @toadkick thanks for your brilliant class! I was able to replace my sprites in no time!
    There is only one problem: is there a way to use blendMode(ADDITIVE) with meshes?

  • edited January 2013 Posts: 580

    .@derhannes: Thank you!

    The answer to your question is yes, but it probably won't work with SpriteBatch in the way you expect. Blend mode does affect meshes, however a limitation of rendering batched sprites using meshes is that you cannot set the blend mode separately on the individual sprites within the mesh, only on the actual mesh itself. In other words, all sprites rendered in the same batch will have the same blend mode. Setting the blend mode before calling SpriteBatch:sprite() will not have the desired effect, because the sprites are not actually drawn until the mesh is drawn.

    If that limitation is not a problem for you, then what you can do is set the blend mode before calling SpriteBatch:draw().

    Here's a quick and dirty example:

    function setup()
        batch = SpriteBatch("Small World:Church")
    end
     
    function draw(dt)
        background(0)
     
        batch:sprite("Church", WIDTH/2, HEIGHT/2)
     
        -- 1) you can set the tint on individual batch sprites:
        tint(255, 255, 255, 128)
        batch:sprite("Church", WIDTH/2 + 40, HEIGHT/2)    
     
        -- 2) reset the opacity before drawing sprite batch
        tint(255)
     
        -- 3) set the blend mode on the sprite batch
        blendMode(ADDITIVE)
        batch:draw()
    end
  • SimeonSimeon Admin Mod
    Posts: 4,889

    Just clarifying the above: blendMode is a feature coming in 1.5.

  • @toadkick thanks for your quick answer!
    Unfortunately that is a problem, but I'll think of a workaround..

  • BriarfoxBriarfox Mod
    Posts: 1,542

    This is pretty interesting, any idea if texturepacker has hadded codea support yet? I couldnt find it. This would be so much more usful then the eaqually spaced spritesheets i'm using.

  • Posts: 580

    It's been awhile since I've contacted Andreas, but last I heard he was not able to reproduce the exporter bug I was running into. At any rate, you can still add the plugin with the workaround manually to TP and it will be available for use as an exporter in TP (I've been using it for some time now, it works great), just follow the link in the first post to din the instructions (it's actually not too bad).

  • BriarfoxBriarfox Mod
    Posts: 1,542

    Thanks @toadkick really cool. Just wish i could use texturepacker from my ipad :) I've been avoiding my pc for a long while.

  • Posts: 8

    Thanks @toadkick Its really great!! ... I faced a problem accidentally when I tried to paste your examples into Lua Jump example after running I can see all sprites are shifted the right side of the screen although the boundary box is in the correct position(i.e. the center), it seems for me its a problem with the translate action, Any hint?

  • Posts: 12

    Try removing the part of your draw where you tell the sprite to be in a certain place. If you use translate to set your sprite, you then need to tell your sprite to draw at (the now translated spot) at 0,0.

    like this

      translate(120,610)
      rotate(180)
      sprite("Cargo Bot:Command Grab", 0,0)
    
  • Posts: 8

    @HaroBlack thank you, mmm... The problem which I am wondering about is the position shifting in-between the BoundaryBox and the actual sprites, I expected a shift for poth of them!.
    Anyway I tried your suggestion but unfortunately nothing changed!

  • Posts: 580

    Sorry @aosama, just noticed your post. Can you post your code for me to look at? I've not seen this issue.

  • Posts: 8

    @toadkick. Thanks, Here is the code

    function draw()

    background(0)
    
    translate(WIDTH/2,HEIGHT/2) -- try to comment this line to see the difference
    
    local sprites = {
        "Base Large",
        "Beam",
        "Church",
        "Court",
        "Explosion"
    }
    
    local x = 0
    for i,spr in ipairs(sprites) do
        local w, h = batch:spriteSize(spr)
      batch:sprite(spr,0, 0)     
    end    
    batch:draw()
    

    end

  • edited April 2013 Posts: 580

    @aosama: Ah yes, I see the issue. Here's the fix:

    function draw()
    
    background(0)
    
    translate(WIDTH/2,HEIGHT/2) -- try to comment this line to see the difference
    
    local sprites = {
        "Base Large",
        "Beam",
        "Church",
        "Court",
        "Explosion"
    }
    
    local x = 0
    for i,spr in ipairs(sprites) do
        local w, h = batch:spriteSize(spr)
      batch:sprite(spr,0, 0)     
    end
    
    translate(0, 0)    
    batch:draw()
    end
    
    

    What's going on here is that whenever you call batch:sprite(), the 'sprite' is created with the current transform information (in this case, with a translation of WIDTH/2, HEIGHT/2). But, it doesn't actually get drawn until batch:draw() is called. Since your translation is still WIDTH/2, HEIGHT/2 at the time batch:draw() is called, your batch is also getting drawn with that translation, so your sprite is actually getting drawn at (WIDTH, HEIGHT). Does that make sense?

  • Posts: 8

    @toadkick : I thought that translate will affect all the following commands once time... Anyway I tried your fix..but it did not fix the problem !!

  • Posts: 580

    @aosama: ugh, sorry, that was a stupid mistake on my part. What I meant was:


    function draw() background(0) pushMatrix() translate(WIDTH/2,HEIGHT/2) -- try to comment this line to see the difference local sprites = { "Base Large", "Beam", "Church", "Court", "Explosion" } local x = 0 for i,spr in ipairs(sprites) do local w, h = batch:spriteSize(spr) batch:sprite(spr,0, 0) end popMatrix() batch:draw() end
  • Posts: 8

    @toadkick : Finally it works fine, but I have to learn more about translate cause It makes me little bit confused. Thanks

  • edited April 2013 Posts: 580

    @aosama: FWIW, you don't have to use translate() (or the view matrix at all) to position your sprites if you aren't building a scene graph (if you don't know what a scene graph is, you probably aren't building one, and you probably don't need to mess with the view matrix). You can just pass the x and y position to batch:sprite() (just like Codea's sprite())

    Like this:


    function draw() background(0) local sprites = { "Base Large", "Beam", "Church", "Court", "Explosion" } for i, spr in ipairs(sprites) do batch:sprite(spr, WIDTH/2, HEIGHT/2) end batch:draw() end
  • Posts: 8

    @toadkick : you are right, but as I told you this story started with Lua Jump example where it uses the translate feature.

  • Posts: 666

    Probably should move the batch table creator outside of draw()

Sign In or Register to comment.