General Game Making FAQ
Clone this wiki locally
How to approach some common game-making tasks in frogatto:
Frogatto's engine is a bit unusual compared to procedural/c-style programming, so this ought to help you wrap your head around how to get basic stuff done.
How do I blit stuff onto the screen?
Generally, you want to make an object which draws it. Objects can draw almost anything that's pre-rasterized; what we don't have support for in any form in our scripting language is drawing arbitrary vector shapes (even though we're driven by openGL). Objects can even tile rasterized graphics, if you have them in the right format; we use this to repeat the texture on ropes. Objects have a very flexible [frame] system which lets you rotate, scale, recolor, and animate raster graphics.
We do have support for drawing done by non-objects, for a few optimized/convenience cases; such as HUD graphics, parallax backgrounds, and tiles. Typically, though, if you're going to draw almost anything onscreen, you want to figure out a way to do it with an object. More on object's frame system can be found at: --link--
How do I make an object do something?
Objects contain small snippets of code inside things called events. These are a lot like functions in most programming languages. Events will be called either automatically, in response to certain in-game circumstances, or you can explicitly call them by using the fire_event(target,'event_name') function. Some events, like on_timer, or on_process, are automatically called on a regular basis; other events like on_start_level or on_create are created when the level starts, or when the object is first activated on the map.
The game supports several built-in events in response to built-in idioms like dying or colliding, and you can freely create your own named events. You don't need to register them with some central "overseer" of event types; you simply add an on_event_name handler in one object, and call fire_event(target, 'event_name') in another. If you direct an event at an object that does not have a handler for it, it will do nothing.
How do I handle player input?
Make an object. Inside this object, you can handle player input in two complementary ways; when a button is pressed, it will fire an ctrl_whatever event, and you can respond to that event with your own code. Likewise, you can poll for the state of events inside a recurring event like on_process; this uses the same event names, and treats them as boolean variables. You'll also need to flag an object by setting the variable is_human=true to recieve input.
How do I make an object accessible in the editor?
Give the object a [editor_info] tag and set category=something, and it will appear in the respective category in the editor menu. You can also add variables which can be tweaked via the editor's UI, which allows you to drag lines to set boundaries visually. More on this and variables in general here: --link--
How do I create a new object in a level?
There are two answers to this. Either you make the object placeable in the editor, and put it where you want it to be, or, you add it into the level programmatically. For most normal game circumstances, objects (such as buildings/props, players, terrain, enemies, etc) will be present throughout the duration of the level (unless killed), so adding them in the editor works fine. However, in unusual circumstances, you need to create new objects on the fly. For example, enemies might spring from an ambush, or an NPC might "walk in from outside".
To create an object, you use the object('type',x,y,facing) function. This returns a reference to this object; you can set it up with all the properties you want it to have (position, hitpoints, etc), without actually placing it on the level. To place it on the level, you would then add_object(your_reference). Note that because frogatto uses a reference-counting system to manage its memory, if you haven't added the object to the level yet, you must store this reference somewhere (such as in the vars of the object that made it), otherwise this object you've just created will immediately be deleted. Reference counting works by deleting anything from memory that has less than 1 reference to it. References are a way of something saying 'I need this to still exist, don't remove it'; when nothing in the game is vouching for something to stick around, it's removed. Just creating an object doesn't make a reference, but when you add an object to a level, the level has a reference to it, so it only gets removed at the end of the level.
Because creating objects, and then adding them to a level is one of the single most common things done in frogatto scripts, we have a convenience; the spawn('type',x,y,facing) function is a combination of creating and immediately adding an object.
You can get rid of objects by calling remove_object(reference). If you have no manually-created references to the object (besides the automatic one made by the level) it'll immediately be deleted. Since you might actually want to keep it around for something else (say, an NPC briefly walks outdoors, but then comes back inside), you can treat remove_object as a way of "pausing-and-storing" an object, by keeping your own reference to it, and then adding it back onto the level later, when you need it again.
Related to removal is the die() function and die event. When objects are told to die, they will execute one event_handler (on_die), and if their hitpoints are still zero at the end of that handler, they will call "remove_object()" on themselves. The biggest use of this is to provide special animations that happen after something dies (such as spawning the puff of smoke that most frogatto enemies die in), but it can also be used, by raising the HP above zero, to do unusual behavior like resurrecting after death, or doing some other animation that requires you to keep the object around before actually triggering its removal (such as a death-animation driven by the object itself; perhaps of it falling over and dying, and only then being removed).
How do I get a reference to an object?
to be added
How do I create a global variable?
You don't (yet). We're considering adding this, but for now, you store the value in the one object that's going to persist across levels: the player. This gets ugly when you want to change the player object, which is why we're considering adding real global variables.
How do I store a value/etc so it will persist across program launches?
to be added
How do I write a script on a level that makes something happen?
You put it in an object, in the level file, rather than directly executing some code in just the level, itself.
We put the scripts in an object that "oversees" the behavior. Our most common use-case for scripts on a level is "when the player walks into this spot, this behavior should happen". To do this, we have an object called an "level_controller", and it polls the player's position infrequently (maybe 5 times a second, which is 1/10 of our framerate), and if the player enters a rect, it does something. Because objects, by default, only execute when they're nearly on-screen, this automatically has the optimization of allowing you to have a whole bunch of these across a level without them all simultaneously polling. Because we usually need the same behavior, we even made a dedicated object just for this: it's invisible, and has a rectangle you can drag in the editor to give it boundaries for when it's triggered.
The way this works is - you can write event handlers in the definition of a generic "type" of object ... however, you can also write event handlers inside each individual instance of an object (e.g. right in the listing of that object in the level file).
The basic 'level controller" object just has an on_timer event that fires every 200ms, and checks if the player's inside a rect - and if so, fires a "triggered" event. The base type (almost) has no "on_triggered" handler, because it treats that behavior as a "virtual function" - it knows you want something to happen when it's triggered, but only on a case-by-case basis do you supply what actually happens. (To be pedantic, it's actually not "purely virtual"; it has a tiny bit of code that plays a soft 'alert' sound. Since you might not want this to happen in certain scenes, it's useful to know that instance versions of event handlers can prevent the more global 'type' version of the handler from being fired by calling "swallow_event()" in their handler.
(Note: There is a simpler 'target' controller which does not fire the "triggered" event, nor make the alert sound.)