Rewtro uses getters to pick what to process and probably are the most important part of Rewtro coding - even more than code statements itself. The coding principle in Rewtro is "get this thing and do that on it" and for this very reason, any line of code is a getter.
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"sprites":[{"id":"A"}],
"tilemaps":[{"map":["A"]}],
"code":[
{
"then":[
{"id":"A","set":[{"text":[{"string":"HELLO WORLD!"}]}]}
]
}
]
}]
}
The single line of code of this cartridge is:
{"id":"A","set":[{"text":[{"string":"HELLO WORLD!"}]}]}
We have two getters here: the first one is the line itself...
{"id":"A"}
It means _get all the sprites with id
set to A
. Then we have a second getter:
{"string":"HELLO WORLD!"}
This gets a string with the HELLO WORLD! text. Reading the code altogether we have: get all the sprites with id
set to A
and set
the text
property to a string
with HELLO WORLD!
in it.
Getters are not just a way to get sprites: it's more a way to temporarily get a thing. Getters can access the game keyboard
, generate primitives like string
and float
numbers, pick random numbers, and even do some math.
If you're roaming around this manual from some time you should have seen the id
and flags
getters in a lot of examples. These getters are used to reference spawned sprites with a given id
or owning a specific flag
.
There is also a less used ids
getter that can reference multiple sprites id
, working like a more narrow flags
getter.
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"sprites":[
{"id":"A","flags":"F","width":16,"height":16,"backgroundColor":3},
{"id":"B","width":16,"height":16,"backgroundColor":4},
{"id":"C","flags":"G","width":16,"height":16,"backgroundColor":5},
{"id":"D","flags":"FH","width":16,"height":16,"backgroundColor":6}
],
"tilemaps":[{
"x":24,"y":64,
"tileWidth":16,
"map":["A B C D"]
}],
"code":[
{
"then":[
{"id":"B","set":[{"y":[{"smallNumber":40}]}]},
{"flags":"FG","set":[{"rotate":[{"smallNumber":45}]}]},
{"ids":"BC","set":[{"scale":[{"float":1.5}]}]}
]
}
]
}]
}
This cartridge shows some scattered and rotated colored squares...
...but removing the code
it shows a more tidy line of squares.
Why?
The first line of code id
gets the B
sprite and moves it a little more up and that's why the cyan square is misaligned.
Then the second line flags
get all the sprites having the F
or G
flag
set and rotate
them by 45 degrees clockwise. The A
sprite is taken since it has the F
flag, the B
sprite has no flag so it's skipped, the C
sprite has the G
flag so it's taken and the D
flags, even it has the unrequested H
flag set, it has the F
flag and it's taken by the getter too. That's why all the shapes but the cyan one are rotated.
Finally, the third line ids
get the sprites with id
set to B
and C
and then zoomed a bit. That's why the cyan and red shapes are a little larger than the others.
(Rewtro v0.2++)
The id
and flags
getters have their search criteria hardcoded. While this method requires less space in your cartridge, it can lead to a lot of duplicated code when you need some sprites to interact together in the same way.
idsByName
and flagsByName
work like ids
and flags
but they can read the search criteria from another getter, making your logic more flexible.
This cartridge...
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"sprites":[
{"id":"A","flags":"F","value5":"D","text":"A"},
{"id":"B","flags":"F","value5":"E","text":"B"},
{"id":"C","flags":"F","value5":"F","text":"C"},
{"id":"D","backgroundColor":3,"x":60,"y":66,"speedY":-1},
{"id":"E","backgroundColor":4,"x":84,"y":66,"speedY":1},
{"id":"F","backgroundColor":5,"x":100,"y":66,"speedX":1}
],
"tilemaps":[{"map":["ABCDEF"]}],
"code":[{
"when":[{"flags":"F"}],
"then":[{
"placeAt":[{"idsByName":[{"attribute":"value5"}]}],
"sum":[{"x":[{"smallNumber":9}]}]
}]
}]
}]
}
...and this cartridge...
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"sprites":[
{"id":"A","text":"A"},
{"id":"B","text":"B"},
{"id":"C","text":"C"},
{"id":"D","backgroundColor":3,"x":60,"y":66,"speedY":-1},
{"id":"E","backgroundColor":4,"x":84,"y":66,"speedY":1},
{"id":"F","backgroundColor":5,"x":84,"y":66,"speedX":1}
],
"tilemaps":[{"map":["ABCDEF"]}],
"code":[{
"then":[
{"id":"A","placeAt":[{"id":"D"}],"sum":[{"x":[{"smallNumber":9}]}]},
{"id":"B","placeAt":[{"id":"E"}],"sum":[{"x":[{"smallNumber":9}]}]},
{"id":"C","placeAt":[{"id":"F"}],"sum":[{"x":[{"smallNumber":9}]}]}
]
}]
}]
}
...will both show the same three moving squares closely followed by a letter.
They occupy the same amount of bytes in your game cartridge but the first one is more readable and flexible than the second one: adding a new follower sprite will just require you to create a new sprite with a value5
key set instead of a new sprite and a new line of code. Moreover, you can change the value5
of an F
flagged sprite in runtime to make it follow another sprite and this dynamic behavior is way harder to implement using the hardcoded version of the getters.
The key as
is a getter that's used to get special objects or sprites. You can set the as
to get:
this
: it's a special keyword that gets the current context object the code is running. It's the default getter so you don't need to specify it most of the time.that
: it's a special keyword that gets the current destination object. Somecode
statements set a secondary object you can get using thethat
value. For example, when checking if a group of sprites is colliding with another one thethis
value holds the colliding object and thethat
value the collided ones.target
: it's a special keyword that gets the upper level object. When a line executes some sub-code using thecode
statementtarget
gets thethis
object at the start of execution.allSprites
: it gets all the spawned sprites. It's useful to clear the screen.scene
: it gets thescene
special object. You can change its properties to move the camera, change the screen background color and so on.game
: it gets thegame
special object. It's mostly used to set game-wide variables, like high scores, etc.keyboard
: it gets thekeyboard
special object. It knows which controller buttons the player is hitting.songRow
: it gets thesongRow
special object. It knows what the song player is playing.
In many cases these getters are not useful alone: they are used together with sub-getters that we will see later.
It's time for an example. Get ready because this one is not going to be so straightforward.
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"sounds":[
{"id":"A","wave":"triangle"}
],
"music":[
{"id":"A","notes":[["C4-","D4-","E4-","F4-","G4-"]],"instruments":"A"}
],
"songs":[
{"id":"A","loopTo":0,"music":"A","tempo":25}
],
"sprites":[
{"id":"A","x":0,"y":0,"flags":"F","width":112,"text":"I'M A!"},
{"id":"B","x":0,"y":8,"flags":"F","x":0,"y":8,"width":112,"text":"I'M B!"},
{"id":"C","x":0,"y":0,"width":112,"text":"I'M C!","textColor":10},
{"id":"D","x":0,"y":24,"width":112,"text":"I'M D!"},
{"id":"E","x":0,"y":40,"width":112,"text":"I'M E!"}
],
"tilemaps":[{"map":["ABCDE"],"song":"A"}],
"code":[
{
"when":[{"flags":"F"}],
"then":[
{"set":[{"text":[{"string":"I HAVE FLAG F!"}]}]},
{
"code":[
{
"when":[{"id":"A","if":[{"is":"collidingWith","id":"C"}]}],
"then":[
{"as":"this","set":[{"backgroundColor":[{"smallNumber":3}]}]},
{"as":"that","set":[{"flipX":[{"smallNumber":1}]}]},
{"as":"target","set":[{"x":[{"smallNumber":48}]}]},
{"as":"allSprites","set":[{"textColor":[{"smallNumber":5}]}]},
{"id":"D","set":[{"text":[{"as":"keyboard","attribute":"buttonA"}]}]},
{"id":"E","set":[{"text":[{"as":"songRow","attribute":"M0"}]}]},
{"as":"scene","set":[{"value0":[{"string":"HELLO SCENE!"}]}]},
{"as":"game","set":[{"value0":[{"string":"HELLO GAME!"}]}]}
]
}
]
}
]
}
]
}]
}
There is a lot going on the screen... and some audio is even playing!
This time we need to have a look at the debugger status too below the game screen:
Let's explain the code step by step. First of all, let's play the cartridge without any code
.
Sprites A
and C
are drawn one on top of the other so the I'M A!
and I'M C!
messages are not clearly readable. All of the other sprites are regularly in their position. The looping song A
started by tilemaps
and is playing in the background.
Now let's add some code:
{
"when":[{"flags":"F"}],
"then":[
{"set":[{"text":[{"string":"I HAVE FLAG F!"}]}]}
]
}
This when
code iterates all the spawned sprites having the F
flag one by one. The following code line is going to set
the text
of some object. Like any other line of code, this one is a getter too and since it's not using any direct getter the line is getting this
- which are F
flagged sprites, one by one. Sprite A
and B
text
is now changed. Notice that the I'M C!
message is still there since C
has no F
flag.
Let's add some more code:
{
"when":[{"flags":"F"}],
"then":[
{"set":[{"text":[{"string":"I HAVE FLAG F!"}]}]},
{
"code":[
{
"when":[{"id":"A","if":[{"is":"collidingWith","id":"C"}]}],
"then":[
{"as":"this","set":[{"backgroundColor":[{"smallNumber":3}]}]},
{"as":"that","set":[{"flipX":[{"smallNumber":1}]}]}
]
}
]
}
]
}
The code
statement is executing some sub-code in which we're going to check if the A
sprite is colliding with the C
sprite. Keep in mind that the this
getter is getting the F
flagged sprites here, as we have seen in the previous example. We're going to use this information in the next example.
Since A
and C
are one on top of each other they are colliding and the then
code is executed: the getter this
picks all of the colliding sprite (that's our A
sprite) and changes its backgroundColor
and the getter that
picks all of the collided sprites (that's the C
sprite) and flips its letters horizontally. That's why you're seeing mirrored letters in I'M C!
and a green background under the first I HAVE FLAG F!
.
Notice that the this
getter could be omitted since it's the default getter for any line of code.
More code again:
{
"when":[{"flags":"F"}],
"then":[
{"set":[{"text":[{"string":"I HAVE FLAG F!"}]}]},
{
"code":[
{
"when":[{"id":"A","if":[{"is":"collidingWith","id":"C"}]}],
"then":[
{"as":"this","set":[{"backgroundColor":[{"smallNumber":3}]}]},
{"as":"that","set":[{"flipX":[{"smallNumber":1}]}]},
{"as":"target","set":[{"x":[{"smallNumber":48}]}]},
{"as":"allSprites","set":[{"textColor":[{"smallNumber":5}]}]},
{"id":"D","set":[{"text":[{"as":"keyboard","attribute":"buttonA"}]}]},
{"id":"E","set":[{"text":[{"as":"songRow","attribute":"M0"}]}]}
]
}
]
}
]
}
It looks like the final screenshot we displayed before!
The target
getter is referencing the this
of the previous sub-code execution, that's the code
statement we added the previous example. Do you remember what the this
was getting during the code
call of before? Exactly! They were the F
flagged sprites and that's why changing the x
coordinates of the target
sprites will move them.
Then the allSprites
getter gets all the spawned sprites and sets its textColor
to the color 5
of the palette, making all the text
on the screen red.
The D
sprite now displaying a 0
but... try holding down the button A (that's mapped on the Z
key of your keyboard). The number will raise! That's because the code is setting the D
sprite text
to the buttonA
sub-value of the keyboard
object which contains for how many game frames the button has been held down.
Finally, the E
sprite is displaying... the note the song player is currently playing! The direct getter songRow
gets the current row of notes played by the song player and its key M0
returns the note on the first row. If you want to know more about music
and songs
have a look at data blocks.
Let's add the last two lines:
{
"when":[{"flags":"F"}],
"then":[
{"set":[{"text":[{"string":"I HAVE FLAG F!"}]}]},
{
"code":[
{
"when":[{"id":"A","if":[{"is":"collidingWith","id":"C"}]}],
"then":[
{"as":"this","set":[{"backgroundColor":[{"smallNumber":3}]}]},
{"as":"that","set":[{"flipX":[{"smallNumber":1}]}]},
{"as":"target","set":[{"x":[{"smallNumber":48}]}]},
{"as":"allSprites","set":[{"textColor":[{"smallNumber":5}]}]},
{"id":"D","set":[{"text":[{"as":"keyboard","attribute":"buttonA"}]}]},
{"id":"E","set":[{"text":[{"as":"songRow","attribute":"M0"}]}]},
{"as":"scene","set":[{"value0":[{"string":"HELLO SCENE!"}]}]},
{"as":"game","set":[{"value0":[{"string":"HELLO GAME!"}]}]}
]
}
]
}
]
}
Nothing changes on the screen but let's have a look at the debugger status:
The scene
getter gets the scene object and changes its value0
key to HELLO SCENE!
and the game
getter changes the value0
of the game object instead.
Another kind of getters we've seen a lot around this manual examples are the constructors.
Constructors can get primitive values like characters, text strings, numbers, and lists. You can use them to construct a value on the fly and change a sprite key from your code
in order to change its text
, movement speed, color, etc.
There are a lot of constructor getters in Rewtro but luckily you're not going to use all of them... and there is the _
special symbol that guesses the constructor you need for you, so you'll going to forget about them soon. But cool people know internals and learning them may give you some flexibility in the future.
There are two types of text getters: character
which gets a single symbol and string
that gets a string of symbols. While the string
getter can be used for getting a single symbol too it occupies a little more space in your data storage so use the character
getter as much as you can.
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"code":[{
"then":[
{"as":"game","set":[{
"value0":[{"character":"1"}],
"value1":[{"character":"A"}],
"value2":[{"string":"SOME TEXT!"}]
}]}
]
}]
}]
}
This cartridge does nothing on the screen but sets some text into the game object variables. Let's have a look at the debugger status:
The code
gets the single character
1
and assign it to the game
object key value0
, the single character
A
to value1
and gets the string
SOME TEXT!
to set value3
.
In order to use the fitting amount of space when storing a number in your cartridge, there are a lot of number getters in Rewtro. They work all the same way except for the range and type of numbers they can get. From the smallest cartridge space to the largest one there are:
smallNumber
gets values from0
to127
number
gets values from0
to255
smallInteger
gets values from-127
to128
integer
gets values from-511
to512
float
gets single decimal float number from-25
to26.1
largeNumber
gets values from0
to2047
Choosing the right getter may be difficult and that's why I strongly suggest you use the _
special symbol instead of these getters.
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"code":[{
"then":[
{"as":"game","set":[{
"value0":[{"smallNumber":127}],
"value1":[{"number":255}],
"value2":[{"smallInteger":-127}],
"value3":[{"integer":512}],
"value4":[{"float":26.1}],
"value5":[{"largeNumber":2047}]
}]}
]
}]
}]
}
The different numbers are get and set to the game object keys.
There are three ways to get lists in Rewtro:
- An empty one with
emptyList
- A set of numbers from
-511
to512
withnumbers
- A single list of numbers from
-511
to512
withlist
The list
gets a single object that collects all of the numbers while numbers
get all its numbers, one by one. You can read more about lists in the list and iterators chapter.
I'll try to explain numbers
and list
with an example.
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"sprites":[
{"id":"A"},
{"id":"B","x":0,"y":8},
{"id":"C","x":0,"y":16}
],
"tilemaps":[{"map":["ABC"]}],
"code":[{
"then":[
{"id":"A","set":[{"text":[{"numbers":[2,4,6,3],"count":true}]}]},
{"id":"B","set":[{"text":[{"numbers":[2,4,6,3],"max":true}]}]},
{
"numbers":[2,4,6,3],
"code":[{
"then":[{"id":"C","set":[{"text":[{"as":"target"}]}]}]
}]
}
]
}]
}]
}
The A
sprite says that the set of numbers created by numbers
is 4 elements long and B
that's the highest value is 6. The iterator fetches the list and set them one by one to the C
sprite text
but, since the screen is rendered after the code execution, we will just see the last number, that's 3
.
Replacing all of the instances of numbers
with list
to the same example the results are very different:
This time we're getting a single list of numbers and that's why the A
sprite is showing an element count of 1: there is just one list. The highest value displayed by B
is the list itself since it's the only element we got and the same goes for the iterator: it iterates just the whole list object once and sets it to the C
sprite text.
It looks like that the list
getter is not so useful and counterintuitive... and that's right in most of the cases. But sometimes you don't need to process a list of values in the very moment it's created. You may want to create a list for later use.
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"sprites":[
{"id":"A"},
{"id":"B","x":0,"y":8},
{"id":"C"}
],
"tilemaps":[{"map":["AB"]}],
"code":[
{
"when":[{"as":"scene","if":[{"itsAttribute":"timer","is":"==","smallNumber":"0"}]}],
"then":[
{"spawn":[{"ids":[{"character":"C"}],"at":[{"list":[8,24]}]}]},
{"id":"A","set":[{"value0":[{"list":[1,6]}]}]},
{"id":"B","set":[{"value0":[{"list":[100,200]}]}]},
{"id":"C","set":[{"value0":[{"list":[200,250]}]}]}
]
},
{
"when":[{"as":"allSprites"}],
"then":[{
"set":[{"text":[{"attribute":"value0","randomNumber":true}]}]
}]
}
]
}]
}
This cartridge spawn 3 sprites that works like dices: every game frame they will display a random number. The A
sprite values ranges from 1 to 6, the B
sprite ones from 100 to 200 and the C
sprite values are from 200 to 250.
These 3 different dices are rolled by the same single line of code (the one with randomNumber
on it) and that's possible because we are setting each dice range using the list
getter: when the game starts the A
, B
, and C
sprites key value0
is set to a list
which describes the range of values of each dice, from the lowest number one to the highest one. But we don't want to use the list in the very moment it's assigned: ranges will be used later to generate a random number and that's why we used the list
getter to assign a list of values to every sprite.
The iterator will fetches allSprites
one by one and sets their text
to a random number into the range found in value0
key. Since all value0
ranges are different for each sprite a different kind of random number is generated for each one.
The C
sprite is spawned in a quite peculiar way. Instead of being spawned by tilemaps
it's spawned by code
using the spawn
statement. In this case, the list
is used to set the spawn coordinates. The list
getter is also used by some special statements, like spawn
.
Finally, you can get an empty value with the undefined
key. Just set the undefined
key to true
. You'll rarely need this.
Getting a sprite, a list, or a special object it's nice... but most of the time you'll need to manipulate one of its key values: changing a sprite speedX
can change its direction, timing a backgroundColor
can make a sprite blink, etc. Sub-getters are special getters that get key values from the current picked object.
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"sprites":[
{"id":"A","text":"HELLO!"},
{"id":"B","x":8,"y":8,"textColor":3}
],
"tilemaps":[{"map":["AB"]}],
"code":[{
"then":[
{"id":"B","set":[{"text":[{"id":"A","attribute":"text"}]}]}
]
}]
}]
}
This cartridge displays the HELLO!
text
using sprite A
and then copies its text
key to sprite B
via code
.
Let's explain this block:
{"id":"A","attribute":"text"}
The getter id
gets the sprite with id
A
and then the sub-getter attribute
gets its text
key value, which is HELLO!
. This value is then set
to the text
key of B
sprite, copying its value.
The attribute
sub-getter gets the key value of any of the sprite attributes from the picked object. Just set its value to the attribute you want.
In the previous example, we used the attribute
sub-getter to get the text
key of a sprite.
{"id":"A","attribute":"text"}
Changing text
to id
...
...will copy the A
sprite id
instead, which is... A
.
Some objects may have some special attributes sprites don't have. Let's see them.
The keyboard
special object holds the game controller status. In order to query a specific button, you've to set the attribute
sub-getter to up
, down
, left
, right
, buttonA
, buttonB
, buttonC
, or buttonD
. The button's availability depends on the system configuration of your game.
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"sprites":[
{"id":"A"},
{"id":"B","backgroundColor":5,"restitutionX":0,"restitutionY":0,"x":76,"y":68}
],
"tilemaps":[{"map":["AB"]}],
"code":[
{
"when":[{"as":"keyboard","attribute":"left","if":[{"is":"down"}]}],
"then":[{"id":"B","set":[{"speedX":[{"smallInteger":-5}]}]}]
},
{
"when":[{"as":"keyboard","attribute":"right","if":[{"is":"down"}]}],
"then":[{"id":"B","set":[{"speedX":[{"smallInteger":5}]}]}]
},
{
"when":[{"as":"keyboard","attribute":"up","if":[{"is":"down"}]}],
"then":[{"id":"B","set":[{"speedY":[{"smallInteger":-5}]}]}]
},
{
"when":[{"as":"keyboard","attribute":"down","if":[{"is":"down"}]}],
"then":[{"id":"B","set":[{"speedY":[{"smallInteger":5}]}]}]
},
{
"then":[
{"id":"A","set":[{"text":[{"as":"keyboard","attribute":"buttonA"}]}]}
]
}
]
}]
}
This cartridge shows a controllable red square in the middle of the screen! There is also a number on the top left of the screen: holding down the button A of your game controller increases that number. If you're playing this example using the debugger hold the up/down/left/right keys for moving the square around and the Z key for changing the number.
The special object keyboard
is used together with the attribute
sub-getter to get the up
, down
, left
, and right
keys and change the B
sprite speed. The number on the top left of the screen reveals what the keyboard
keys are containing: there are numbers that go up when holding one button down and then go back to 0
when that button is released.
The songRow
special object knows which notes are actually played by the song player. Quite like the keyboard
special object, you can query the status of a single row setting the attribute
key to M0
, M1
, M2
, M3
, M4
, M5
, M6
, M7
, M8
, or M9
.
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"sounds":[
{"id":"A","wave":"triangle"},
{"id":"B","wave":"whitenoise"}
],
"music":[
{
"id":"A",
"notes":[
["C4-","D4-","E4-","F4-","G4-","F4-","E4-","D4-"],
["C4-"," ","G7-"," ","C4-"," ","G7-"," "]
],"instruments":"AB"}
],
"songs":[
{"id":"A","loopTo":0,"music":"A","tempo":5}
],
"sprites":[
{"id":"A"},
{"id":"B","x":0,"y":16}
],
"tilemaps":[{"map":["AB"],"song":"A"}],
"code":[
{
"then":[
{"id":"A","set":[{"text":[{"as":"songRow","attribute":"M0"}]}]},
{"id":"B","set":[{"text":[{"as":"songRow","attribute":"M1"}]}]}
]
}
]
}]
}
This cartridge plays a simple song and a beat. The screen displays the notes played in real time.
The M0
sub-getter gets the currently playing notes on the first row of the music
, that's the theme, and M1
the ones from the second row of the music
, that's the beat. The code
block will assign these values to A
and B
text
keys, making them appear on the screen.
Notice that the notes read from songRow
are 4 symbols long instead of 3: the first letter is the instrument id
that's playing that note.
There is a number of sub-getters you can use to work with a set of elements:
max
gets the maximum number of the set.min
gets the maximum number of the set.count
gets the number of elements of the set.oneRandom
gets a random element of the set.
...and others that operate on a single list of elements:
index
gets an element at a specific position of the list and uses another getter to decide the position.randomValue
gets a random element picked from the list.randomNumber
gets a random integer number between the first list element and the second list element included.
Some objects may have a single list of elements as key values, like the touchUp
or touchLeft
keys we've seen in sprite attributes or when setting a list
to a sprite key like in the list
and numbers
example of this chapter.
The sublist
getter goes inside a single list of elements turning it in a set of elements. This way you can use iterators and max
, min
, and count
sub-getters on its elements.
I've another example that may be a little hard. I'll try my best on explaining:
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"sprites":[
{"id":"A"},
{"id":"B","x":0,"y":8},
{"id":"C","x":0,"y":16},
{"id":"D","x":0,"y":24},
{"id":"E","x":0,"y":40},
{"id":"F","x":0,"y":48},
{"id":"G","x":0,"y":56},
{"id":"H","x":0,"y":72},
{"id":"I","x":0,"y":80},
{"id":"J","x":0,"y":96},
{"id":"K","x":0,"y":104}
],
"tilemaps":[{"map":["ABCDEFGHIJK"]}],
"code":[
{
"then":[
{"id":"A","set":[{"text":[{"numbers":[2,6,4,1,10],"count":true}]}]},
{"id":"B","set":[{"text":[{"numbers":[2,6,4,1,10],"min":true}]}]},
{"id":"C","set":[{"text":[{"numbers":[2,6,4,1,10],"max":true}]}]},
{"id":"D","set":[{"text":[{"numbers":[2,6,4,1,10],"oneRandom":true}]}]},
{"id":"E","set":[{"text":[{"list":[2,6,4,1,10],"index":[{"smallNumber":2}]}]}]},
{"id":"F","set":[{"text":[{"list":[2,6,4,1,10],"randomNumber":true}]}]},
{"id":"G","set":[{"text":[{"list":[2,6,4,1,10],"randomValue":true}]}]},
{"id":"A","set":[{"value0":[{"list":[1,2,3,4,5]}]}]},
{"id":"H","set":[{"text":[{"id":"A","attribute":"value0","count":true}]}]},
{"id":"I","set":[{"text":[{"id":"A","sublist":"value0","count":true}]}]},
{
"id":"A","attribute":"value0",
"code":[{"then":[{"id":"J","set":[{"text":[{"as":"that"}]}]}]}]
},{
"id":"A","sublist":"value0",
"code":[{"then":[{"id":"K","set":[{"text":[{"as":"that"}]}]}]}]
}
]
}
]
}]
}
This cartridge does a lot of stuff:
Let's explain the code
line by line:
-
As we've seen before
numbers
gets a set of elements so calling its sub-gettercount
will result on the elements count of the set, that's5
. -
The same happens for the
min
imum value of the set, that's1
... -
...and the
max
imum one, that's10
. -
The
oneRandom
gets a random element from the set. -
Then the
list
key creates a single list of elements this time and the sub-getterindex
gets its2
nd element, that's 4. (positions starts from 0) -
The next line generates a
randomNumber
from2
to6
, ignoring the other values... -
...and the next one picks any
randomValue
from thelist
. -
Then a
list
, that's a single list of elements, is set to thevalue0
of spriteA
. -
The next line uses the
attribute
to get that list and prints thecount
sub-getter. The result is1
because we are manipulating a single list of elements but... -
...the
sublist
getter it goes inside the list instead, turning thelist
from a single list of elements to a set of elements. That's why thecount
subkey returns5
this time. -
The iterators work the same. Using the
attribute
getter there will be just one iteration on the single list object so the wholelist
is printed... -
...but the
sublist
sub-getter goes inside the list and iterates its element one by one. Even if all of the list elements are iterated one by one we will just see the last element5
because the screen frame is rendered just when the code has been fully executed.
Take your time to understand how a set of elements and a single list of elements works and how their sub-getters behave and feel free to experiment. After working on some games you'll get when the difference matters and eventually forget everything about the internals. Nothing to see here. Let's move on.
Some sub-getters accept another getter and calculate a relation between the picked sprite and them.
angleTo
returns the angle between the currently picked sprite and the specified getter.distanceTo
returns the distance between the currently picked sprite and the specified getter.nearest
returns the nearest sprite of the specified getter.farthest
returns the farthest sprite of the specified getter.
The inArea
sub-getter accepts an object that describes a rectangular area and returns the subset of the picked sprites that are into that area. The area is described this way:
x
is a getter that defines the vertical position of the area.y
is a getter that defines the horizontal position of the area.width
is a getter that defines the width of the area.height
is a getter that defines the height of the area.
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"sprites":[
{"id":"A","x":76,"y":68,"backgroundColor":2,"text":"A"},
{"id":"B","flags":"F","backgroundColor":5,"restitutionX":0,"restitutionY":0,"x":76,"y":44,"text":"B"},
{"id":"C","flags":"F","backgroundColor":6,"x":108,"y":100,"text":"C"},
{"id":"D","x":0,"y":0},
{"id":"E","x":0,"y":8},
{"id":"F","x":0,"y":16},
{"id":"G","x":0,"y":24},
{"id":"H","x":0,"y":32}
],
"tilemaps":[{"map":["ABCDEFGH"]}],
"code":[
{
"then":[
{"id":"D","set":[{"text":[{"id":"A","angleTo":[{"id":"B"}]}]}]},
{"id":"E","set":[{"text":[{"id":"A","distanceTo":[{"id":"B"}]}]}]},
{
"id":"A","nearest":[{"flags":"F"}],
"code":[{
"then":[{"id":"F","set":[{"text":[{"as":"that","attribute":"id"}]}]}]
}]
},
{
"id":"A","farthest":[{"flags":"F"}],
"code":[{
"then":[{"id":"G","set":[{"text":[{"as":"that","attribute":"id"}]}]}]
}]
},
{
"id":"H",
"set":[{
"text":[{"id":"B","inArea":[{
"x":[{"smallInteger":60}],
"y":[{"smallInteger":52}],
"width":[{"smallInteger":40}],
"height":[{"smallInteger":40}]
}],"count":true}]
}]
}
]
},
{
"when":[{"as":"keyboard","attribute":"left","if":[{"is":"down"}]}],
"then":[{"id":"B","set":[{"speedX":[{"smallInteger":-5}]}]}]
},
{
"when":[{"as":"keyboard","attribute":"right","if":[{"is":"down"}]}],
"then":[{"id":"B","set":[{"speedX":[{"smallInteger":5}]}]}]
},
{
"when":[{"as":"keyboard","attribute":"up","if":[{"is":"down"}]}],
"then":[{"id":"B","set":[{"speedY":[{"smallInteger":-5}]}]}]
},
{
"when":[{"as":"keyboard","attribute":"down","if":[{"is":"down"}]}],
"then":[{"id":"B","set":[{"speedY":[{"smallInteger":5}]}]}]
}
]
}]
}
This cartridge displays three squares labeled A
, B
, and C
. Moving the B
square with the controller the numbers on the top left of the screen changes:
The first line of code gets A
and calculates the angleTo
the sprite B
and display it on the first row on the screen. The second line does the same but calculates the distanceTo
the sprite B
and prints it on the second row.
The third and fourth lines of code are getting the sprite B
and then the nearest
or farthest
sprite with flag F
, which are the B
and C
sprite. The sprite is iterated and its id
is printed, so you'll see the nearest and farthest sprites id
on the third and fourth row of the screen.
The fifth line of code gets all the F
flagged sprites that are into the area at 60,52 with a width and height of 40 and then counts them. It's a squared area around the A
sprite, so moving the A
sprite near it the counter on the fifth row of the screen will go up to 1
and leaving it the counter will go down to 0
.
There are few sub-getters for text processing:
prefix
accepts a string of symbols and prepends some text to the picked value.suffix
accepts a string of symbols and appends some text to the picked value.
They are mostly used to make simple UI.
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"sprites":[
{"id":"A"},
{"id":"B","x":0,"y":8},
{"id":"C","x":0,"y":16}
],
"tilemaps":[{"map":["ABC"]}],
"code":[
{
"then":[
{"as":"scene","set":[{
"value0":[{"smallInteger":100}],
"value1":[{"smallInteger":3}],
"value2":[{"smallInteger":120}]
}]},
{"id":"A","set":[{"text":[{"as":"scene","attribute":"value0","prefix":"SCORE: "}]}]},
{"id":"B","set":[{"text":[{"as":"scene","attribute":"value1","suffix":" LIVES LEFT"}]}]},
{"id":"C","set":[{"text":[{"as":"scene","attribute":"value2","prefix":"BEST SCORE IS ","suffix":"!!"}]}]}
]
}
]
}]
}
The first line initializes the value0
, value1
, and value2
variables of the scene
. The following code shows how to add a prefix
, a suffix
, and both of them in order to make a simple game UI.
Rewtro supports a number of number processing sub-getters that applies a function on the picked number. To enable them just set their key to true
.
abs
returns the absolute value of the picked number. On both-3
and3
it returns3
.sqrt
returns the square root of the picked value. On9
it returns3
.sin
returns the sine of the picked value. On0
it returns0
.cos
returns the cosine of the picked value. On0
it returns1
.acos
returns the arccosine of the picked value. On0
it returns1.5707...
.floor
returns the largest integer less than or equal to the picked value. On both1.9
and1.3
it returns1
.negate
returns the logic not of the value. On0
it returns1
and for any other value returns0
.ceil
(Rewtro v0.3++) always rounds the picked value up to the next largest whole number or integer. On both1.9
and1.3
returns2
.round
(Rewtro v0.3++) returns the value of a number rounded to the nearest integer. On1.9
returns2
but on1.3
returns1
.
These sub-getters are quite straightforward and boring. Let's try making an interesting example out of it:
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"sprites":[
{"id":"A","backgroundColor":4,"height":144}
],
"tilemaps":[{
"y":68,
"map":["AAAAAAAAAAAAAAAAAAAA"]
}],
"code":[
{
"when":[{"id":"A"}],
"then":[
{
"set":[{"value0":[{"attribute":"x"}]}],
"sum":[{"value0":[{"attribute":"timer"}]}],
"divide":[{"value0":[{"smallInteger":10}]}]
},
{
"sum":[{"y":[{"attribute":"value0","sin":true}]}]
}
]
}
]
}]
}
This cartridge show an animated rough sea!
The tilemaps
spawn a row of A
sprites in the middle of the screen. Each A
sprite is a tall blue rectangle. Then the code
iterates all of them and copies its x
position into value0
and then sum
their timer
. That makes the value0
a number that has a growing starting value depending on the sprite x
position and goes up over time. The divide
statement smoothes the value0
a little.
The resulting value0
is sum
to each sprite y
moving them vertically, but first sin
sub-getter is applied making value0
a number oscillating between -1
and 1
. Since value0
starting value is different for each sprite x
a wavy pattern is displayed. Adding the timer
value every frame will keep increasing `value0' over time animating our sea.
While getting a number can ensure that's within a range adding the limit
sub-getter. It accepts two numbers from -127
to 128
that are the lowest and highest allowed number.
{
"systemVersion":"0.2",
"metadata":{
"title":"My first game"
},
"data":[{
"id":"A",
"sprites":[
{"id":"A"},
{"id":"B","x":0,"y":8}
],
"tilemaps":[{"map":["AB"]}],
"code":[
{
"then":[
{"id":"A","set":[{"text":[{"as":"scene","attribute":"timer","limit":[0,80]}]}]},
{"id":"B","set":[{"text":[{"as":"scene","attribute":"timer","limit":[50,100]}]}]}
]
}
]
}]
}
This cartridge shows two numbers going up:
The first number will go from 0
to 50
alone. Then the two numbers will go together from 50
to 80
and finally the first one will stop and the second one will go to 100
. That's because the code
show the same timer but applying two different limit
to them.
Getters are executed following a fixed order. This is the list of all getters and sub-getters sorted by execution priority.
- Main getter
emptyList
integer
smallinteger
number
smallnumber
float
largenumber
list
string
character
numbers
undefined
ids
orid
flags
idByName
flagsByName
as
- Sub-getters
distanceTo
angleTo
nearest
orfarthest
inArea
oneRandom
sublist
attribute
randomValue
randomNumber
index
sqrt
sin
cos
acos
limit
negate
abs
floor
ceil
round
max
min
count
prefix
suffix
_DEBUG