This is the same as the player below, except it's illustrating a way to link multiple animations using cutaways. Normally you would need to account for each shape in a previous frame in the new frame as they are intended to 'animate'. That can be used for interesting effects, like the cat gif below that has words transition from Japanese to Meownese. But using this structure allows you to more traditionally link completely unrelated scenes so they will be played in a sequence, before returning to the main program state.
INSTRUCTIONS: Use Left/Right to change the selected animation, and 'X' to play the currently selected animation.
Here's a standalone vector player with some sample animations. The token count here is pretty high (Just under 3k ! :O) -- a version with less overhead is on the list for a future release :)
Vaca v1.4
After over a month of tooling around, I have completed a pretty decent Pong clone. See?:
...Wait, what?
Ohhh that's right. This is actually a vector animation creation application. Thaaat's why I named it that..
Here's a cart with that animation in it. Manual / instructions are in the code, but I'll reprint them at the bottom of this post:
Here's a couple sample animations I made to test things out in various states of development:
And here is another version of this cart that does /not/ have an animation stored so you can make your own things:
So! This thing still needs a little work, including a major change I'd like to make to how rect elements are done, and better compression for saved strings... But, I've also been working on it for long enough that I'd like to share it. If you find any crash bugs (even after all the ones I've fixed, you very well may!), please let me know!
In addition to bugfixes and some tweaks/additions, I'm planning to release some further write ups over the next few weeks that outline some of the concepts behind this little tool. A lot of this stuff was mostly new (or forgotten -- apologies to my highschool math teachers) for me, so there were a lot of '..oh!' and '...Aha!' moments as I tried to reason things out. If I got stuck, I would usually flip through an old math text.. and sometimes I'd find I hadn't been too far from the mark. ..Of course, there were other times I'd realize I had been pretty off in the weeds, but hey whatever -- it was a fun process :)
But yeah, the code in those carts isn't the most well written or well organized; partly due to the procedural nature of my knowledge, the need to work around token limitations, and partly well you know.. I'm kind of messy sometimes okay? But my hope is that using long-form essays will be more useful to people with questions about how this works. And along with those articles, I'll be giving some examples of how to use these animations as assets in games:
Here's the manual for Vaca!:
Vaca v1.4
by enargy [check comments]
Special thanks to:
- Gustave (inspiration! This wouldn't exist without his suggestion)
- meek_nate (soundboarding)
- Felice (#{nil} issue)
- P ("it makes triangles? thats uh.. great, dear..")
- All the great p8 twitter people
- and -YOU- the user
-
Left Click=set point(s)
- tri mode:
- --> 3 clicks --> triangle
- other modes:
- --> click+hold-->release ---> line, circle, rect
- tri mode:
-
Right Click=Change shape mode (Line, Circle, Tri, Rect)
- save icon: saves to file/clipboard
- To load, add loadfromstring("str") to the end of _init, where "str" is your saved string
** protip: hover over buttons to see what they do! ***
-
(keyboard controls)
- z=next object
- x=next point in current object
- Move point:
- UP/DOWN/LEFT/RIGHT=move point in current object
- Move all:
- UP/DOWN/LEFT/RIGHT=move all points in current object
- Move all super:
- UP/DOWN/LEFT/RIGHT=move all points for all objects
note
yeahhhh so i need to add scaling for lines.. and proper scaling that takes into account centers... tris already do that buuut... the rest obviously do not... yet.
- UP/DOWN/LEFT/RIGHT=move all points for all objects
- Scale:
- LEFT/RIGHT=scale shape
- Scale all:
- LEFT/RIGHT=scale all shapes of the selected type
- Scale all super:
more like super buggy amirite????
err.. wait for v2.0 -_-;- LEFT/RIGHT=scale all shapes
-
Rotate tri:
only works on triangles- LEFT/RIGHT=rotate counter/clockwise
- v1.4
- 20170804
- Release date!
- v1.1
- 20170726
- This should be (mostly) bug free and feature-full except:
- moveall_super needs work (centers from non-tris)
- line rotation/scaling
- saved strings can be further optimized by saving deltas..
If you have questions or want to support this project, I'm also on twitter as @enargy (the lexaloffle forums don't have notifications yet, so if you post here it's possible I won't see it)
Nice. I considered supporting a subset of flash, since we once did a decent flash player in an xbox game (this was before scaleform existed) and it really wasn't too bad. But then I came to my senses and played with more fun things. ;)
PS: I don't remember the nil issue but glad to help. :D
@Felice: ah for animations? Yeah animation/ vector art it's.. it's interesting. And a lot of fun.
Usually I like the logic/puzzle part of dev. And a weakness I've had is that I'll figure out the 'trick' to something, get bored, and then move on to something new before the first one is fully realized. There are 2 or 3 p8 games I'm at the 85% mark on completing for example. Here, I've really been pushing myself to polish things, add features, make it better. A lot of this was sort of figuring things out and then looking up trig references if I couldn't get something to work.
So even though I've mostly used it for silly gif responses on twitter, it also represents a level of dedication and follow through I want to work hard to maintain.
The nil issue was that thread where I was wondering what was up with the length operator being unreliable on sparse tables. Your explanation helped and I moved to saving 'deleted' shapes as -1 versus nils.
.. wait minute.. -1 uses 2 tokens doesn't it..
If so I can save a few dozen tokens by changing that to a single special character like $ can't I.. or just a 1 (checks are against -1 vs a table) so I'm saving on chars too.
See, you helped me again :)
Good point. In my testing pairs() was more expensive I think?
Another reason I didn't go that route is that the way the data is structured it's expecting a shape to always have the same offset each frame. And I wasn't sure about how deterministic the behavior of add() is after seeing how Len worked (would it always add to latest non nil offset + 1, find the first available... or just depend on harder to predict rules like len.)
If I made this now it would be structured differently. I'm going to standardize some things in the next version. (At first data types were more uniform and then that shifted as features were added, some things optimized, I learned more about what was needed and what wasn't etc..) I'll look at using nils and pairs() too. Maybe I can track id's some how and.. I don't know :p
COOL! Just found that you released this.
Looking forward to playing around with it! :D
Thanks a lot @enargy
Thanks @Liquidream
Hopefully it will be useful for you lorez game? The built-in player doesn't support nonlinear frame control flow, but the rail shooter game's implementation does. Some form of that will come out this week.. but all I do is add the animation as a property of an object and store its frame offset/counter. Then I store a state that the animation player uses to do things like delete the object after playing once (for explosions and effects), or to run a single frame after a trigger is called (for things like the levels.)
First bit of info:
An indexed for is actually slower than a pairs() for. The loop overhead is the same, but you still have to index the array inside the loop, for an extra cycle. With pairs() it's just directly iterating the underlying hash table, which means it doesn't need to hash the index, but order isn't guaranteed.
Here are my test results to demonstrate:
t={1,2,3} cyc code --- ------------------------------------- 14 for idx=1,#t do s+=t[idx] end 11 for k,v in pairs(t) do s+=v end 84 for v in all(t) do s+=v end <-- bonus measurement t={1,2,3,4} cyc code --- ------------------------------------- 17 for idx=1,#t do s+=t[idx] end 13 for k,v in pairs(t) do s+=v end 102 for v in all(t) do s+=v end <-- bonus measurement |
That's 3 cycles per iteration to get t[idx] using idx, 2 cycles to get it via pairs(), and 16(!) to get it with all(). I, uh... I don't understand all().
So anyway, yeah, try pairs(). :D
Next up:
The built-in add(t,v) always adds a new entry after the end, growing the length by one. Scanning for an empty slot could be prohibitively costly in large lists, so it makes sense that it would not do that.
For example, adding this to your code would basically be a no-op:
function add(t,v) t[#t+1]=v end |
You can confirm this behavior pretty easily:
> t={1,nil,3} > ?#t 3 > ?t[2] nil > add(t,2) > ?#t 4 > ?t[2] nil > ?t[4] 2 |
Note that del() does shrink the list (vs. setting the entry nil manually) and I can't vouch for how efficient that is on a large list.
@Felice: Awesome! Thank you for all of the info. I hadn't considered the overhead of the indexes inside the loop.
It sounds like I can use pairs then! I dont think call del in this thing.
Just remember it's not ordered, except on an unknown hashing algorithm, so you might not get the order you need (if you need one).
Mind you, I haven't tested much to see if an array-style table is always ordered anyway. I know if you start using random strings you will stop getting stuff in the order you added it, but it could be that array-style tables remain ordered on index, since the index could just be the hash value. It depends on the hashing algorithm and whatever the lua guys have done to make common stuff less expensive.
@Felice: well right now it's important that things align from one animation keyframe to the next since thats how we get data to... I think the word is interpolate but maybe it's 'tween?
Since pairs() gives key and value it should be ok unless I'm overlooking a potential issue with add() maybe... I had just been using the ordinal offset as the key.
Oh I guess if I set something to nil I just need to make sure that a new object won't take its offset when added unless it's explicitly replacing that object.
I'll mess around a bit. It sounds like just replacing some for loops with pair() is going to free up tokens I want for other things like string compression and trapezoids.
Edit: Felice! pairs is a complete game changer re: token counts and readability. Thanks for the tip -- I may have enough room to fit all the things I want :)
[Please log in to post a comment]