Caution
This posts acts also as a kind of documentation for the tool, its usage and the integration of the data. It's not final and might probably change in the future, to improve the writing style, fix mistakes or add more explanations. Please do report any feedback you desire so I can improve the documentation.
Anim Editor
Hello! From starting a project, I ended up going on a tangent for weeks and had been making a frame-based animation editor for the last few weeks with an intent of making my own internal mini animation library to make sprite animations as easy as drawing -or at least, for me-.
Changelog
0.0
- Initial version
0.1
Additions
- Added a right-click menu on animations with delete and duplicate options.
- Added ability to cycle between frames of the current animation by pressing left and right.
Changes
- TAE will sort alphabetically the animations in the editor.
- Changed BBS mode detection and added some failsafes to make it work.
Fixes
- Fixed looping checkbox not updated on animation change
- Fixed handling of GFX files. Those shouldn't change the reported current file anymore, which caused saving issues when using TAE as a dev editor like Picotron's.
- Prevents animation info from staying visible after loading a file. Prevents possible crash when fetching an animation's data when no animation is selected after loading.
- Fixed loss of ability to use space to play the animation after activating a rename field.
Using the tool
The animation editor is trying to follow the philosophy of Picotron's builtin editors. While it can't enjoy the same integration than the tools provided with the OS (like not having its own file open intent), it'll still aiming to feel at home when next to the other tool. Thus it's working at its best when opened while a cart is mounted/loaded to work on the cart's files.
The editor is split in three parts : the view, the timeline and the sidebar, each of which is going to have its own section. There's also going to be one for using the data generated by the animation editor.
The sidebar
The sidebar has buttons to open or save an animation, save as another file, replace the currently loaded GFX file, a button to create animations and undo/redo actions. You can right click the open button to open up a recent file list instead of Picotron's open dialog for a faster access.
Note that saving and opening are disabled in the BBS because there's no persistence nor demo files. This is planned for when I'll the energy to.
Then is presented to you the animation list. Once you created one or more animations, they'll be listed there. Click on one of them to select it and double click an animation to rename it. The X button allows you to delete animations. Don't worry, deleting an animation is undoable.
Following down is the sprite selector. It should work like the GFX editor except that you have an extra button to reload the GFX if you edited it externally. You can click & drag a sprite from the grid to drop it on the view to add it on the current frame in the current animation.
Note that the reload button is going to go away as soon as I'll replicate the map editor's automatic GFX reload mechanism. Another planned "when in the mood for" feature.
The timeline
Once you create and selected an animation, you'll see there its frames in the bottom bar and two buttons crossing over its border. The first button will create more frames at the end of the animation and the second button toggle playing the animation, this is also doable by pressing space.
Click on a frame to select it. Drag it to move it in the timeline. More options are hidden a right-click on a frame, like copy & paste or duplicate the frame. The small circle on the top right corner will delete the frame. Again, it's one undo away from you.
Note that most actions are disabled during playback, for your convenience (and to avoid a plethora of bugs). The grid will disappear and you'll be pretty much limited to change the playback speed (left editable for your convenience) and pausing the playback.
The scene view
Finally, the rest of the owl: the scene view. The scene view will display the current animation's current frame by overlaying the sprites from first to last inserted. Drag a sprite from the sprite selector to the view to add it to the frame. Once dropped, you can continue interacting with them by dragging them to reposition them or right-click for more options, like applying the currently selected sprite on the selected sprite. You can drag the view by click and dragging the middle mouse button to pan in the scene.
Note that the two blue and green lines are the main axises of the animations and the point where they meet will be the origin of the animation. You might want to use that point as a reference when integrating your animations, the latter being the main topic of the next section. Nice segue, eh?
Using the animation data
Now that you made your animations, you might want to use them in your game or project, right? This is the section that will explain the inner details to help you getting to it.
Like any POD file, an .anim
file is just a serialized Lua table. You can introspect the .anim
files by opening them with podtree
, that's always a good trick to keep around in case you want to figure something or edit them.
Animation structure
An animation file (.anim
), once loaded with fetch
or unpod
, contains two main elements at its root: a reference to the GFX file used during the creation of the file and a table named anims
.
anims
contains your animations, indexed by the name you put in the editor. So my_anim
will be accessible by getting my_loaded_file.anims["my_anim"]
or my_loaded_file.anims.my_anim
; the former syntax allows for spaces in the name.
The GFX reference is used by the editor to determine which GFX file to load when loading the .anim
, but you can also use it to identify yourself what to load, for situations like having a specific GFX file for a specific animations or anything, really, it's up to you.
Animations
An animation contains a list of frames, a tick
member and a loop
flag.
ticks
: The system currently being based on rendering frames (or game logic ticks) as a measure of time, that member indicates how many ticks should be spent between two frames - so, in other words, a bit like the speed of the animation. Think of SFX'speed
loop
: This value is currently not used in the editor but you can use it in your code to determine if your animation should stop or not
Each frame contains a list of sprites, which each stores an ID mapped to the loaded GFX file's sprite list(so like spr
does too) and a position offset (relative to center of the scene in the editor). Those sprites should be rendered from first to last in the array to reflect what you'll see in the editor
Sample code
This is not fully tested, I just ripped off my project and tried to remove what was speicfic to it, but the general idea is there.
local player_anims = fetch "anim/player.anim" player = { ... anims = player_anims.anims } function player:set_anim(anim) self.curanim = anim local a=self.anims[self.curanim] self.animticks = a.ticks self.curframe = 1 end function player:update_animation() self.animtick-=1 if self.animtick<=0 then self.curframe+=1 local a=self.anims[self.curanim] self.animtick=a.ticks--reset timer if self.curframe>#a.frames then if a.loop then self.curframe=1--loop else -- Here I had something else in my code to transition into another animation if needed. -- Another element I'll probably add in the editor when I'll feel the need for. self.curframe = #a.frames end end end end function player:draw_animation() local a=self.anims[self.curanim] local frame=a.frames[self.curframe] -- Here, the animation's origin will be placed on (cx,cy), so the center of the player object. -- That's one way to of doing it, you could also use the middle point on the bottom, a corner, etc. local cx, cy = self.x-(self.w/2), self.y-(self.h/2) local flp_x = self.flipx and -1 or 1 for sprite in all(frame) do spr(sprite.gfx_index, cx + (sprite.x * flp_x), cy + sprite.y, self.flipx, false) end end |
About the tool's future
I'm probably going to plug more features as I'll need them in the future, like having a timeline for hitboxes or triggers. I'll probably go back to this tool only when I'll really feel the need for it.
Also, I'd like to be honest and say in advance I don't really plan on making the most versatile tool ever, but I'd like to make it a tool one could remix to their own needs. I made this small tool when building for another project in mind (or two, maybe???) and I'd not want it to take most of my time. I hope you'll understand.
That said, I'll also add the task of trying to improve the source code to make it more open for customization in the "maybe later" task list.
Resources used
- Zep's GUI lib and wrangler utility (forked the latter into a custom version). I also borrowed his save icon I recolorized. I hope you don't mind. :°
- Surt's take on Kenney's Platformer Kit. Licence: CC0
I moved the cartridge to the release section, not because it's worthy of a 1.0 moniker but more because it's unlikely to change until I get needs that can be solved by this tool.
Sorry for the noise on the BBS.
[Please log in to post a comment]