387 lines
16 KiB
Text
387 lines
16 KiB
Text
== Lesson 13: A Game Folder
|
|
|
|
image::learn/13-game-folder.png[The finished lesson, 480]
|
|
|
|
Your game is a script in a folder you remember the name of, started by typing
|
|
its name at a terminal. That is fine for you and useless for anybody else. A
|
|
player should be able to copy a folder next to Singe, start the menu, see your
|
|
game listed with its title and its artwork, and press a button. The picture
|
|
above is that menu, with your game in it.
|
|
|
|
That takes one new file, about six lines long, and two pictures you can take
|
|
with one key. Your script does not change at all.
|
|
|
|
=== Give the Game a Name
|
|
|
|
A game has two names, one for the computer and one for people.
|
|
|
|
The one for the computer is the folder, and you chose it in lesson nine:
|
|
`rocks`, with `rocks.singe` inside it. The folder and the script share a name,
|
|
the way every lesson has since lesson one, which is why `Singe rocks` finds the
|
|
script from the folder alone. Keep that name plain. No spaces, which a
|
|
terminal reads as the gap between two names. And the same capitals everywhere
|
|
you type it: on most computers that are not Windows, `rocks` and `Rocks` are
|
|
two different folders, and a game that only runs on your machine is not a game
|
|
anybody else can have.
|
|
|
|
The name for people can be anything you like, capitals, spaces, and all, and
|
|
it does not live in the folder name. It lives in the file this lesson is
|
|
about, so that renaming the game on the menu never means renaming a folder.
|
|
|
|
=== What Goes in the Folder
|
|
|
|
Everything your game needs, and nothing else. By the end of this lesson it
|
|
looks like this:
|
|
|
|
----
|
|
rocks/
|
|
games.dat What the menu reads
|
|
rocks.singe The game
|
|
art/ The art kit from lesson nine
|
|
spaceship.png
|
|
asteroid.png
|
|
bullet.png
|
|
star.png
|
|
shoot.wav
|
|
boom.wav
|
|
...
|
|
cabinet.png A picture the menu shows beside the list
|
|
marquee.png A picture the menu shows above it
|
|
----
|
|
|
|
Anything else that ended up in there while you were learning -- `walk.singe`
|
|
from lesson nine, the little sound test from lesson ten -- is not part of the
|
|
game. Move them into a folder of their own beside `rocks`. The art kit also
|
|
has a few files this game never loads, and they do no harm for now. Lesson
|
|
thirty is where you go through a game folder and take out everything that is
|
|
not the game.
|
|
|
|
The rule behind that layout is that a game never reaches outside its own
|
|
folder. Not for artwork, not for a sound, and not for a library you also use in
|
|
another game -- if you share code between two games, each one keeps its own
|
|
copy. There is exactly one place outside the folder a game may load from, and
|
|
you are already loading from it: the engine's own `Singe` folder, where
|
|
`Singe/Framework.singe` lives, and since lesson ten the click and the music.
|
|
|
|
The game folder sits in your work folder, beside the engine:
|
|
|
|
----
|
|
singe/ Your work folder
|
|
Singe-v3.00-... The engine itself, whatever yours is called
|
|
Menu.sh Starts the menu. Menu.bat on Windows
|
|
Singe/ Support files. Not yours; leave them alone
|
|
data/ Everything anything writes, your save among it
|
|
rocks/ Your game
|
|
----
|
|
|
|
That is the shape a player's machine has too. The engine wrote `Singe`,
|
|
`data`, and `Menu.sh` (`Menu.bat` on Windows) the first time you ran anything,
|
|
back in lesson one. Lesson one mentioned the first two. The third is new to
|
|
you, and this lesson puts it to work.
|
|
|
|
=== Paths Count from Where Singe Started
|
|
|
|
You have been doing this since lesson nine, so this is a reminder, not a
|
|
change.
|
|
|
|
Every name your game loads -- `art/spaceship.png`, `art/boom.wav` -- is looked
|
|
for starting at the folder Singe was *started in*, not the folder your script
|
|
is in. You start Singe in your work folder, so a bare `art/spaceship.png`
|
|
would be looked for in `singe/art`, which does not exist. `DIR` is your
|
|
script's own folder with the slash already on the end, so a name joined to it
|
|
points at your file from wherever Singe was started:
|
|
|
|
[source,lua]
|
|
----
|
|
local shipSprite = spriteLoad(DIR .. "art/spaceship.png")
|
|
----
|
|
|
|
The menu starts Singe in the folder `Menu.sh` sits in, which is your work
|
|
folder again, so `DIR` does there exactly what it does for you. It keeps doing
|
|
it when the game is packed into a single file in lesson thirty, when somebody
|
|
else's work folder is called something else entirely, and on a machine you
|
|
will never see. A name that begins `Singe/` is the engine's folder and never
|
|
needs `DIR`; every name that is yours does.
|
|
|
|
=== games.dat
|
|
|
|
`games.dat` is how a game introduces itself. The menu reads the `games.dat` of
|
|
every game folder beside it and lists what it finds. No `games.dat`, no
|
|
listing: your folder is invisible, however good the game inside it is.
|
|
|
|
Make a new file called `games.dat` in your `rocks` folder. This is the smallest
|
|
one that works:
|
|
|
|
[source,lua]
|
|
----
|
|
GAMES = {
|
|
{
|
|
TITLE = "Rocks",
|
|
SCRIPT = "rocks/rocks.singe"
|
|
}
|
|
}
|
|
----
|
|
|
|
That is Lua, and it is a table of the kind you met in lesson six: `GAMES` is a
|
|
list, and each thing in the list is a record describing one game. One folder
|
|
can hold several games -- that is why it is a list -- but yours holds one.
|
|
|
|
`SCRIPT` is the field the engine needs to run the game, and `TITLE` the one the
|
|
menu needs to list it. The script's path is counted from the folder *above* the
|
|
`games.dat`, not from the folder the `games.dat` is in.
|
|
So a `games.dat` inside `rocks` names its own script as `rocks/rocks.singe`.
|
|
That looks like it says `rocks` twice and it is correct. Every other path in
|
|
the file works the same way. Get it wrong and nothing complains when you type
|
|
the name: the entry simply never matches the script you ran.
|
|
|
|
`TITLE` is the name for people from the start of this lesson. It is what the
|
|
menu shows, and games are listed in title order, so a title is also where
|
|
your game sits in the list.
|
|
|
|
=== Telling the Menu More
|
|
|
|
The menu has a whole panel to fill beside the list, and it fills it from the
|
|
rest of the entry:
|
|
|
|
[source,lua]
|
|
----
|
|
GAMES = {
|
|
{
|
|
TITLE = "Rocks",
|
|
SCRIPT = "rocks/rocks.singe",
|
|
CANVAS_X = 720,
|
|
CANVAS_Y = 480,
|
|
YEAR = 2026,
|
|
GENRE = "Shooter",
|
|
DEVELOPER = "Your Name Here",
|
|
PUBLISHER = "Your Name Here",
|
|
DESCRIPTION = "Shoot the rocks before they reach your ship.",
|
|
CABINET = "rocks/cabinet.png",
|
|
MARQUEE = "rocks/marquee.png"
|
|
}
|
|
}
|
|
----
|
|
|
|
`CABINET` and `MARQUEE` are ordinary image files in your game folder, in any
|
|
format Singe can read. The cabinet art is the big picture beside the list and
|
|
the marquee is the strip above it. Make them whatever size you like; the menu
|
|
fits them into their panels.
|
|
|
|
You do not need a drawing program to make them, because your game can take
|
|
its own picture. Run it, and when the screen looks the way you want the world
|
|
to see it, press F12 (or F11, because some desktops keep F12 for themselves).
|
|
Singe saves a picture of the window into your game's data folder, `data/rocks`,
|
|
named `singe000.png`, then `singe001.png`, and so on. Take one of the title
|
|
screen and one in the middle of a fight. Copy them into your `rocks` folder and
|
|
rename them: the fight is `cabinet.png`, the title is `marquee.png`.
|
|
|
|
A real marquee is a wide strip with the game's name in big letters, and a
|
|
whole screen squeezed into it looks like a postage stamp. It will do until you
|
|
have something better. Leave `MARQUEE` out and the menu puts the engine's own
|
|
missing picture there instead, a pink checkerboard that says MISSING, which is
|
|
worse.
|
|
|
|
`YEAR`, `GENRE`, `DEVELOPER`, `PUBLISHER`, and `DESCRIPTION` are the text
|
|
underneath, and the engine never looks at them. They are for the person reading
|
|
the menu, which is the point.
|
|
|
|
`CANVAS_X` and `CANVAS_Y` are the size of your game's world, and 720 by 480 is
|
|
the default -- the same world you have been drawing in since lesson one. Set
|
|
them only if your game wants a different shape. A game with no `VIDEO` field is
|
|
a game with no video, which is what yours is; lesson fourteen is where that
|
|
field starts to matter.
|
|
|
|
The reference's `games.dat` section lists every field there is, including
|
|
several for hardware you do not have yet. A few more are worth knowing the
|
|
names of now.
|
|
|
|
`REQUIRES` says what a game needs from the machine beyond plain 2D: `"GUI"` for
|
|
the menus and pages of lesson twenty, `"SCENE"` for the 3D that starts in
|
|
lesson twenty-two, and a few more. The menu reads it so that it can tell a
|
|
player "this machine cannot run that" instead of letting the game fail
|
|
halfway in. Rocks is plain 2D, and leaving `REQUIRES` out means exactly that,
|
|
so leave it out. You will rarely have to work out the list yourself, because
|
|
Singe notices what a game uses as it runs and says so when the entry does not
|
|
list it. From lesson twenty on you will see lines like this one, whether or
|
|
not the game has a `games.dat` at all:
|
|
|
|
----
|
|
Warning: this game uses GUI, which its games.dat does not list in REQUIRES.
|
|
----
|
|
|
|
It is advice, not an error; the game runs either way. The cure is one line in
|
|
the entry, `REQUIRES = { "GUI" },`, and packing a game in lesson thirty writes
|
|
the list for you if the entry has none. Its partner `TIER`, a number from 0 to
|
|
3, says how much machine a game wants, and can wait until you write a game
|
|
heavy enough to care.
|
|
|
|
`GAME_ID` is a unique identity for your game, which the online high score
|
|
tables in lesson twenty-eight need and nothing else does. And `RESOLUTION_X`
|
|
and `RESOLUTION_Y` ask for a particular window size. Ignore the rest until
|
|
something sends you looking.
|
|
|
|
=== Running It from the Menu
|
|
|
|
Run `Menu.sh` -- `Menu.bat` on Windows -- from your work folder. It finds the
|
|
newest Singe beside it and starts the menu.
|
|
|
|
Your game is in the list, with its artwork beside it and its description
|
|
underneath. It is the only thing in the list, because `rocks` is the only
|
|
folder you have given a `games.dat`; `hello`, `dodge`, and the rest are not
|
|
games as far as the menu can tell. Up and down move one game, left and right
|
|
move a page, and start or a fire button plays the one that is selected. Quit
|
|
the game with Escape and you are back at the menu, on the same game, ready to
|
|
go again. The menu remembers which game you were on between runs, too.
|
|
|
|
That is the whole of shipping a game, as far as the engine is concerned. A
|
|
player copies your folder next to Singe and it appears.
|
|
|
|
Typing the name still works, and works the same way:
|
|
|
|
----
|
|
Singe rocks
|
|
----
|
|
|
|
When you launch a script by hand like that, Singe looks for a `games.dat`
|
|
beside it -- and in up to three folders above it -- and if an entry names the
|
|
script you launched, that entry's settings apply to it. So a game plays the
|
|
same from a terminal as from the menu, which means you can go on working the
|
|
way you have been, with `-R` and a text editor, and still trust what a player
|
|
will get. It writes to the same place, too: started either way, your game's
|
|
save is the one in `data/rocks`.
|
|
|
|
=== Later: One File
|
|
|
|
A folder is easy to work in and slightly awkward to give away: a dozen files, a
|
|
folder inside a folder, and a player who unzips it into the wrong place. A
|
|
finished Singe game can be packed into a single `.game` file that the engine
|
|
runs directly, artwork and sounds and all, which a player copies next to Singe
|
|
and is done.
|
|
|
|
Nothing in your game has to change for that. It is lesson thirty, and it
|
|
is worth waiting for: pack a game that is not finished and you will pack it
|
|
again tomorrow.
|
|
|
|
=== What Just Happened
|
|
|
|
[source,lua]
|
|
----
|
|
GAMES = {
|
|
{
|
|
----
|
|
|
|
Two braces, because it is a list of records. The outer one is the list. The
|
|
inner one is the first thing in the list, which is the record for one game.
|
|
Getting one of them wrong is the usual mistake, and Lua will tell you the line.
|
|
|
|
[source,lua]
|
|
----
|
|
SCRIPT = "rocks/rocks.singe",
|
|
----
|
|
|
|
Counted from the folder above the `games.dat`, which is your work folder. It is
|
|
the same name you would type after `Singe` to run the script by hand, and that
|
|
is the easiest way to remember it.
|
|
|
|
The comma at the end of the line separates one field from the next, exactly as
|
|
in lesson six. The last field in a record has no comma after it -- Lua does not
|
|
mind if it does, but leave it off and your file will look like everybody
|
|
else's. A comma that is missing in the middle is another matter, and it is
|
|
this lesson's error.
|
|
|
|
[source,lua]
|
|
----
|
|
CABINET = "rocks/cabinet.png",
|
|
----
|
|
|
|
A picture the menu loads, not your game, so it is named the way `SCRIPT` is,
|
|
from the folder above, and not with `DIR`. `DIR` belongs to your script while
|
|
it runs, and the menu and the engine read `games.dat` before your script has
|
|
started.
|
|
|
|
=== Try It
|
|
|
|
. *Make better artwork.* If you have a drawing program, make a proper
|
|
`marquee.png`: a wide strip with ROCKS across it in big letters. Put it in
|
|
place of the screenshot and look at the menu again.
|
|
. *Give Dodge a games.dat.* Write a `games.dat` in your `dodge` folder from
|
|
lesson seven and start the menu. Two games now, in title order. Then change
|
|
the `TITLE` of Rocks to `Asteroid Field` and watch it move above Dodge: the
|
|
list is sorted by title, not by folder.
|
|
. *Break games.dat for the menu.* Delete one of the closing braces in the
|
|
`games.dat` in `rocks` and start the menu. Your game is gone from the list,
|
|
and the terminal says why. Put it back.
|
|
. *Get SCRIPT wrong.* Set `CANVAS_X` to `1280` and `CANVAS_Y` to `720`, and run
|
|
`Singe rocks`. The field is wider. Now change `SCRIPT` to `rocks.singe` and
|
|
run it again. The game is back to its old size, and nothing told you: the
|
|
entry no longer names the script you ran, so it does not apply. Put both back.
|
|
. *Find your save.* Start the game from the menu, set a high score, quit back
|
|
to the menu, and quit the menu. Run `Singe rocks` and look at the title.
|
|
Then look in `data/rocks` for the file that remembered it.
|
|
|
|
=== Break It on Purpose
|
|
|
|
Take the comma off the end of the `TITLE` line, so the top of the file reads:
|
|
|
|
[source,lua]
|
|
----
|
|
GAMES = {
|
|
{
|
|
TITLE = "Rocks"
|
|
SCRIPT = "rocks/rocks.singe",
|
|
----
|
|
|
|
Run `Singe rocks`. The game starts, and the terminal says this:
|
|
|
|
----
|
|
Note: rocks/games.dat ignored: [string "rocks/games.dat"]:4: '}' expected (to close '{' at line 2) near 'SCRIPT'
|
|
----
|
|
|
|
Your game still runs, because a game started by name does not need its entry.
|
|
It just runs without it. Start the menu, though, and your game is gone. If it
|
|
was the only one there, the list says `No games yet`, and the terminal says
|
|
the same thing a different way:
|
|
|
|
----
|
|
rocks/games.dat: rocks/games.dat:4: '}' expected (to close '{' at line 2) near 'SCRIPT' Skipped.
|
|
----
|
|
|
|
Read it like any other Lua error. The file is `rocks/games.dat` and the line
|
|
is 4. But line 4 is the `SCRIPT` line, and there is nothing wrong with it. The
|
|
mistake is at the end of line 3. After `TITLE = "Rocks"`, Lua expected either
|
|
a comma and another field, or the `}` that closes the record that began on
|
|
line 2. It found `SCRIPT` instead, so line 4 is where it noticed. Its guess at
|
|
the fix -- a `}` -- is wrong; its line is out by one. When an error points at
|
|
the start of a line, look at the end of the line before it.
|
|
|
|
Put the comma back, and start the menu again.
|
|
|
|
=== What You Learned
|
|
|
|
* A game is a folder: the script, its artwork, and a `games.dat`, and nothing
|
|
from outside it except the engine's own `Singe` folder.
|
|
* The folder's name is for the computer, so keep it plain. The name for people
|
|
is `TITLE`.
|
|
* Names your script loads are counted from where Singe was started, which is
|
|
why every one of them is built from `DIR`.
|
|
* `games.dat` is a Lua file holding a `GAMES` list, and each entry is one game.
|
|
* An entry needs `TITLE` and `SCRIPT` and nothing else; paths in it count from
|
|
the folder above the `games.dat`.
|
|
* `CABINET`, `MARQUEE`, `YEAR`, `GENRE`, `DEVELOPER`, `PUBLISHER`, and
|
|
`DESCRIPTION` are what the menu shows the player, and F12 takes a picture you
|
|
can use for the first two.
|
|
* `REQUIRES` tells the menu what a game needs beyond 2D, and Singe warns you
|
|
when a game uses something its entry does not list.
|
|
* `Menu.sh` or `Menu.bat` starts the bundled menu, which lists every game
|
|
folder beside it, sorted by title.
|
|
* A game launched by name gets its `games.dat` entry too, so it behaves the
|
|
same either way, and a `games.dat` that will not load is reported and
|
|
ignored.
|
|
* A finished game can be packed into one file later, in lesson thirty.
|
|
|
|
=== Next Time
|
|
|
|
That is part two finished: you have a game, with art, sound, collision, score,
|
|
and a way for somebody else to run it. Part three is about the thing almost no
|
|
other engine does -- playing film as the world the game happens in -- and
|
|
lesson fourteen starts with the disc, the frame, and the wait.
|