Back to Defold after 2 years, "Bouncy Catapult" hypercasual prototype


Hi, my name is Marat and I want to share my first experience with Defold.

I hope it can be helpful for other newbies to avoid some issues I’ve faced or for engine developers to better understand how it looks from our side :slightly_smiling_face:

Well, actually it’s my second try with Defold. The first one was 2 years ago, in Autumn 2016 when I dropped Flash development and was thinking where to apply myself next. So I tried Defold, spent about 2 weeks to came up with this $hitty [prototype] - and it was 2 weeks of pain and suffering, it was so hard for me to swich my mind into a new paradigm (Lua, non-OOP, soft typisation, scripts attached to objects, factories, proxies, messages, global scope, etc…) So I became a Unity-developer :sweat_smile:
(By the way, this prototype idea was reworked under Unity and successfully released on iOS and Android, but it is another long story)

New history
In the company I’m currently working there was an internal Game Jam, with the goal to create a hypercasual game with the “D.I.Y” theme in a month. So I thought it’s a good chance to give Defold another try.

The Game Jam is finished now, here is the actual state of the prototype:
HTML5: - don’t hesistate to leave a feedback :see_no_evil:

lvl_1 lvl_2 lvl_3

First issue
The first thing I’ve faced when launched the newly installed editor on my laptop - crashes with “The graphics device does not support: glGenBuffers” error. Not the best “first time user experience”, right :grin: ? There was something with support of old GPUs like mine IntelHD3000, solution was found here and some details here. Not a big deal, but I don’t have such issues with other software, so it would be nice to have solution from the box (if it’s possible).

Next issues in more or less chronological order (Editor v1.2.142)

  1. "Alien" physics by default
    From the docs it sounds like physics is kinda Earth-based, with newtons, kilos and meters, gravity set to -10, but when you try to create a 1kg-1-meter-sided box and apply some force to it, the box floats like it’s under water or on an asteroid. After reading forum and playing with settings, you understand, that it’s very far from “Earth-based” from the box and more comfortable settings should be like:
    GravityY: -1000, Scale: 0.02
    I wonder if there is a case, when default physics are good to go? Maybe it would be better to set defaults to something more usable?
  2. BUG: Wrong representation of scaled physical objects
    If you scale your physical objects unproportionally, then their representation in the Editor and in the build will be different (for ex. the bar in the game and in the editor). It seems to be a known issue, the workaround is to scale all axis the same. But for level design purposes it would be very useful to be able to scale your objects as you want.
  3. "Edge bleeding"
    It’s a thing I believe every user faces when he deals with atlases first time in Defold (ok, and in pretty any other engine…) Solution is to set a margin/borders in your atlas settings. I even voted to set such margin by default here, but now I’m not so sure.
  4. Masks/Groups management of collisions is not handy to edit
    To say “I want this group of objects to collide with that group(s)” you need to set the mask names in both collision objects. Ok, soudns reasonable. But when you want to add a new group, which should collide with some old groups, but not with all of them, you are forced to manually go through all your collision objects and set a new grouping/masking settings. In my opinion the collision objects matrix like in Unity is more friendly.
  5. Objects, spawned by proxy, can’t collide with previously spawned ones
    When you spawn a new collection with the same objects via collectionproxy (so, they have the same grouping/masking) these new objects will not collide with old ones, because they “live” in a new “world”. This is by design, but was not obvious at first, when I wanted to keep walls static and only respawn inner stuff for new levels, but this did not work. So now I’m spawning the whole new level with walls, even if they stay the same.
  6. Stretch render projection by default
    By defaut game contents will be rendered stretched if the actual screen’s ratio differs from sizes set in settings. There is “fit size projection” in the render script so it’s not hard to switch it, but again - I can’t imagine a situation in a “real world” where developer wants his contents to be streched. Why not make it proportionally fitting screen size by defaut?
  7. Clicks appear in logic coordinates
    When I’ve switched from strech_projection to fit_size_projection in render script, something strange happened to clicks handling. After some investigation I’ve figured out that clicks still appear in “stretched” coordinates or something like this, when game contents were rendered differently. There are screen_x and screen_y params, but these are still live in some strange coordinates, so I had to write a lua module to grab screen sizes from render script and convert click coordinates to actual screen coordinates. I’ve spent one or two evenings to deal with it, but honestly I’d prefer such thing to work from the box. I understand that it might sound naive, but it feels like some simple things does not work by default and you had to implement them manually. I never faced such issues in Flash or Unity.
  8. There is no clear strategy to support different screen resolutions
    Ok, I want to support HTML5, iOS and Android, so the screen sizes can be, say, from 600x400 to whatever_crazy_retina_sizes. How to make my game look good on all devices? I did not find a solid answer, just some threads on forum (one, two, three) with advices like: “draw your sprites in 2k resolution, set logic screen sizes to 1k and set 0.5 scale to all your images in scenes; and enable highDPI”. I tried so and it seems working. But it’s not clear why and how it works, right now it sounds like a cargo-cult for me. Would be nice to have a solid manual covering this question.
  9. Converting global coordinates to local and vice versa
    To show a hit-point on a bar (or better say in a bar) I had to convert global coordinates of hit-point to bar’s local coordinates. I did not find any API to do so, and manual convertion looked tricky because local coordinates seem to be dependent on scale and rotation of objects in hierarchy. I’ve solved this by setting object’s parent to global and back to local, but it would be nice to have such API from the box (btw, both Unity and Flash had it)
  10. HTML5 page template with flexible canvas
    Currently in HTML5 build the canvas size is set to project’s logic sizes, but in my opinion auto-stretching canvas is more useful solution. I made such template based on Dragosha’s project. But maybe such template should be set by default or added as an option?
  11. You can’t edit built-in stuff
    It sounds logic, but at first time when I’ve tried to edit my render script it was very frustrating why my changes worked locally but did not in the build. Then I’ve noticed the star-sign saying “this file is not saved” and copied the script to a custom folder, saved and it worked. But later I faced this 2-3 times again. Would be nice to have some notification on attempt to edit and savethe built-in stuff
  12. BUG: Wrong font’s kerning and align in Editor
    “Text tracking” setting is shown wrong (or better say is not showing at all) in the editor, but works in the build. Here is a screenshot - at the left how it looks in the build, at the right - in Editor.
  13. mipmaps are enabled by default
    I’ve noticed, that when the game is shown on screens smaller than logic sizes set in settings, the game appears very blurred and with artifacts. After investigation I figured out that in Defold mipmaps are enabled by default, when I’ve disabled them the issue was solved. So the question - how mipmaps suppose to work in 2D and maybe better to disable them by default?
  14. Particles stop spawning after X iterations
    I have not investigated this eyt, but at least in HTML5 build particles stop spawning after playing the game for few minutes. Maybe it’s a known thing, have not got time to dig into yet.
  15. Font issues in 1.2.144
    Another issue I’ve just faced and have not checked yet - after updating to 1.2.144 there are new issues with font’s outline and tracking

