|
Smerik
Level 1
|
|
« Reply #1 on: October 25, 2020, 11:57:24 PM » |
|
Undo Button
In this post I'm going to explain how we've solved a simple yet highly underrated feature of any editor, the undo button!.
The very first feedback we received on our game was the fact that it was lacking a "simple" undo button. A vital feature to any editor out there.
But technically it's really not that simple, and I'll explain a bit why. But before that let's go a little bit into the internals of Jolly World.
Jolly World serializes the whole world as an JSON object. Each independent object in the world is serialized through a serializer that turns that object into an array of properties, e.g.: [6,2347.101869683881,1015.5543600150933,0,"","",2,"#999999","#000",1,null,[{"x":-4992.11140782106,"y":396.085418860877},{"x":-4992.11140782106,"y":-396.085418860877},{"x":4992.11140782106,"y":-396.085418860877},{"x":4992.11140782106,"y":396.085418860877}],null,null,null,null,"Grass.jpg",1,0,0,0].
The order in the JSON is the actual sorting order of the rendering engine, so objects that come first are rendered on a lower layer as new objects.
Whenever you click the screen the engine tries to find the most logical sprite you tried to click in the game and sees if it is attached to any higher level object / group or prefab and makes the full selection. Then when you move the object 10 pixels to the right, an action is fired with the current selection and it executes the desired action of moving the object 10 pixels.
The very first attempt of making an Undo is simply inverting the action and applying it again, this was very simple to make. Just store a list of all the actions executed and simply undoing inverts that action.
However very soon the engine became to complex for this, to give an example: Let's say you have 10 different objects on 10 different layers, all with many different objects in between them. And you select all those 10 objects and decide to group them. My code executes the action group and combines all the objects on a single layer. Now to undo that we simply have to ungroup them right? Well we lost a lot of information, because we don't know any more on which layers all those objects were placed. Simply ungrouping them won't do, we also have to position them in the right layer. This becomes even more of a nightmare when all the objects also have triggers attached to them with multiple actions that are removed on grouping.
Now we could obviously make the Undo script smarter and also store more info with each type of action. But that approach is not very scalable, because then for every new feature we make we would have to go over all of the undo code and see if everything works as expected.
Can we think of a better way of solving this? The key was in the serialization of the world. We have a very fast serializer and we can build the world from a relatively small JSON object. So now instead of storing each action itself, we store the full world json of the complete world at the current state. We capped the undos to at max 50, this result in a maximum memory consumption of roughly 250MB, which is fine given that this game has a small memory footprint by itself. The added benefit now is that any new feature we build that can be serialized is also automatically "undoable". Initially I also had code in there that diffed the current world json with the previous world json and would just store the delta between them, however I found that with bigger worlds this process would become CPU intensive and was not worth the saved memory consumption.
Anyways I hope you found this interesting, I will think about a next post, if there are requests please do let me know!
|
|
|
Logged
|
|
|
|
Smerik
Level 1
|
|
« Reply #2 on: October 29, 2020, 12:38:47 AM » |
|
Spikes and SpearsIt took me quite a long time to figure out how to do spikes in the game. Even to the point where I sparred with Jim Bonacci from Happy Wheels to ask him how he did it. He truly is an amazing person. He has been my motivation to push through these years of working on this game. Happy Wheels has always been one of my favorite games, and growing up on Newgrounds where I also placed all my games https://erik.newgrounds.com I really looked up to him. Anyways now back to the technical part, so like shared in the conversation they are done with Prismatic joints. quoting iforce2d: The prismatic joint is probably more commonly known as a slider joint. The two joined bodies have their rotation held fixed relative to each other, and they can only move along a specified axis That's exactly what we want right? We want the body attached to the spike only move along the axis of the spike. So in terms of mock code this is what i do: this.contactListener.BeginContact = function (contact) {
// 1) we get the bodies and figure out which body is the spike // 2) we cancel the collision reaction // 3) we get the world manifold to find the world collision point // 4) we ensure this body is not already connected and has the conditions that allows it to connect (e.g. property softBody or Flesh) // 5) we check the contact angle, we only want to attach bodies that enter the spike from the right direction, it should not stick // when the body touches the side of the spike // 6) if all conditions are met we push the body in an array to attach the joint in the next frame (can't attach joints during collision step) } this.contactListener.EndContact = function (contact) { // 1) we check if this body was attached to this spike // 2) if so we push it in an array to remove in the next frame }
And voila! You can use the maxMotorForce property of a prismatic joint to set the resistance of the body on the spike. This code is also powering things like arrows and spears:
|
|
|
Logged
|
|
|
|
Smerik
Level 1
|
|
« Reply #3 on: November 06, 2020, 11:09:37 AM » |
|
Currently working on the functionality similar to the Ninja Rope from worms, wow that was way harder than I expected. This blog post was most helpful in figuring out how to do it: http://antonior-software.blogspot.com/2016/12/box2d-ninja-rope.htmlObviously we won't shoot the rope from his head, we will have upgrades that you can place around the world, similar to how it works in Mario. Here is an example of the hats you can find: Any idea what the first hat is going to do?
|
|
|
Logged
|
|
|
|
|
Smerik
Level 1
|
|
« Reply #5 on: November 20, 2020, 02:09:30 AM » |
|
I have finally managed to add full Bezier Curve editing in the engine and vertice editing in general. You trigger this mode by double clicking a graphic or a physics object. Bezier curves are really fun! One thing was a bit tricky, for adding new vertices you can click the path at any point, but how do you detect clicking on a bezier curve? For that I'm actually using a library called jsBezier. This has a very simple function that can calculate the distance to any bezier. Having this functionality in there really improves the art created by people in our community. Check out this amazing level!
|
|
|
Logged
|
|
|
|
JobLeonard
|
|
« Reply #6 on: November 20, 2020, 04:06:15 AM » |
|
Nice! Gave the Christmas level a spin - took me a little experimenting to figure out the controls but worked just fine after that
|
|
|
Logged
|
|
|
|
Smerik
Level 1
|
|
« Reply #7 on: November 20, 2020, 12:37:32 PM » |
|
Nice! Gave the Christmas level a spin - took me a little experimenting to figure out the controls but worked just fine after that That's actually great feedback, I still have to work on a proper tutorial for the game. That's one of those things that is always pushed back.
|
|
|
Logged
|
|
|
|
Smerik
Level 1
|
|
« Reply #8 on: November 23, 2020, 11:27:35 AM » |
|
Optimization of Explosions I took a stab at optimizing explosions. They are already quite optimized by themselves, but when you group A LOT of them next to each other, you create a chain reaction which results in a lot of debris being created. Each barrel creates like 30 physics particles, so when you stack 30 of them together thats 900 physics particles being created in a single frame. I'm going to change how this works and grab particles from a pool that can max hold 200 particles. This way I'm not creating particles (using "new" in javascript or any other language is expensive) but am just swapping in and out existing particles from the pool. This will increase the performance and take a very tiny cut in memory consumption which is way worth it!
|
|
|
Logged
|
|
|
|
JobLeonard
|
|
« Reply #9 on: November 23, 2020, 02:55:03 PM » |
|
Nice. I'll be on the look-out for improperly cleaned up state
|
|
|
Logged
|
|
|
|
Smerik
Level 1
|
|
« Reply #10 on: November 27, 2020, 01:39:37 AM » |
|
Nice. I'll be on the look-out for improperly cleaned up state Haha! Yeah i'm constantly on the lookout out for these kind of leaks. It's becoming a bigger nightmare with the complexity of the engine growing.
|
|
|
Logged
|
|
|
|
vdapps
|
|
« Reply #11 on: November 27, 2020, 05:55:01 AM » |
|
Heh, I gave it a try (web alpha version), and it's lot of fun, with superb physical mechanics. Very nice piece of work, I always admire pure HTML5 games done right (I see it as more complicated to do and to debug comparing to 'conventional' languages).
Also I have to say, I appreciate physics in your game (I'm doing simple 2D physics in my other game RTG) and for me it's quite a challenge (I did only simple box vs box collisions, so veeery basic stuff and I saw it's no easy thing to do it correctly). I see that you are resolving much more complex things like joints, generic geometry vs generic geometry collisions, etc.. and it works nicely, fluently without glitches, this is quite high-level to me. (btw, I was working with Havok before, back when I was in professional game development, I had lot of fun with physics in test levels).
|
|
|
Logged
|
|
|
|
Smerik
Level 1
|
|
« Reply #12 on: November 28, 2020, 06:03:16 AM » |
|
Thanks @vdapps. I do have to admit that I'm using a library for all the pure physics calculations. It's a library called Box2D. I have always been fascinated by physics engine. Love also the work from Natural Motion (Endorphin & Euphoria), but Havok managed to bring physics in games to mass market.
|
|
|
Logged
|
|
|
|
vdapps
|
|
« Reply #13 on: November 28, 2020, 03:19:36 PM » |
|
Nice to know about this Box2D lib, maybe I'll give it a shot, even if in my RTG project I will use only very simple physics. Let's see. Yeah, I was with Havok around 2005, it was new thing back then, we were awed by what it's doing. Look at JOLLY WORLD again, are you not inspired by Happy Tree Friends ?
|
|
|
Logged
|
|
|
|
Smerik
Level 1
|
|
« Reply #14 on: November 28, 2020, 10:19:08 PM » |
|
Yes! Happy Three Friends, the strong contrast between funny cute characters and gore is something that we (me and Cicla) always loved. Also things like Rick & Morty, Southpark.
|
|
|
Logged
|
|
|
|
vdapps
|
|
« Reply #15 on: November 29, 2020, 03:23:26 PM » |
|
Happy Tree Friends - Out on a limb - my all time favorite. Can't stop laughing even if watching for 100th time.
|
|
|
Logged
|
|
|
|
Smerik
Level 1
|
|
« Reply #16 on: February 06, 2021, 02:26:00 AM » |
|
Hey All, it has been a long time of crunch. Sorry for not posting more updates here. But I'm here now to say that the game finally reached Beta! The road was hard, but we managed to pull true. Here is a short recap of what happened in the last months: First of all, JollyWorld was initially build on Firebase backend (from google), this is very awesome to get a quick prototype of your product ready, however I read so many horror stories of people getting billed 30.000+ USD for simple mistakes they made in their code that I got very worried. I did not want to spread the word of the game with this backend still attached. We managed to find someone who is very capable of building backends, and he helped us out and created a fully custom backend in GO language. Awesome! Then came the next challenge, we wanted the game to work on mobile phones, however the UI was not at all optimized for mobile screens, especially not for portrait view. Getting the game playable and UI navigable was a very big challenge. We came up with this auto scroll screen, which shows the user there is also horizontal scroll support: Now with the new backend and the mobile UI & UX fully working we are ready for the next step in our journey! BETA!
|
|
|
Logged
|
|
|
|
cicla
|
|
« Reply #17 on: February 06, 2021, 05:46:40 AM » |
|
A lot of progress achieved very quickly, with a lot of effort of course but also with the help of the small community that is active on discord giving suggestions, reporting bugs and often engaged with the updates. Really cool!
|
|
|
Logged
|
Yohooo!
|
|
|
Smerik
Level 1
|
|
« Reply #18 on: March 20, 2021, 08:24:00 AM » |
|
Update 0.9.38 - We now support midi songs for your levels! You can upload your self created midi songs, or upload any of the 100.000 midi songs from here: https://bitmidi.com/ - When you have a midi uploaded to your level, you can also play any of its included instruments using a trigger. - Renamed `transparency`to `opacity`
|
|
|
Logged
|
|
|
|
|