Few other things I’d want to have in the engine:

  • Get particle texture randomly from the set
    I have not found a way to configure an emitter to choose particle’s texture randomly from a set of textures. Would be nice to have such option.
  • Trigger “window_resized” message on startup
    It might be very helpful, if this event will trigger on the startup, so you can know actual screen sizes from the beginning and then just track changes. In this case you probably don’t need any workarounds to get real screen sizes from render script, like I did by the Lua module.
  • Custom event in analytics
    There is a built-in analytics system in Defold, would be nice to be able to send something custom to it (or more default events)

Hey, It’s not so bad! :sunglasses:
In common working with Defold this time was a pleasure for a 95% of time! It’s a powerful and flexible tool and all the issues I’ve listed above were not very critical.

Further plans
I did not win in the Game Jam, but I’m looking forward to finish the game and release on mobile stores. Maybe even as an Instant game, we’ll see.

Thanks to the engine team and comunity, you’re great! :+1:


P.S. The ability to share HTML5 build in any messenger and expect IMMEDIATE feedback - priceless! Forgotten feeling in the mobile phones era. :smiling_face_with_three_hearts:


Wow, a super big thank you for the amazingly detailed feedback on your first (second) impression of Defold. We will go through this feedback, point by point, within the team and see which of the rough edges that we can get rid of or simplify.

Maybe I can send you some swag as a consolation prize and a way of thanking you for the great feedback? PM me with an address!


What was the ”pixel size” of the box?


Well, can’t remember exactly, something like 100px, but for sure it was not a 1 pixel, which used to be an interpretation of 1 meter with default physics world scale, I guess. So I was wrong saying that my experiment was with for „1 meter” box, and from such point of view it’s behaviour probably was correct, but still confusing :slight_smile:


Yes, 1 unit (pixel) corresponds to 1 meter with default scaling and gravity.


I’ve clarified the units used in the physics manual:

Created DEFEDIT-1524 to make sure the editor behaves like the engine does.

There’s a long discussion regarding this in the post you linked. Our standpoint is that we will not change it.

I agree that the workflow is a bit problematic. It is however nothing we have any plans to solve soon.

Also nothing that we plan to change. But maybe it needs better documentation?

Our promise to never break backwards compatibility is preventing us from changing the default behaviour. What we will do is to change the default render script so that it can accept a message to change projection. This will make it easier for new users to change the projection from stretch to fit without having to copy the render script and make modifications. Created DEF-3721.

This is something that may seem trivial to solve but it really isn’t. Since you have full control over the render script you can render your game in multiple passes with different viewports and projections which makes it impossible for us to know what coordinates you actually need. The way we provide values in the action table:

  • action.screen_x/y will give you the pixel position of the mouse.
  • action.x/y will give you a position that is mapped to the width and height specified in game.project, regardless of the actual window height

Example: With a game.project size of 400x400 and a window size of 400x400 and the mouse is positioned in the top right corner of the window:

  • action.x = 400
  • action.y = 400
  • action.screen_x = 400
  • action.screen_y = 400

Example: With a game.project size of 400x400 and a window size of 600x600 and the mouse is positioned in the top right corner of the window:

  • action.x = 400
  • action.y = 400
  • action.screen_x = 600
  • action.screen_y = 600

If you need the mouse position to work well with whatever projection you are using you need to make the necessary calculations yourself, or use a camera system such as RenderCam

We need to create a manual that explains this. Created DEF-3722.

There is go.get_world_position() to convert from local to world position. And gui.get_screen_position(). You also have the keep_scene_transform argument to gui.set_parent() and the keep_world_transform argument for the set_parent message (yes we should have a go.set_parent function, it’s in DEF-3723).

I totally agree. I have my own template:

It’s nice that you can make changes to test things but it is also confusing. Can we make this clearer @mats.gisselson and @markus.gustavsson?

I can’t find a report for this issue. Would you mind creating one via Help->Report Issue?

Not sure what is expected here. @jhonny.goransson and @sven?

This is not a known thing and it sure sounds like a bug! Can you please create a repro and share it?

@jhonny.goransson, can you follow up on this?

This sounds like a nice improvement. It is however currently not something that we have planned to do.

This or adding a function to window.* to get current size of window (tracked as DEF-3012).

We do not plan to make any improvements to the analytics tool. In fact, we will probably evaluate if it should be removed (we need to make a proper analysis of it’s use first though!).


There is a really nice suggestion/prototype by @Jerakin in editor2-issues by the way!


Regarding the “window_resized” message, we also have a discrepancy between platforms for the focus gained/lost (DEF-2520. E.g.all platforms should get a focus gained as well.


Do you have shadows enabled in your font? Could you share the project with me ( or send a zip directly so I can take a look at it :slight_smile:


Can’t really give you a good answer I’m afraid, it’s probably been default for a long time :slight_smile: But generally, the reasoning behind using mipmaps at all is that it is better for performance since smaller textures are more cache coherent when fetching texture samples. Mipmap selection is not directly related to 2D or 3D, it depends specifically on how fast the texture coordinates changes between blocks of projected pixels on screen. So I guess it is enabled by default due to optimisation, but yes it might be confusing if you don’t know why the rendering appears fuzzy.


Nice, I really appreciate such reaction to my feedback, that is super-motivating to keep working on Defold, thanks!

Let’s wait for more complains then :slightly_smiling_face:

I remember I read about “new collection instantiates in a new world” or smith like this, but it was not obvious at first, that such two “worlds” can’t collide with each other. So maybe it worths additionally pointing to such fact somewhere in collection/proxies docs (if it was not already and I did not just miss it)

Ok… I see :pensive: With big power (full control over render) comes big responsibility (managing your clicks regarding your render)

Cool! Can’t wait to read it :+1:

Good. Just to clarify what I’m doing: currently I have an object as a child of a bar and want to move it in bar’s local coordinates to the hit point of a raycast and bar’s collision object. So, I have a global position of a hit and want to convert it to bar’s local coordinates to set as a position of a child object. Currently bar receives a collision message on itself and sends a message with hotpoint to the child object, where I have such not-verry-pretty code:".", "set_parent", {keep_world_transform = 0})
go.set_position(global_hit_position)".", "set_parent", {parent_id = bar_path, keep_world_transform = 1})

Oh, super, I’ll check it. My (and Dragosha’s) template had an issue with loading progress-bar scaling, maybe it’s correct in yours.

Ok, np, let’s see if there will be more requests for such feature

Meh, not a problem at all, there are a lot of ready-to-use analytics systems (just need to chose ones, who support both web and mobile).

I’ll answer other bugs-related questions in separate comments.


That’s my first report, it took me some time to raise the issue =)
Here it is:

Also, after creating my report I’ve noticed this one: which looks exactly the same. Not sure how you’re handling duplicated reports, but pointing just in case.


I don’t have shadows, at least I did not enabled them manually, but for sure I’ve used outline.
Here is the issue reported, there you can find the attached project:


Thanks! I’ll look at it tomorrow (probably). If you want a quick workaround in case it bothers you, you can change the fragment shader in the material to the ”singlelayer”-version from the builtins folder until then!


Thanks. I’ve closed the duplicate and created internal issue DEFEDIT-1526 and added it to our next sprint planning.


Yes, not so pretty code, but you could move those three lines to a utility function. It is not optimal from a performance standpoint of course to make three calls into the engine to do this, but this kind of thing is likely not done that often.


It is mentioned here:
But it should probably be mentioned in the physics manual as well.


And now it is:


Btw you was right about the shadow - shadow alpha was set to 1, but I did not set it and it was not here before the update (or it was set to 1 but just did not work before, can’t say). So, when I’ve set it to 0 the thing I’ve blamed as a “white outline” was solved, plus kerning also looks also correct not, seems I was confused with the symbols thickness caused by the shadow. I’ll update the issue report.


Ok, this one was easy. I’m creating a GO with a sprite and particle system via the factory and when bug appears there is an error in the console:

ERROR:GAMESYS: Sprite could not be created since the sprite buffer is full (128).

Which means I was not properly clearing spawned objects. At first in GO’s “self killing” function I wrote".", “disable”) but it should be go.delete() Now it works.