http://wiki.spheredev.org/api.php?action=feedcontributions&user=Radnen&feedformat=atomSpherical wiki - User contributions [en]2024-03-29T11:22:38ZUser contributionsMediaWiki 1.29.0http://wiki.spheredev.org/index.php?title=Tile_Movement&diff=1161Tile Movement2014-03-04T10:56:56Z<p>Radnen: /* Bonus: adding a sound */ simplified sound portion</p>
<hr />
<div>[[Category:Tutorials]]<br />
<br />
This tutorial is for beginners on up. So, you are wondering how to make a good tile movement system for your game? In Sphere it's not that hard and can be made as a natural extension of the map engine. You will need to know how to integrate existing systems into your game, and understand how Sphere's SetUpdateScript works.<br />
<br />
--[[User:Radnen|Radnen]] ([[User talk:Radnen|talk]]) 05:55, 4 March 2014 (UTC)<br />
<br />
== Step 0: the class ==<br />
<br />
As you set up any system, we need a ''class'' to hold the information. In JavaScript we can do so by creating a new function.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
}<br />
</syntaxhighlight><br />
<br />
== Step 1: the ''listener'' ==<br />
<br />
The next thing we do is create what I call a ''listener''. It's code that must run always in an update loop. A listener in specific is something that must run all the time, but does nothing until you hit a key or a button or something. We add it to our tile movement system like so:<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
}<br />
<br />
TileSystem.prototype.update = function() {<br />
}<br />
</syntaxhighlight><br />
<br />
When the player hits the movement keys, it should move the entity. We know what the entity is by the '''this.input''' field. We first want to wait until the person is no longer moving, by using the function IsCommandQueueEmpty(). If the queue is not empty we return early, letting it do nothing. If the command queue is empty then we are good for seeing if we can move the player left or right, up or down by hitting those 4 keys respectively.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || !IsCommandQueueEmpty(this.input)) return;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) // move left<br />
else if (IsKeyPressed(KEY_RIGHT)) // move right<br />
else if (IsKeyPressed(KEY_UP)) // move up<br />
else if (IsKeyPressed(KEY_DOWN)) // move down<br />
}<br />
</syntaxhighlight><br />
<br />
Good. We created a listener. Now, let's make it move the player.<br />
<br />
== Step 2: movement ==<br />
<br />
Adding movement means creating a new method stub called ''move'' which queues enough move commands to move the sprite in the given direction. We use the arrow keys to set that direction.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || !IsCommandQueueEmpty(this.input)) return;<br />
<br />
if (IsKeyPressed(KEY_LEFT )) this.move(COMMAND_MOVE_WEST);<br />
else if (IsKeyPressed(KEY_RIGHT)) this.move(COMMAND_MOVE_EAST); <br />
else if (IsKeyPressed(KEY_UP )) this.move(COMMAND_MOVE_NORTH);<br />
else if (IsKeyPressed(KEY_DOWN )) this.move(COMMAND_MOVE_SOUTH);<br />
}<br />
<br />
TileSystem.prototype.move = function(command) {<br />
var pixels = GetTileWidth();<br />
for (var i = 0; i < pixels; ++i) {<br />
QueuePersonCommand(this.input, command, false);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
Good. We are almost done. The last major step is to figure out facing.<br />
<br />
== Step 3: facing ==<br />
<br />
Facing is best done adding on to the directional keys, and queuing a face command in the same direction as the move command.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || !IsCommandQueueEmpty(this.input)) return;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_WEST, true);<br />
this.move(COMMAND_MOVE_WEST);<br />
}<br />
else if (IsKeyPressed(KEY_RIGHT)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_EAST, true);<br />
this.move(COMMAND_MOVE_EAST);<br />
}<br />
else if (IsKeyPressed(KEY_UP)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_NORTH, true);<br />
this.move(COMMAND_MOVE_NORTH);<br />
}<br />
else if (IsKeyPressed(KEY_DOWN)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_SOUTH, true);<br />
this.move(COMMAND_MOVE_SOUTH);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
== Step 4: overwriting Sphere ==<br />
<br />
Sphere uses the movement keys internally for movement, and we must stop that from happening. We can do this by binding the 4 keys to nothing.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
<br />
BindKey(KEY_UP, '', '');<br />
BindKey(KEY_DOWN, '', '');<br />
BindKey(KEY_LEFT, '', '');<br />
BindKey(KEY_RIGHT, '', '');<br />
}<br />
</syntaxhighlight><br />
<br />
This step was crucial since Sphere would still try to move the sprite per pixel rather than our newer per tile method. <br />
<br />
== Step 5: using it ==<br />
<br />
Good, at this stage you have a basic tile mover ready to go. Now, how do you use it? We make a new instance of TileMover, giving it the name of our attached entity, and set an update script, like so.<br />
<br />
<syntaxhighlight><br />
RequireScript('tilemover.js'); // or however you saved it<br />
<br />
var my_mover = new TileMover("player");<br />
<br />
function game() {<br />
SetUpdateScript("my_mover.update()");<br />
CreatePerson("player");<br />
AttachInput("player");<br />
AttachCamera("player");<br />
MapEngine("map.rmp", 60);<br />
}<br />
</syntaxhighlight><br />
<br />
And that's it!<br />
<br />
== Intermediate: checking obstructions ==<br />
<br />
If you are using a map that does not have tile based collisions, then checking collisions can get tricky. If you followed the tutorial up until now, you'll notice that it is possible to walk 'off tile' so to speak. In order to make sure the player always stays on tile, we can employ a check to make sure it only walks if the next tile is clear.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.check = function(command) {<br />
var x = GetPersonX(this.input);<br />
var y = GetPersonY(this.input);<br />
<br />
switch(command) {<br />
case COMMAND_MOVE_NORTH: y -= GetTileHeight(); break;<br />
case COMMAND_MOVE_SOUTH: y += GetTileHeight(); break;<br />
case COMMAND_MOVE_EAST: x += GetTileWidth(); break;<br />
case COMMAND_MOVE_WEST: x -= GetTileWidth(); break;<br />
}<br />
<br />
return IsPersonObstructed(this.input, x, y);<br />
}<br />
</syntaxhighlight><br />
<br />
So, how does this work? It checks the next tile in the direction the person is walking and returns false if there is no obstruction and true if there is anything in the way. This is so far, just the check. Now we should go add it like so.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || !IsCommandQueueEmpty(this.input)) return;<br />
<br />
var command = null;<br />
var face = null;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) {<br />
face = COMMAND_FACE_WEST;<br />
command = COMMAND_MOVE_WEST;<br />
}<br />
else if (IsKeyPressed(KEY_RIGHT)) {<br />
face = COMMAND_FACE_EAST;<br />
command = COMMAND_MOVE_EAST;<br />
}<br />
else if (IsKeyPressed(KEY_UP)) {<br />
face = COMMAND_FACE_NORTH;<br />
command = COMMAND_MOVE_NORTH;<br />
}<br />
else if (IsKeyPressed(KEY_DOWN)) {<br />
face = COMMAND_FACE_SOUTH;<br />
command = COMMAND_MOVE_SOUTH;<br />
}<br />
<br />
if (command != null && !this.check(command)) {<br />
if (face != null) QueuePersonCommand(this.input, face, true);<br />
this.move(command);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
What this does is ''defer'' the command until we check the direction. If all is good, we are allowed to move. Otherwise it returns doing nothing.<br />
<br />
=== Bonus: adding a sound ===<br />
<br />
Alright you got it to check if something is blocking in the way. Now you are wondering like how it is in Pokémon that it creates a sound when you hit something? First we should load that sound up when we create our tile mover, like so. You can use [http://www.bfxr.net/ bfxr] to create the thump sound.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input, sound) {<br />
this.input = input;<br />
this.sound = sound;<br />
<br />
BindKey(KEY_UP, '', '');<br />
BindKey(KEY_DOWN, '', '');<br />
BindKey(KEY_LEFT, '', '');<br />
BindKey(KEY_RIGHT, '', '');<br />
}<br />
</syntaxhighlight><br />
<br />
Next we can add the sound by slightly modifying the move section of the update loop.<br />
<br />
<syntaxhighlight><br />
if (command != null) {<br />
if (this.check(command)) {<br />
if (this.sound) this.sound.play();<br />
command = COMMAND_ANIMATE;<br />
}<br />
if (face != null) QueuePersonCommand(this.input, face, true);<br />
this.move(command);<br />
}<br />
</syntaxhighlight><br />
<br />
And that's it! I add the animate command to make it still appear as if the sprite were walking in place; otherwise he's just standing still.<br />
<br />
== Appendix: full code ==<br />
<br />
More advanced systems can always be made. They are simply, too much to go into detail here but all of them would be built off a method similar to this. So, feel free to add your own things to this if you want.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input, sound) {<br />
this.input = input;<br />
this.sound = sound;<br />
<br />
BindKey(KEY_UP, '', '');<br />
BindKey(KEY_DOWN, '', '');<br />
BindKey(KEY_LEFT, '', '');<br />
BindKey(KEY_RIGHT, '', '');<br />
}<br />
<br />
TileSystem.prototype.update = function() {<br />
if (!this.input || !IsCommandQueueEmpty(this.input)) return;<br />
<br />
var command = null;<br />
var face = null;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) {<br />
face = COMMAND_FACE_WEST;<br />
command = COMMAND_MOVE_WEST;<br />
}<br />
else if (IsKeyPressed(KEY_RIGHT)) {<br />
face = COMMAND_FACE_EAST;<br />
command = COMMAND_MOVE_EAST;<br />
}<br />
else if (IsKeyPressed(KEY_UP)) {<br />
face = COMMAND_FACE_NORTH;<br />
command = COMMAND_MOVE_NORTH;<br />
}<br />
else if (IsKeyPressed(KEY_DOWN)) {<br />
face = COMMAND_FACE_SOUTH;<br />
command = COMMAND_MOVE_SOUTH;<br />
}<br />
<br />
if (command != null) {<br />
if (this.check(command)) {<br />
if (this.sound) this.sound.play();<br />
command = COMMAND_ANIMATE;<br />
}<br />
if (face != null) QueuePersonCommand(this.input, face, true);<br />
this.move(command);<br />
}<br />
}<br />
<br />
TileSystem.prototype.check = function(command) {<br />
var x = GetPersonX(this.input);<br />
var y = GetPersonY(this.input);<br />
<br />
switch(command) {<br />
case COMMAND_MOVE_NORTH: y -= GetTileHeight(); break;<br />
case COMMAND_MOVE_SOUTH: y += GetTileHeight(); break;<br />
case COMMAND_MOVE_EAST: x += GetTileWidth(); break;<br />
case COMMAND_MOVE_WEST: x -= GetTileWidth(); break;<br />
}<br />
<br />
return IsPersonObstructed(this.input, x, y);<br />
}<br />
<br />
TileSystem.prototype.move = function(command) {<br />
var pixels = GetTileWidth();<br />
for (var i = 0; i < pixels; ++i) {<br />
QueuePersonCommand(this.input, command, false);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
That's all there is to it! It ''seems'' like a lot of code, but really we had to handle 4 separate directions. I ''could'' condense this down a bit, but then it'd get harder to understand.</div>Radnenhttp://wiki.spheredev.org/index.php?title=Tile_Movement&diff=1160Tile Movement2014-03-04T10:55:08Z<p>Radnen: More minor code fixes</p>
<hr />
<div>[[Category:Tutorials]]<br />
<br />
This tutorial is for beginners on up. So, you are wondering how to make a good tile movement system for your game? In Sphere it's not that hard and can be made as a natural extension of the map engine. You will need to know how to integrate existing systems into your game, and understand how Sphere's SetUpdateScript works.<br />
<br />
--[[User:Radnen|Radnen]] ([[User talk:Radnen|talk]]) 05:55, 4 March 2014 (UTC)<br />
<br />
== Step 0: the class ==<br />
<br />
As you set up any system, we need a ''class'' to hold the information. In JavaScript we can do so by creating a new function.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
}<br />
</syntaxhighlight><br />
<br />
== Step 1: the ''listener'' ==<br />
<br />
The next thing we do is create what I call a ''listener''. It's code that must run always in an update loop. A listener in specific is something that must run all the time, but does nothing until you hit a key or a button or something. We add it to our tile movement system like so:<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
}<br />
<br />
TileSystem.prototype.update = function() {<br />
}<br />
</syntaxhighlight><br />
<br />
When the player hits the movement keys, it should move the entity. We know what the entity is by the '''this.input''' field. We first want to wait until the person is no longer moving, by using the function IsCommandQueueEmpty(). If the queue is not empty we return early, letting it do nothing. If the command queue is empty then we are good for seeing if we can move the player left or right, up or down by hitting those 4 keys respectively.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || !IsCommandQueueEmpty(this.input)) return;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) // move left<br />
else if (IsKeyPressed(KEY_RIGHT)) // move right<br />
else if (IsKeyPressed(KEY_UP)) // move up<br />
else if (IsKeyPressed(KEY_DOWN)) // move down<br />
}<br />
</syntaxhighlight><br />
<br />
Good. We created a listener. Now, let's make it move the player.<br />
<br />
== Step 2: movement ==<br />
<br />
Adding movement means creating a new method stub called ''move'' which queues enough move commands to move the sprite in the given direction. We use the arrow keys to set that direction.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || !IsCommandQueueEmpty(this.input)) return;<br />
<br />
if (IsKeyPressed(KEY_LEFT )) this.move(COMMAND_MOVE_WEST);<br />
else if (IsKeyPressed(KEY_RIGHT)) this.move(COMMAND_MOVE_EAST); <br />
else if (IsKeyPressed(KEY_UP )) this.move(COMMAND_MOVE_NORTH);<br />
else if (IsKeyPressed(KEY_DOWN )) this.move(COMMAND_MOVE_SOUTH);<br />
}<br />
<br />
TileSystem.prototype.move = function(command) {<br />
var pixels = GetTileWidth();<br />
for (var i = 0; i < pixels; ++i) {<br />
QueuePersonCommand(this.input, command, false);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
Good. We are almost done. The last major step is to figure out facing.<br />
<br />
== Step 3: facing ==<br />
<br />
Facing is best done adding on to the directional keys, and queuing a face command in the same direction as the move command.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || !IsCommandQueueEmpty(this.input)) return;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_WEST, true);<br />
this.move(COMMAND_MOVE_WEST);<br />
}<br />
else if (IsKeyPressed(KEY_RIGHT)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_EAST, true);<br />
this.move(COMMAND_MOVE_EAST);<br />
}<br />
else if (IsKeyPressed(KEY_UP)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_NORTH, true);<br />
this.move(COMMAND_MOVE_NORTH);<br />
}<br />
else if (IsKeyPressed(KEY_DOWN)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_SOUTH, true);<br />
this.move(COMMAND_MOVE_SOUTH);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
== Step 4: overwriting Sphere ==<br />
<br />
Sphere uses the movement keys internally for movement, and we must stop that from happening. We can do this by binding the 4 keys to nothing.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
<br />
BindKey(KEY_UP, '', '');<br />
BindKey(KEY_DOWN, '', '');<br />
BindKey(KEY_LEFT, '', '');<br />
BindKey(KEY_RIGHT, '', '');<br />
}<br />
</syntaxhighlight><br />
<br />
This step was crucial since Sphere would still try to move the sprite per pixel rather than our newer per tile method. <br />
<br />
== Step 5: using it ==<br />
<br />
Good, at this stage you have a basic tile mover ready to go. Now, how do you use it? We make a new instance of TileMover, giving it the name of our attached entity, and set an update script, like so.<br />
<br />
<syntaxhighlight><br />
RequireScript('tilemover.js'); // or however you saved it<br />
<br />
var my_mover = new TileMover("player");<br />
<br />
function game() {<br />
SetUpdateScript("my_mover.update()");<br />
CreatePerson("player");<br />
AttachInput("player");<br />
AttachCamera("player");<br />
MapEngine("map.rmp", 60);<br />
}<br />
</syntaxhighlight><br />
<br />
And that's it!<br />
<br />
== Intermediate: checking obstructions ==<br />
<br />
If you are using a map that does not have tile based collisions, then checking collisions can get tricky. If you followed the tutorial up until now, you'll notice that it is possible to walk 'off tile' so to speak. In order to make sure the player always stays on tile, we can employ a check to make sure it only walks if the next tile is clear.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.check = function(command) {<br />
var x = GetPersonX(this.input);<br />
var y = GetPersonY(this.input);<br />
<br />
switch(command) {<br />
case COMMAND_MOVE_NORTH: y -= GetTileHeight(); break;<br />
case COMMAND_MOVE_SOUTH: y += GetTileHeight(); break;<br />
case COMMAND_MOVE_EAST: x += GetTileWidth(); break;<br />
case COMMAND_MOVE_WEST: x -= GetTileWidth(); break;<br />
}<br />
<br />
return IsPersonObstructed(this.input, x, y);<br />
}<br />
</syntaxhighlight><br />
<br />
So, how does this work? It checks the next tile in the direction the person is walking and returns false if there is no obstruction and true if there is anything in the way. This is so far, just the check. Now we should go add it like so.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || !IsCommandQueueEmpty(this.input)) return;<br />
<br />
var command = null;<br />
var face = null;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) {<br />
face = COMMAND_FACE_WEST;<br />
command = COMMAND_MOVE_WEST;<br />
}<br />
else if (IsKeyPressed(KEY_RIGHT)) {<br />
face = COMMAND_FACE_EAST;<br />
command = COMMAND_MOVE_EAST;<br />
}<br />
else if (IsKeyPressed(KEY_UP)) {<br />
face = COMMAND_FACE_NORTH;<br />
command = COMMAND_MOVE_NORTH;<br />
}<br />
else if (IsKeyPressed(KEY_DOWN)) {<br />
face = COMMAND_FACE_SOUTH;<br />
command = COMMAND_MOVE_SOUTH;<br />
}<br />
<br />
if (command != null && !this.check(command)) {<br />
if (face != null) QueuePersonCommand(this.input, face, true);<br />
this.move(command);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
What this does is ''defer'' the command until we check the direction. If all is good, we are allowed to move. Otherwise it returns doing nothing.<br />
<br />
=== Bonus: adding a sound ===<br />
<br />
Alright you got it to check if something is blocking in the way. Now you are wondering like how it is in Pokémon that it creates a sound when you hit something? First we should load that sound up when we create our tile mover, like so. You can use [http://www.bfxr.net/ bfxr] to create the thump sound.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input, sound) {<br />
this.input = input;<br />
this.sound = sound;<br />
<br />
BindKey(KEY_UP, '', '');<br />
BindKey(KEY_DOWN, '', '');<br />
BindKey(KEY_LEFT, '', '');<br />
BindKey(KEY_RIGHT, '', '');<br />
}<br />
</syntaxhighlight><br />
<br />
Next we can add the sound by slightly modifying the move section of the update loop.<br />
<br />
<syntaxhighlight><br />
if (command != null)<br />
if(!this.check(command)) {<br />
if (face != null) QueuePersonCommand(this.input, face, true);<br />
this.move(command);<br />
}<br />
else {<br />
this.sound.play();<br />
this.move(COMMAND_ANIMATE);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
And that's it! I add the animate command to make it still appear as if the sprite were walking in place; otherwise he's just standing still.<br />
<br />
== Appendix: full code ==<br />
<br />
More advanced systems can always be made. They are simply, too much to go into detail here but all of them would be built off a method similar to this. So, feel free to add your own things to this if you want.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input, sound) {<br />
this.input = input;<br />
this.sound = sound;<br />
<br />
BindKey(KEY_UP, '', '');<br />
BindKey(KEY_DOWN, '', '');<br />
BindKey(KEY_LEFT, '', '');<br />
BindKey(KEY_RIGHT, '', '');<br />
}<br />
<br />
TileSystem.prototype.update = function() {<br />
if (!this.input || !IsCommandQueueEmpty(this.input)) return;<br />
<br />
var command = null;<br />
var face = null;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) {<br />
face = COMMAND_FACE_WEST;<br />
command = COMMAND_MOVE_WEST;<br />
}<br />
else if (IsKeyPressed(KEY_RIGHT)) {<br />
face = COMMAND_FACE_EAST;<br />
command = COMMAND_MOVE_EAST;<br />
}<br />
else if (IsKeyPressed(KEY_UP)) {<br />
face = COMMAND_FACE_NORTH;<br />
command = COMMAND_MOVE_NORTH;<br />
}<br />
else if (IsKeyPressed(KEY_DOWN)) {<br />
face = COMMAND_FACE_SOUTH;<br />
command = COMMAND_MOVE_SOUTH;<br />
}<br />
<br />
if (command != null) {<br />
if (this.check(command)) {<br />
if (this.sound) this.sound.play();<br />
command = COMMAND_ANIMATE;<br />
}<br />
if (face != null) QueuePersonCommand(this.input, face, true);<br />
this.move(command);<br />
}<br />
}<br />
<br />
TileSystem.prototype.check = function(command) {<br />
var x = GetPersonX(this.input);<br />
var y = GetPersonY(this.input);<br />
<br />
switch(command) {<br />
case COMMAND_MOVE_NORTH: y -= GetTileHeight(); break;<br />
case COMMAND_MOVE_SOUTH: y += GetTileHeight(); break;<br />
case COMMAND_MOVE_EAST: x += GetTileWidth(); break;<br />
case COMMAND_MOVE_WEST: x -= GetTileWidth(); break;<br />
}<br />
<br />
return IsPersonObstructed(this.input, x, y);<br />
}<br />
<br />
TileSystem.prototype.move = function(command) {<br />
var pixels = GetTileWidth();<br />
for (var i = 0; i < pixels; ++i) {<br />
QueuePersonCommand(this.input, command, false);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
That's all there is to it! It ''seems'' like a lot of code, but really we had to handle 4 separate directions. I ''could'' condense this down a bit, but then it'd get harder to understand.</div>Radnenhttp://wiki.spheredev.org/index.php?title=Tile_Movement&diff=1159Tile Movement2014-03-04T10:20:57Z<p>Radnen: Minor code fixes</p>
<hr />
<div>[[Category:Tutorials]]<br />
<br />
This tutorial is for beginners on up. So, you are wondering how to make a good tile movement system for your game? In Sphere it's not that hard and can be made as a natural extension of the map engine. You will need to know how to integrate existing systems into your game, and understand how Sphere's SetUpdateScript works.<br />
<br />
--[[User:Radnen|Radnen]] ([[User talk:Radnen|talk]]) 05:55, 4 March 2014 (UTC)<br />
<br />
== Step 0: the class ==<br />
<br />
As you set up any system, we need a ''class'' to hold the information. In JavaScript we can do so by creating a new function.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
}<br />
</syntaxhighlight><br />
<br />
== Step 1: the ''listener'' ==<br />
<br />
The next thing we do is create what I call a ''listener''. It's code that must run always in an update loop. A listener in specific is something that must run all the time, but does nothing until you hit a key or a button or something. We add it to our tile movement system like so:<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
}<br />
<br />
TileSystem.prototype.update = function() {<br />
}<br />
</syntaxhighlight><br />
<br />
When the player hits the movement keys, it should move the entity. We know what the entity is by the '''this.input''' field. We first want to wait until the person is no longer moving, by using the function IsCommandQueueEmpty(). If the queue is not empty we return early, letting it do nothing. If the command queue is empty then we are good for seeing if we can move the player left or right, up or down by hitting those 4 keys respectively.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || IsCommandQueueEmpty(this.input)) return;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) // move left<br />
else if (IsKeyPressed(KEY_RIGHT)) // move right<br />
else if (IsKeyPressed(KEY_UP)) // move up<br />
else if (IsKeyPressed(KEY_DOWN)) // move down<br />
}<br />
</syntaxhighlight><br />
<br />
Good. We created a listener. Now, let's make it move the player.<br />
<br />
== Step 2: movement ==<br />
<br />
Adding movement means creating a new method stub called ''move'' which queues enough move commands to move the sprite in the given direction. We use the arrow keys to set that direction.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || IsCommandQueueEmpty(this.input)) return;<br />
<br />
if (IsKeyPressed(KEY_LEFT )) this.move(COMMAND_MOVE_WEST);<br />
else if (IsKeyPressed(KEY_RIGHT)) this.move(COMMAND_MOVE_EAST); <br />
else if (IsKeyPressed(KEY_UP )) this.move(COMMAND_MOVE_NORTH);<br />
else if (IsKeyPressed(KEY_DOWN )) this.move(COMMAND_MOVE_SOUTH);<br />
}<br />
<br />
TileSystem.prototype.move = function(command) {<br />
var pixels = GetTileWidth();<br />
for (var i = 0; i < pixels; ++i) {<br />
QueuePersonCommand(this.input, command, false);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
Good. We are almost done. The last major step is to figure out facing.<br />
<br />
== Step 3: facing ==<br />
<br />
Facing is best done adding on to the directional keys, and queuing a face command in the same direction as the move command.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || IsCommandQueueEmpty(this.input)) return;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_WEST, true);<br />
this.move(COMMAND_MOVE_WEST);<br />
}<br />
else if (IsKeyPressed(KEY_RIGHT)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_EAST, true);<br />
this.move(COMMAND_MOVE_EAST);<br />
}<br />
else if (IsKeyPressed(KEY_UP)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_NORTH, true);<br />
this.move(COMMAND_MOVE_NORTH);<br />
}<br />
else if (IsKeyPressed(KEY_DOWN)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_SOUTH, true);<br />
this.move(COMMAND_MOVE_SOUTH);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
== Step 4: overwriting Sphere ==<br />
<br />
Sphere uses the movement keys internally for movement, and we must stop that from happening. We can do this by binding the 4 keys to nothing.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
<br />
BindKey(KEY_UP, '', '');<br />
BindKey(KEY_DOWN, '', '');<br />
BindKey(KEY_LEFT, '', '');<br />
BindKey(KEY_RIGHT, '', '');<br />
}<br />
</syntaxhighlight><br />
<br />
This step was crucial since Sphere would still try to move the sprite per pixel rather than our newer per tile method. <br />
<br />
== Step 5: using it ==<br />
<br />
Good, at this stage you have a basic tile mover ready to go. Now, how do you use it? We make a new instance of TileMover, giving it the name of our attached entity, and set an update script, like so.<br />
<br />
<syntaxhighlight><br />
RequireScript('tilemover.js'); // or however you saved it<br />
<br />
var my_mover = new TileMover("player");<br />
<br />
function game() {<br />
SetUpdateScript("my_mover.update()");<br />
CreatePerson("player");<br />
AttachInput("player");<br />
AttachCamera("player");<br />
MapEngine("map.rmp", 60);<br />
}<br />
</syntaxhighlight><br />
<br />
And that's it!<br />
<br />
== Intermediate: checking obstructions ==<br />
<br />
If you are using a map that does not have tile based collisions, then checking collisions can get tricky. If you followed the tutorial up until now, you'll notice that it is possible to walk 'off tile' so to speak. In order to make sure the player always stays on tile, we can employ a check to make sure it only walks if the next tile is clear.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.check = function(command) {<br />
var x = GetPersonX(this.input);<br />
var y = GetPersonY(this.input);<br />
<br />
switch(command) {<br />
case COMMAND_MOVE_NORTH: y -= GetTileHeight(); break;<br />
case COMMAND_MOVE_SOUTH: y += GetTileHeight(); break;<br />
case COMMAND_MOVE_EAST: x += GetTileWidth(); break;<br />
case COMMAND_MOVE_WEST: x -= GetTileWidth(); break;<br />
}<br />
<br />
return IsPersonObstructed(this.input, x, y);<br />
}<br />
</syntaxhighlight><br />
<br />
So, how does this work? It checks the next tile in the direction the person is walking and returns false if there is no obstruction and true if there is anything in the way. This is so far, just the check. Now we should go add it like so.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || IsCommandQueueEmpty(this.input)) return;<br />
<br />
var command = null;<br />
var face = null;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) {<br />
face = COMMAND_FACE_WEST;<br />
command = COMMAND_MOVE_WEST;<br />
}<br />
else if (IsKeyPressed(KEY_RIGHT)) {<br />
face = COMMAND_FACE_EAST;<br />
command = COMMAND_MOVE_EAST;<br />
}<br />
else if (IsKeyPressed(KEY_UP)) {<br />
face = COMMAND_FACE_NORTH;<br />
command = COMMAND_MOVE_NORTH;<br />
}<br />
else if (IsKeyPressed(KEY_DOWN)) {<br />
face = COMMAND_FACE_SOUTH;<br />
command = COMMAND_MOVE_SOUTH;<br />
}<br />
<br />
if (command != null && !this.check(command)) {<br />
if (face != null) QueuePersonCommand(this.input, face, true);<br />
this.move(command);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
What this does is ''defer'' the command until we check the direction. If all is good, we are allowed to move. Otherwise it returns doing nothing.<br />
<br />
=== Bonus: adding a sound ===<br />
<br />
Alright you got it to check if something is blocking in the way. Now you are wondering like how it is in Pokémon that it creates a sound when you hit something? First we should load that sound up when we create our tile mover, like so. You can use [http://www.bfxr.net/ bfxr] to create the thump sound.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
this.sound = LoadSound("thump.wav"); // have a sound like this<br />
<br />
BindKey(KEY_UP, '', '');<br />
BindKey(KEY_DOWN, '', '');<br />
BindKey(KEY_LEFT, '', '');<br />
BindKey(KEY_RIGHT, '', '');<br />
}<br />
</syntaxhighlight><br />
<br />
Next we can add the sound by slightly modifying the move section of the update loop.<br />
<br />
<syntaxhighlight><br />
if (command != null)<br />
if(!this.check(command)) {<br />
if (face != null) QueuePersonCommand(this.input, face, true);<br />
this.move(command);<br />
}<br />
else {<br />
this.sound.play();<br />
this.move(COMMAND_ANIMATE);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
And that's it! I add the animate command to make it still appear as if the sprite were walking in place; otherwise he's just standing still.<br />
<br />
== Appendix: full code ==<br />
<br />
More advanced systems can always be made. They are simply, too much to go into detail here but all of them would be built off a method similar to this. So, feel free to add your own things to this if you want.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
this.sound = LoadSound("thump.wav"); // have a sound like this<br />
<br />
BindKey(KEY_UP, '', '');<br />
BindKey(KEY_DOWN, '', '');<br />
BindKey(KEY_LEFT, '', '');<br />
BindKey(KEY_RIGHT, '', '');<br />
}<br />
<br />
TileSystem.prototype.update = function() {<br />
if (!this.input || IsCommandQueueEmpty(this.input)) return;<br />
<br />
var command = null;<br />
var face = null;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) {<br />
face = COMMAND_FACE_WEST;<br />
command = COMMAND_MOVE_WEST;<br />
}<br />
else if (IsKeyPressed(KEY_RIGHT)) {<br />
face = COMMAND_FACE_EAST;<br />
command = COMMAND_MOVE_EAST;<br />
}<br />
else if (IsKeyPressed(KEY_UP)) {<br />
face = COMMAND_FACE_NORTH;<br />
command = COMMAND_MOVE_NORTH;<br />
}<br />
else if (IsKeyPressed(KEY_DOWN)) {<br />
face = COMMAND_FACE_SOUTH;<br />
command = COMMAND_MOVE_SOUTH;<br />
}<br />
<br />
if (command != null && !this.check(command)) {<br />
if (face != null) QueuePersonCommand(this.input, face, true);<br />
this.move(command);<br />
}<br />
}<br />
<br />
TileSystem.prototype.check = function(command) {<br />
var x = GetPersonX(this.input);<br />
var y = GetPersonY(this.input);<br />
<br />
switch(command) {<br />
case COMMAND_MOVE_NORTH: y -= GetTileHeight(); break;<br />
case COMMAND_MOVE_SOUTH: y += GetTileHeight(); break;<br />
case COMMAND_MOVE_EAST: x += GetTileWidth(); break;<br />
case COMMAND_MOVE_WEST: x -= GetTileWidth(); break;<br />
}<br />
<br />
return IsPersonObstructed(this.input, x, y);<br />
}<br />
<br />
TileSystem.prototype.move = function(command) {<br />
var pixels = GetTileWidth();<br />
for (var i = 0; i < pixels; ++i) {<br />
QueuePersonCommand(this.input, command, false);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
That's all there is to it! It ''seems'' like a lot of code, but really we had to handle 4 separate directions. I ''could'' condense this down a bit, but then it'd get harder to understand.</div>Radnenhttp://wiki.spheredev.org/index.php?title=Handling_Multiple_Update_or_Render_Scripts&diff=1158Handling Multiple Update or Render Scripts2014-03-04T06:23:22Z<p>Radnen: Created a page for handling multiple update or render scripts</p>
<hr />
<div>[[Category:Tutorials]]<br />
<br />
Hi, so if you are wondering how to add multiple update or render scripts to your game you came to the right place. I'll teach you some good tricks to manage several update codes in a game.<br />
<br />
--[[User:Radnen|Radnen]] ([[User talk:Radnen|talk]]) 06:23, 4 March 2014 (UTC)<br />
<br />
== The Problem ==<br />
<br />
We are trying to solve the multiple-update-script problem. This is a very early and common problem with new Sphere users. Say you have a tile movement update script that runs in a SetUpdateScript. Then you also have a screen fade effect that you wrote, and it also uses the update script. You try this, and get nowhere:<br />
<br />
<syntaxhighlight><br />
SetUpdateScript("tile_mover.update()");<br />
SetUpdateScript("fader.update();");<br />
SetUpdateScript("something_else();");<br />
//...<br />
</syntaxhighlight><br />
<br />
Only to see that the last item in the list is what runs. This is because SetUpdateScript or SetRenderScript ''overwrite'' the last script used. What we need then is a way to manage all these updates.<br />
<br />
== Method 1 (Beginner): the long-ass string ==<br />
<br />
Since SetUpdateScript takes a string we can conceivably tack on everything as one long string.<br />
<br />
<syntaxhighlight><br />
SetUpdateScript("tile_mover.update(); fader.update(); something_else();"); // only once!<br />
</syntaxhighlight><br />
<br />
The only problem with this message is the string. It just gets longer and longer, which is not too pretty to look at. We can do better.<br />
<br />
== Method 2 (Beginner): the function ==<br />
<br />
By far the simplest and easiest method is to make sure you use only one update function. This is accomplished by using one function and adding ''into it'' the other functions you are using.<br />
<br />
<syntaxhighlight><br />
SetUpdateScript("Update()"); // only once!<br />
</syntaxhighlight><br />
<br />
Then in Update you put all your other update scripts:<br />
<br />
<syntaxhighlight><br />
function Update() {<br />
tile_mover.update();<br />
fader.update();<br />
something_else();<br />
//...<br />
}<br />
</syntaxhighlight><br />
<br />
== Method 3 (Intermediate): the manager ==<br />
<br />
By far the smartest way is the manager. We can do some neat tricks. For one we can remove specific updates, and add or remove others at will. Even though this is called UpdateManager it works for the SetRenderScript too.<br />
<br />
<syntaxhighlight><br />
function UpdateManager() {<br />
this.updates = [];<br />
}<br />
<br />
// runs each update function you add to it:<br />
UpdateManager.prototype.update = function() {<br />
for (var i = 0; i < this.updates.length; ++i) {<br />
this.updates[i].call();<br />
}<br />
}<br />
<br />
// creates a meta object with a name and a function:<br />
UpdateManager.prototype.add = function(name, call) {<br />
this.updates[i].push({ name: name, call: call });<br />
}<br />
<br />
// searches for the update with the specified name and removes it<br />
UpdateManager.prototype.remove = function(name) {<br />
for (var i = 0; i < this.updates.length; ++i) {<br />
if (this.updates[i].name == name) {<br />
this.updates.splice(i, 1);<br />
return;<br />
}<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
To add an update we can contain them in ''lamda functions'' like so.<br />
<syntaxhighlight><br />
var MyUpdates = new UpdateManager();<br />
MyUpdates.add("movement", function() { tile_mover.update(); });<br />
MyUpdates.add("fader", function() { fader.update(); });<br />
MyUpdates.add("other", function() { my_function(); });<br />
</syntaxhighlight><br />
<br />
We add the update manager like so:<br />
<br />
<syntaxhighlight><br />
SetUpdateScript("MyUpdates.update()"); // only once!<br />
</syntaxhighlight><br />
<br />
And at any time we can remove something if we no longer need it, such as the tile movement by saying MyUpdates.remove("movement");<br />
<br />
That's it! If you are even more advanced you can continue with the manager and add priorities as well as other neat features, but this is the core gist of it.</div>Radnenhttp://wiki.spheredev.org/index.php?title=Tile_Movement&diff=1157Tile Movement2014-03-04T05:55:14Z<p>Radnen: Created Tile Movement tutorial</p>
<hr />
<div>[[Category:Tutorials]]<br />
<br />
This tutorial is for beginners on up. So, you are wondering how to make a good tile movement system for your game? In Sphere it's not that hard and can be made as a natural extension of the map engine. You will need to know how to integrate existing systems into your game, and understand how Sphere's SetUpdateScript works.<br />
<br />
--[[User:Radnen|Radnen]] ([[User talk:Radnen|talk]]) 05:55, 4 March 2014 (UTC)<br />
<br />
== Step 0: the class ==<br />
<br />
As you set up any system, we need a ''class'' to hold the information. In JavaScript we can do so by creating a new function.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
}<br />
</syntaxhighlight><br />
<br />
== Step 1: the ''listener'' ==<br />
<br />
The next thing we do is create what I call a ''listener''. It's code that must run always in an update loop. A listener in specific is something that must run all the time, but does nothing until you hit a key or a button or something. We add it to our tile movement system like so:<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
}<br />
<br />
TileSystem.prototype.update = function() {<br />
}<br />
</syntaxhighlight><br />
<br />
When the player hits the movement keys, it should move the entity. We know what the entity is by the '''this.input''' field. We first want to wait until the person is no longer moving, by using the function IsCommandQueueEmpty(). If the queue is not empty we return early, letting it do nothing. If the command queue is empty then we are good for seeing if we can move the player left or right, up or down by hitting those 4 keys respectively.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || IsCommandQueueEmpty(this.input)) return;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) // move left<br />
else if (IsKeyPressed(KEY_RIGHT)) // move right<br />
else if (IsKeyPressed(KEY_UP)) // move up<br />
else if (IsKeyPressed(KEY_DOWN)) // move down<br />
}<br />
</syntaxhighlight><br />
<br />
Good. We created a listener. Now, let's make it move the player.<br />
<br />
== Step 2: movement ==<br />
<br />
Adding movement means creating a new method stub called ''move'' which queues enough move commands to move the sprite in the given direction. We use the arrow keys to set that direction.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || IsCommandQueueEmpty(this.input)) return;<br />
<br />
if (IsKeyPressed(KEY_LEFT )) this.move(COMMAND_MOVE_WEST);<br />
else if (IsKeyPressed(KEY_RIGHT)) this.move(COMMAND_MOVE_EAST); <br />
else if (IsKeyPressed(KEY_UP )) this.move(COMMAND_MOVE_NORTH);<br />
else if (IsKeyPressed(KEY_DOWN )) this.move(COMMAND_MOVE_SOUTH);<br />
}<br />
<br />
TileSystem.prototype.move = function(command) {<br />
var pixels = GetTileWidth();<br />
for (var i = 0; i < pixels; ++i) {<br />
QueuePersonCommand(this.input, command, false);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
Good. We are almost done. The last major step is to figure out facing.<br />
<br />
== Step 3: facing ==<br />
<br />
Facing is best done adding on to the directional keys, and queuing a face command in the same direction as the move command.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || IsCommandQueueEmpty(this.input)) return;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_WEST, true);<br />
this.move(COMMAND_MOVE_WEST);<br />
}<br />
else if (IsKeyPressed(KEY_RIGHT)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_EAST, true);<br />
this.move(COMMAND_MOVE_EAST);<br />
}<br />
else if (IsKeyPressed(KEY_UP)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_NORTH, true);<br />
this.move(COMMAND_MOVE_NORTH);<br />
}<br />
else if (IsKeyPressed(KEY_DOWN)) {<br />
QueuePersonCommand(this.input, COMMAND_FACE_SOUTH, true);<br />
this.move(COMMAND_MOVE_SOUTH);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
== Step 4: overwriting Sphere ==<br />
<br />
Sphere uses the movement keys internally for movement, and we must stop that from happening. We can do this by binding the 4 keys to nothing.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
<br />
BindKey(KEY_UP, '', '');<br />
BindKey(KEY_DOWN, '', '');<br />
BindKey(KEY_LEFT, '', '');<br />
BindKey(KEY_RIGHT, '', '');<br />
}<br />
</syntaxhighlight><br />
<br />
This step was crucial since Sphere would still try to move the sprite per pixel rather than our newer per tile method. <br />
<br />
== Step 5: using it ==<br />
<br />
Good, at this stage you have a basic tile mover ready to go. Now, how do you use it? We make a new instance of TileMover, giving it the name of our attached entity, and set an update script, like so.<br />
<br />
<syntaxhighlight><br />
RequireScript('tilemover.js'); // or however you saved it<br />
<br />
var my_mover = new TileMover("player");<br />
<br />
function game() {<br />
SetUpdateScript("my_mover.update()");<br />
CreatePerson("player");<br />
AttachInput("player");<br />
AttachCamera("player");<br />
MapEngine("map.rmp", 60);<br />
}<br />
</syntaxhighlight><br />
<br />
And that's it!<br />
<br />
== Intermediate: checking obstructions ==<br />
<br />
If you are using a map that does not have tile based collisions, then checking collisions can get tricky. If you followed the tutorial up until now, you'll notice that it is possible to walk 'off tile' so to speak. In order to make sure the player always stays on tile, we can employ a check to make sure it only walks if the next tile is clear.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.check = function(command) {<br />
var x = GetPersonX(this.input);<br />
var y = GetPersonY(this.input);<br />
<br />
switch(command) {<br />
case COMMAND_MOVE_NORTH: y -= GetTileHeight(); break;<br />
case COMMAND_MOVE_SOUTH: y += GetTileHeight(); break;<br />
case COMMAND_MOVE_EAST: x += GetTileWidth(); break;<br />
case COMMAND_MOVE_WEST: x -= GetTileWidth(); break;<br />
}<br />
<br />
return IsPersonObstructed(name, x, y);<br />
}<br />
</syntaxhighlight><br />
<br />
So, how does this work? It checks the next tile in the direction the person is walking and returns false if there is no obstruction and true if there is anything in the way. This is so far, just the check. Now we should go add it like so.<br />
<br />
<syntaxhighlight><br />
TileSystem.prototype.update = function() {<br />
if (!this.input || IsCommandQueueEmpty(this.input)) return;<br />
<br />
var command = null;<br />
var face = null;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) {<br />
face = COMMAND_FACE_WEST;<br />
command = COMMAND_MOVE_WEST;<br />
}<br />
else if (IsKeyPressed(KEY_RIGHT)) {<br />
face = COMMAND_FACE_EAST;<br />
command = COMMAND_MOVE_EAST;<br />
}<br />
else if (IsKeyPressed(KEY_UP)) {<br />
face = COMMAND_FACE_NORTH;<br />
command = COMMAND_MOVE_NORTH;<br />
}<br />
else if (IsKeyPressed(KEY_DOWN)) {<br />
face = COMMAND_FACE_SOUTH;<br />
command = COMMAND_MOVE_SOUTH;<br />
}<br />
<br />
if (command != null && !this.check(command)) {<br />
if (face != null) QueuePersonCommand(this.input, face, true);<br />
this.move(command);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
What this does is ''defer'' the command until we check the direction. If all is good, we are allowed to move. Otherwise it returns doing nothing.<br />
<br />
=== Bonus: adding a sound ===<br />
<br />
Alright you got it to check if something is blocking in the way. Now you are wondering like how it is in Pokémon that it creates a sound when you hit something? First we should load that sound up when we create our tile mover, like so. You can use [http://www.bfxr.net/ bfxr] to create the thump sound.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
this.sound = LoadSound("thump.wav"); // have a sound like this<br />
<br />
BindKey(KEY_UP, '', '');<br />
BindKey(KEY_DOWN, '', '');<br />
BindKey(KEY_LEFT, '', '');<br />
BindKey(KEY_RIGHT, '', '');<br />
}<br />
</syntaxhighlight><br />
<br />
Next we can add the sound by slightly modifying the move section of the update loop.<br />
<br />
<syntaxhighlight><br />
if (command != null)<br />
if(!this.check(command)) {<br />
if (face != null) QueuePersonCommand(this.input, face, true);<br />
this.move(command);<br />
}<br />
else {<br />
this.sound.play();<br />
this.move(COMMAND_ANIMATE);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
And that's it! I add the animate command to make it still appear as if the sprite were walking in place; otherwise he's just standing still.<br />
<br />
== Appendix: full code ==<br />
<br />
More advanced systems can always be made. They are simply, too much to go into detail here but all of them would be built off a method similar to this. So, feel free to add your own things to this if you want.<br />
<br />
<syntaxhighlight><br />
function TileSystem(input) {<br />
this.input = input;<br />
this.sound = LoadSound("thump.wav"); // have a sound like this<br />
<br />
BindKey(KEY_UP, '', '');<br />
BindKey(KEY_DOWN, '', '');<br />
BindKey(KEY_LEFT, '', '');<br />
BindKey(KEY_RIGHT, '', '');<br />
}<br />
<br />
TileSystem.prototype.update = function() {<br />
if (!this.input || IsCommandQueueEmpty(this.input)) return;<br />
<br />
var command = null;<br />
var face = null;<br />
<br />
if (IsKeyPressed(KEY_LEFT)) {<br />
face = COMMAND_FACE_WEST;<br />
command = COMMAND_MOVE_WEST;<br />
}<br />
else if (IsKeyPressed(KEY_RIGHT)) {<br />
face = COMMAND_FACE_EAST;<br />
command = COMMAND_MOVE_EAST;<br />
}<br />
else if (IsKeyPressed(KEY_UP)) {<br />
face = COMMAND_FACE_NORTH;<br />
command = COMMAND_MOVE_NORTH;<br />
}<br />
else if (IsKeyPressed(KEY_DOWN)) {<br />
face = COMMAND_FACE_SOUTH;<br />
command = COMMAND_MOVE_SOUTH;<br />
}<br />
<br />
if (command != null && !this.check(command)) {<br />
if (face != null) QueuePersonCommand(this.input, face, true);<br />
this.move(command);<br />
}<br />
}<br />
<br />
TileSystem.prototype.check = function(command) {<br />
var x = GetPersonX(this.input);<br />
var y = GetPersonY(this.input);<br />
<br />
switch(command) {<br />
case COMMAND_MOVE_NORTH: y -= GetTileHeight(); break;<br />
case COMMAND_MOVE_SOUTH: y += GetTileHeight(); break;<br />
case COMMAND_MOVE_EAST: x += GetTileWidth(); break;<br />
case COMMAND_MOVE_WEST: x -= GetTileWidth(); break;<br />
}<br />
<br />
return IsPersonObstructed(name, x, y);<br />
}<br />
<br />
TileSystem.prototype.move = function(command) {<br />
var pixels = GetTileWidth();<br />
for (var i = 0; i < pixels; ++i) {<br />
QueuePersonCommand(this.input, command, false);<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
That's all there is to it! It ''seems'' like a lot of code, but really we had to handle 4 separate directions. I ''could'' condense this down a bit, but then it'd get harder to understand.</div>Radnenhttp://wiki.spheredev.org/index.php?title=Factory_Tutorial&diff=1156Factory Tutorial2014-03-03T01:25:21Z<p>Radnen: Added authorship</p>
<hr />
<div>[[Category:Tutorials]]<br />
<br />
What is a Factory? Why use Factories? How hard are they to make or use? All of these questions will be explained and put to use in this JavaScript programming tutorial. Recommended proficiency: intermediate to advanced.<br />
<br />
--[[User:Radnen|Radnen]] ([[User talk:Radnen|talk]]) 01:25, 3 March 2014 (UTC)<br />
<br />
== Factories ==<br />
<br />
A Factory is a design pattern in JavaScript aimed to aid in the construction of objects. Why is this useful? Sometimes creating your own objects can be a pain; especially when you have hundreds of different objects. In games this is commonly seen in item lists or enemy lists. The trouble is if you create an enemy in the 'old way' you'll get bad behavior.<br />
<br />
=== The Old Way ===<br />
<br />
<syntaxhighlight><br />
function Enemy(name, hp, atk) {<br />
this.name = name;<br />
this.hp = hp;<br />
this.atk = atk;<br />
}<br />
<br />
<br />
var enemies = [];<br />
enemies[0] = new Enemy("Bug", 10, 2);<br />
enemies[1] = new Enemy("Rodent", 15, 5);<br />
enemies[2] = new Enemy("Wolf", 25, 8);<br />
<br />
// later on:<br />
<br />
enemies[0].hp -= 5;<br />
</syntaxhighlight><br />
<br />
Then if you use enemy[0] in combat you can actually affect the base object rather than a clone of it. So most people, if they want enemies in their game they end up cloning them like so:<br />
<br />
<syntaxhighlight><br />
function CloneEnemy(enemy) {<br />
return new Enemy(enemy.name, enemy.hp, enemy.atk);<br />
}<br />
<br />
var enemy = CloneEnemy(enemies[0]);<br />
enemy.hp -= 5;<br />
</syntaxhighlight><br />
<br />
That is a very nice solution, but it requires you to run a clone method each time, and in the case above a new clone method must be made for each object you want to have a copy of. Of course the next step would then to write a general clone method, and I'm sure you have one or heard of it before in JS. This is not how the Factory paradigm works, however. So, we won't go into object cloning.<br />
<br />
=== The New Way ===<br />
<br />
A Factory streamlines the process of constructing new objects. But in order to harness the full power we need to change the way in which we create objects. The enemy class from the old way now looks like this:<br />
<br />
<syntaxhighlight><br />
function Enemy(params) {<br />
this.name = params.name || "none";<br />
this.hp = params.hp || 0;<br />
this.atk = params.atk || 0;<br />
}<br />
</syntaxhighlight><br />
<br />
The params are important since we can use new params objects to define new enemies rather than put then all into an array. So each time you create an enemy you can do this:<br />
<br />
<syntaxhighlight><br />
var bug = { name: "bug", hp: 10, atk: 2 };<br />
<br />
var enemy = new Enemy(bug);<br />
enemy.hp -= 5;<br />
</syntaxhighlight><br />
<br />
Although this is a slightly better method that reduces the need to use a cloning method, you still have to type up what object to build and use 'new' keyword. It's not bad, in fact if we stop here you'll already benefit from a good JS design practice. But, we can go one step further. We can create the actual Factory. Yes, up until now all we did is create the inventory for the Factory. Let's make the factory.<br />
<br />
== The Factory Code ==<br />
<br />
A factory is good since it holds info on how to make the object and then makes the object, anew, whenever you ask it to. This is better than cloning entities since it physically calls constructors, and so the performance is not only slightly better it uses native JavaScript techniques to produce the objects without looking like you are doing much at all. It can reduce some boilerplate code.<br />
<br />
<syntaxhighlight><br />
function Factory(proto) {<br />
this.params = { };<br />
this.proto = proto;<br />
}<br />
<br />
Factory.prototype.register = function(name, params) {<br />
this.params[name] = params;<br />
}<br />
<br />
Factory.prototype.create = function(name) {<br />
var object = params[name];<br />
return object && new this.proto(object);<br />
}<br />
</syntaxhighlight><br />
<br />
Tip: The && operator in JS can be used to ''short-circuit'' return statements. In the example above if 'object' is undefined it won't return '''new this.proto(object)''' but '''undefined''' instead. This is a ''very'' nifty way of doing it.<br />
<br />
<br />
So, how do you use it? Let's build off of the new way for Enemy construction. Remember how I made the bug parameters object? Let's do that with a factory instead, and then use the factory to create a new bug enemy.<br />
<br />
<syntaxhighlight><br />
function Enemy(params) {<br />
this.name = params.name || "none";<br />
this.hp = params.hp || 0;<br />
this.atk = params.atk || 0;<br />
}<br />
<br />
var Enemies = new Factory(Enemy);<br />
Enemies.register("bug", { name: "Bug", hp: 10, atk: 2 }); // like doing bug = { ... }<br />
<br />
var enemy = Enemies.create("bug");<br />
enemy.hp -= 5;<br />
</syntaxhighlight><br />
<br />
See? All we do is tell it what new kind of enemy to make and then it does all of the rest internally. This is great since it reduces the level of knowledge the programmer has going into creating an enemy. All the programmer has to do is call the factories create method and out pops a brand new bug. What's better is the bug is an instanceof Enemy, which is nice to have. It's a perfect clone! We can then go on to define other enemies like the wolf or rodent very easily.<br />
<br />
== Advanced: Adding Inheritance ==<br />
<br />
When working with items, you might have various inherited classes. Here is an inheritance based Factory.<br />
<br />
<syntaxhighlight><br />
function Factory(proto) {<br />
this.bases = { };<br />
this.proto = proto;<br />
}<br />
<br />
Factory.prototype.register = function(name, defaults, superclass) {<br />
this.bases[name] = { params: defaults, superclass: superclass};<br />
}<br />
<br />
Factory.prototype.create = function(type) {<br />
var data = this.bases[type];<br />
if (data && data.superclass) {<br />
var obj = new data.superclass(data.params);<br />
this.proto.call(obj, data.params);<br />
obj.prototype = new this.proto({});<br />
return obj;<br />
}<br />
else return data && new this.proto(data.params);<br />
}<br />
</syntaxhighlight><br />
<br />
The main change is the ability to store a third argument, the superclass. Then in the create method if the super class is not present it'll use the base class to create the item.<br />
<br />
Here's what this looks like, elegantly:<br />
<syntaxhighlight><br />
function Item(params) {<br />
this.name = params.name || "untitled";<br />
this.price = params.price || 0;<br />
this.weight = params.weight || 0;<br />
}<br />
<br />
function Weapon(params) {<br />
this.atk = params.atk || 0;<br />
}<br />
<br />
var Items = new Factory(Item);<br />
<br />
// register a basic item:<br />
Items.register("book", { name: "Book", price: 5, weight: 2 });<br />
<br />
// register a weapon item, that inherits from Item:<br />
Items.register("sword", { name: "Sword", price: 50, weight: 10, atk: 5 }, Weapon); // notice new 'atk' parameter<br />
<br />
// creating new items:<br />
var book = Items.create("book");<br />
var sword = Items.create("sword");<br />
</syntaxhighlight><br />
<br />
You'll find that 'book' is an instanceof Item and 'sword' is an instanceof Weapon ''and'' Item. This is great for managing items from different classes.<br />
<br />
== Intermediate: A General Factory ==<br />
<br />
What if you want a factory for any kind of item? Well we can create a general factory that is easier to use than the above factory method.<br />
<br />
<syntaxhighlight><br />
var Create = (function() {<br />
var types = { };<br />
<br />
function Create(type) {<br />
var object = types[type];<br />
return object && new object.base(object.params);<br />
}<br />
<br />
Create.register = function(name, construct, defaults) {<br />
types[name] = { base: construct, params: defaults };<br />
}<br />
<br />
return Create;<br />
})();<br />
</syntaxhighlight><br />
<br />
Tip: This is achieved with a ''closure''. Notice 'types' is a global object? Well, only from the perspective of Create. A closure contains everything in it's own little world. This gives it a sandbox to play in and reveals only the Create function by returning just it.<br />
<br />
Create is a global object that has some cool properties. Let's make any item we desire!<br />
<syntaxhighlight><br />
Create.register("bug", Enemy, { name: "Bug", hp: 10, atk: 2 });<br />
Create.register("book", Item, { name: "Book", price: 5, weight: 2 });<br />
<br />
// create some items in a simpler syntax:<br />
var book = Create("book");<br />
var bug = Create("bug");<br />
</syntaxhighlight><br />
<br />
The sky's the limit here. However you'll run out of names if you don't stick to a naming convention. This method also puts item inheritance into your own hands rather than the hands of the factory. This is by far the most flexible factory method, however.<br />
<br />
=== Bonus: Inheritance ===<br />
<br />
What if you don't want the factory to do the inheritance for you? No sweat, you can do it yourself like this:<br />
<syntaxhighlight><br />
function Item(params) {<br />
this.name = params.name || "untitled";<br />
this.price = params.price || 0;<br />
this.weight = params.weight || 0;<br />
}<br />
<br />
function Weapon(params) {<br />
Item.call(this, params);<br />
this.atk = params.atk || 0;<br />
}<br />
<br />
Weapon.prototype = new Item({});<br />
<br />
Create.register("book", Item, { name: "Book", weight: 2, price: 5 });<br />
Create.register("sword", Weapon, { name: "Sword", weight: 10, price: 50, atk: 5 });<br />
<br />
// create the items:<br />
var book = Create("book"); // instanceof Item<br />
var sword = Create("sword"); // instance of Weapon and Item<br />
</syntaxhighlight><br />
<br />
You end up writing a bit more inheritance code, but at least you can safely use the newer global Create Factory.</div>Radnenhttp://wiki.spheredev.org/index.php?title=Factory_Tutorial&diff=1155Factory Tutorial2014-03-03T01:23:44Z<p>Radnen: Created a page on JS Factories. This is some real good stuff.</p>
<hr />
<div>[[Category:Tutorials]]<br />
<br />
What is a Factory? Why use Factories? How hard are they to make or use? All of these questions will be explained and put to use in this JavaScript programming tutorial. Recommended proficiency: intermediate to advanced.<br />
<br />
== Factories ==<br />
<br />
A Factory is a design pattern in JavaScript aimed to aid in the construction of objects. Why is this useful? Sometimes creating your own objects can be a pain; especially when you have hundreds of different objects. In games this is commonly seen in item lists or enemy lists. The trouble is if you create an enemy in the 'old way' you'll get bad behavior.<br />
<br />
=== The Old Way ===<br />
<br />
<syntaxhighlight><br />
function Enemy(name, hp, atk) {<br />
this.name = name;<br />
this.hp = hp;<br />
this.atk = atk;<br />
}<br />
<br />
<br />
var enemies = [];<br />
enemies[0] = new Enemy("Bug", 10, 2);<br />
enemies[1] = new Enemy("Rodent", 15, 5);<br />
enemies[2] = new Enemy("Wolf", 25, 8);<br />
<br />
// later on:<br />
<br />
enemies[0].hp -= 5;<br />
</syntaxhighlight><br />
<br />
Then if you use enemy[0] in combat you can actually affect the base object rather than a clone of it. So most people, if they want enemies in their game they end up cloning them like so:<br />
<br />
<syntaxhighlight><br />
function CloneEnemy(enemy) {<br />
return new Enemy(enemy.name, enemy.hp, enemy.atk);<br />
}<br />
<br />
var enemy = CloneEnemy(enemies[0]);<br />
enemy.hp -= 5;<br />
</syntaxhighlight><br />
<br />
That is a very nice solution, but it requires you to run a clone method each time, and in the case above a new clone method must be made for each object you want to have a copy of. Of course the next step would then to write a general clone method, and I'm sure you have one or heard of it before in JS. This is not how the Factory paradigm works, however. So, we won't go into object cloning.<br />
<br />
=== The New Way ===<br />
<br />
A Factory streamlines the process of constructing new objects. But in order to harness the full power we need to change the way in which we create objects. The enemy class from the old way now looks like this:<br />
<br />
<syntaxhighlight><br />
function Enemy(params) {<br />
this.name = params.name || "none";<br />
this.hp = params.hp || 0;<br />
this.atk = params.atk || 0;<br />
}<br />
</syntaxhighlight><br />
<br />
The params are important since we can use new params objects to define new enemies rather than put then all into an array. So each time you create an enemy you can do this:<br />
<br />
<syntaxhighlight><br />
var bug = { name: "bug", hp: 10, atk: 2 };<br />
<br />
var enemy = new Enemy(bug);<br />
enemy.hp -= 5;<br />
</syntaxhighlight><br />
<br />
Although this is a slightly better method that reduces the need to use a cloning method, you still have to type up what object to build and use 'new' keyword. It's not bad, in fact if we stop here you'll already benefit from a good JS design practice. But, we can go one step further. We can create the actual Factory. Yes, up until now all we did is create the inventory for the Factory. Let's make the factory.<br />
<br />
== The Factory Code ==<br />
<br />
A factory is good since it holds info on how to make the object and then makes the object, anew, whenever you ask it to. This is better than cloning entities since it physically calls constructors, and so the performance is not only slightly better it uses native JavaScript techniques to produce the objects without looking like you are doing much at all. It can reduce some boilerplate code.<br />
<br />
<syntaxhighlight><br />
function Factory(proto) {<br />
this.params = { };<br />
this.proto = proto;<br />
}<br />
<br />
Factory.prototype.register = function(name, params) {<br />
this.params[name] = params;<br />
}<br />
<br />
Factory.prototype.create = function(name) {<br />
var object = params[name];<br />
return object && new this.proto(object);<br />
}<br />
</syntaxhighlight><br />
<br />
Tip: The && operator in JS can be used to ''short-circuit'' return statements. In the example above if 'object' is undefined it won't return '''new this.proto(object)''' but '''undefined''' instead. This is a ''very'' nifty way of doing it.<br />
<br />
<br />
So, how do you use it? Let's build off of the new way for Enemy construction. Remember how I made the bug parameters object? Let's do that with a factory instead, and then use the factory to create a new bug enemy.<br />
<br />
<syntaxhighlight><br />
function Enemy(params) {<br />
this.name = params.name || "none";<br />
this.hp = params.hp || 0;<br />
this.atk = params.atk || 0;<br />
}<br />
<br />
var Enemies = new Factory(Enemy);<br />
Enemies.register("bug", { name: "Bug", hp: 10, atk: 2 }); // like doing bug = { ... }<br />
<br />
var enemy = Enemies.create("bug");<br />
enemy.hp -= 5;<br />
</syntaxhighlight><br />
<br />
See? All we do is tell it what new kind of enemy to make and then it does all of the rest internally. This is great since it reduces the level of knowledge the programmer has going into creating an enemy. All the programmer has to do is call the factories create method and out pops a brand new bug. What's better is the bug is an instanceof Enemy, which is nice to have. It's a perfect clone! We can then go on to define other enemies like the wolf or rodent very easily.<br />
<br />
== Advanced: Adding Inheritance ==<br />
<br />
When working with items, you might have various inherited classes. Here is an inheritance based Factory.<br />
<br />
<syntaxhighlight><br />
function Factory(proto) {<br />
this.bases = { };<br />
this.proto = proto;<br />
}<br />
<br />
Factory.prototype.register = function(name, defaults, superclass) {<br />
this.bases[name] = { params: defaults, superclass: superclass};<br />
}<br />
<br />
Factory.prototype.create = function(type) {<br />
var data = this.bases[type];<br />
if (data && data.superclass) {<br />
var obj = new data.superclass(data.params);<br />
this.proto.call(obj, data.params);<br />
obj.prototype = new this.proto({});<br />
return obj;<br />
}<br />
else return data && new this.proto(data.params);<br />
}<br />
</syntaxhighlight><br />
<br />
The main change is the ability to store a third argument, the superclass. Then in the create method if the super class is not present it'll use the base class to create the item.<br />
<br />
Here's what this looks like, elegantly:<br />
<syntaxhighlight><br />
function Item(params) {<br />
this.name = params.name || "untitled";<br />
this.price = params.price || 0;<br />
this.weight = params.weight || 0;<br />
}<br />
<br />
function Weapon(params) {<br />
this.atk = params.atk || 0;<br />
}<br />
<br />
var Items = new Factory(Item);<br />
<br />
// register a basic item:<br />
Items.register("book", { name: "Book", price: 5, weight: 2 });<br />
<br />
// register a weapon item, that inherits from Item:<br />
Items.register("sword", { name: "Sword", price: 50, weight: 10, atk: 5 }, Weapon); // notice new 'atk' parameter<br />
<br />
// creating new items:<br />
var book = Items.create("book");<br />
var sword = Items.create("sword");<br />
</syntaxhighlight><br />
<br />
You'll find that 'book' is an instanceof Item and 'sword' is an instanceof Weapon ''and'' Item. This is great for managing items from different classes.<br />
<br />
== Intermediate: A General Factory ==<br />
<br />
What if you want a factory for any kind of item? Well we can create a general factory that is easier to use than the above factory method.<br />
<br />
<syntaxhighlight><br />
var Create = (function() {<br />
var types = { };<br />
<br />
function Create(type) {<br />
var object = types[type];<br />
return object && new object.base(object.params);<br />
}<br />
<br />
Create.register = function(name, construct, defaults) {<br />
types[name] = { base: construct, params: defaults };<br />
}<br />
<br />
return Create;<br />
})();<br />
</syntaxhighlight><br />
<br />
Tip: This is achieved with a ''closure''. Notice 'types' is a global object? Well, only from the perspective of Create. A closure contains everything in it's own little world. This gives it a sandbox to play in and reveals only the Create function by returning just it.<br />
<br />
Create is a global object that has some cool properties. Let's make any item we desire!<br />
<syntaxhighlight><br />
Create.register("bug", Enemy, { name: "Bug", hp: 10, atk: 2 });<br />
Create.register("book", Item, { name: "Book", price: 5, weight: 2 });<br />
<br />
// create some items in a simpler syntax:<br />
var book = Create("book");<br />
var bug = Create("bug");<br />
</syntaxhighlight><br />
<br />
The sky's the limit here. However you'll run out of names if you don't stick to a naming convention. This method also puts item inheritance into your own hands rather than the hands of the factory. This is by far the most flexible factory method, however.<br />
<br />
=== Bonus: Inheritance ===<br />
<br />
What if you don't want the factory to do the inheritance for you? No sweat, you can do it yourself like this:<br />
<syntaxhighlight><br />
function Item(params) {<br />
this.name = params.name || "untitled";<br />
this.price = params.price || 0;<br />
this.weight = params.weight || 0;<br />
}<br />
<br />
function Weapon(params) {<br />
Item.call(this, params);<br />
this.atk = params.atk || 0;<br />
}<br />
<br />
Weapon.prototype = new Item({});<br />
<br />
Create.register("book", Item, { name: "Book", weight: 2, price: 5 });<br />
Create.register("sword", Weapon, { name: "Sword", weight: 10, price: 50, atk: 5 });<br />
<br />
// create the items:<br />
var book = Create("book"); // instanceof Item<br />
var sword = Create("sword"); // instance of Weapon and Item<br />
</syntaxhighlight><br />
<br />
You end up writing a bit more inheritance code, but at least you can safely use the newer global Create Factory.</div>Radnenhttp://wiki.spheredev.org/index.php?title=Developing_a_Sphere-compatible_engine&diff=990Developing a Sphere-compatible engine2013-07-18T20:51:27Z<p>Radnen: /* Complete or in-progress */ clarified sfml version</p>
<hr />
<div>{{aside|Notice|This [[:Category:Tutorials|tutorial article]] is incomplete, but it is also important. Do not edit it unless you've been given permission, thanks.|note.svg}}<br />
<br />
This article aims to provide a checklist and resources for developing a JavaScript-powered game engine that is compatible with [[API:Functions|Sphere's JavaScript API]].<br />
<br />
__TOC__<br />
<br />
==Introduction==<br />
Throughout this article, the original Sphere implementation shall be referred to as "vanilla" Sphere and consisted of use of an older version of [https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey] as the JavaScript engine, the first-party [http://corona.sf.net Corona library] for the software implementation of video, and the first-party [http://audiere.sf.net Audiere library] for the audio driver. Input was mapped directly in software using whatever API was native to the OS in the case of the Windows and Linux versions of vanilla Sphere. The recent Mac OS X port of vanilla Sphere used SDL to handle all input and output while still using an older version of SpiderMonkey for JavaScript.<br />
<br />
Possible frameworks to implement Sphere:<br />
* JavaScript<br />
** V8<br />
** SpiderMonkey v1.8.5<br />
** Jurassic / IronJS / JavaScript.Net / Jint<br />
* Game Libraries<br />
** SDL<br />
** SFML<br />
* Graphics libraries<br />
** OpenGL<br />
** pixi.js / three.js<br />
** DirectX (DirectDraw)<br />
** hand-rolled software renderer.<br />
* Audio libraries<br />
** Audiere<br />
** Libsndfile<br />
** BASS<br />
** Irrklang<br />
** FMod<br />
<br />
<br />
(TODO: more)<br />
<br />
==Input==<br />
<br />
GetKey() must be able to block the sphere engine. If your key queue is zero, go into a loop that just updates the game screen.<br />
<br />
=== SFML ===<br />
If you are using SFML, you need to handle the key pressed and released events. It's a good idea to use a static array for all of the keys, mouse, and joystick buttons. The array's index corresponds with a key, mouse, and joystick code with a true/false value indicating IsPressed. In order to support more than one joystick you may need to bump up that joystick array to a 2D array, where 'x' is the joystick id and 'y' is the button code.<br />
<br />
For the key queue, just use a queue data structure. Enqueue keys on the released state, and dequeue keys with GetKey.<br />
<br />
=== Key Constant Mapping ===<br />
<br />
In SDL, SFML, and other game libraries the key codes may differ from Sphere's. In order to get the correct key mapping you might need to implement a very large structure that says "this key" = "that key". This does not have to happen as it is optional so long as you keep to the same key naming conventions. What this will do is fix it so that if you saved a game with key mappings from vanilla sphere, other sphere engines can use those same codes.<br />
<br />
See key constants: (<tt>KEY_ESCAPE = 1, KEY_F1 = 2,</tt> ... etc).<br />
<br />
https://github.com/sphere-group/sphere/blob/v1.6/sphere/docs/development/keys.txt<br />
<br />
<br />
(keyboard, mouse, joystick, touch-screen?)<br />
<br />
==Output==<br />
===Video===<br />
<br />
Blitting is a process that draws the image or surface to a screen's render target prior to flipping. In web based engines this is best emulated with a "draw queue". You fill the queue with what to draw prior to a frame and update it when you are ready.<br />
<br />
(TODO: more)<br />
(TODO: multi-monitor?)<br />
(TODO: touch-screen?)<br />
<br />
===Audio===<br />
<br />
====SFML====<br />
Audio is split between sounds and music. They have the same API, but music streams intrinsically.<br />
Volume however takes a range of 0 to 100. Treat that as a percent of the 0 to 255 range Sphere uses. You might need to cache the volume into a private variable and get set from that, making sure to set the underlying volume as a percent of whatever you used.<br />
<br />
==The map engine==<br />
(TODO)<br />
<br />
===The MapEngine loop===<br />
(TODO)<br />
<br />
==Maintaining API compatibility==<br />
Sphere's original JavaScript API was written with a procedural mentality. JavaScript is a language with a powerful prototype-based inheritance system, so you may want to change Sphere's native objects such as the [[API:Color|Color object]] to allow variable creation via the ''new'' syntax; if you do this natively you must either write the equivalent loading function (in this case, [[API:CreateColor|CreateColor]]) as native code or in a scripted shim. The [[system scripts|system script]] [[Script:system/oldsphere.js|oldsphere.js]] is an example of such a shim, existing to maintain compatibility with projects written for pre-1.0 versions of Sphere. If you'd rather leave the original procedural-style loading functions but add the ability to create native Sphere objects with a working prototype constructor, visit [http://forums.spheredev.org/index.php/topic,69.0.html this forum thread] for information on doing it in script.<br />
<br />
===Compatibility with 1.5===<br />
(TODO)<br />
<br />
===Compatibility with 1.6 beta===<br />
(TODO)<br />
<br />
===Compatibility with 1.7 alpha===<br />
(TODO)<br />
<br />
===Backwards-compatibility with pre-1.5===<br />
(TODO)<br />
<br />
==List of Sphere-compatible engine implementations==<br />
===Complete or in-progress===<br />
{| class="wikitable sortable" width="100%"<br />
|+Complete or in-progress Sphere-compatible engines<br />
|-<br />
! scope="col"| Implementation<br />
! scope="col"| Operating System<br />
! scope="col"| Version<br />
! scope="col"| JS engine<br />
! scope="col"| Video driver<br />
! scope="col"| Audio driver<br />
! scope="col"| Input handler<br />
|-<br />
|vanilla Sphere<br/>[https://github.com/sphere-group/sphere source], [http://forums.spheredev.org/index.php/topic,155.0.html thread]<br />
|Win x86, OSX, Linux x86<br />
|stable: 1.5<br/>unstable: 1.6 beta 4<br/>inactive: 1.7 alpha<br />
|[https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey]<br />
|configurable<br />
|configurable<br />
|configurable<br />
|-<br />
|TurboSphere<br/>[https://github.com/FlyingJester/TurboSphere source], [http://forums.spheredev.org/index.php/topic,13.0.html thread]<br />
|Win x86/64, OSX, Linux x86/64<br />
|0.3.0<br />
|[https://code.google.com/p/v8/ V8]<br />
|OpenGL via SDL2<br />
|BASS<br />
|SDL2<br />
|-<br />
|unnamed Sphere clone in SDL<br/>[https://github.com/postcasio/sphereclone source], [http://forums.spheredev.org/index.php/topic,72.0.html thread]<br />
|?<br />
|?<br />
|[https://code.google.com/p/v8/ V8]<br />
|SDL<br />
|SDL<br />
|SDL<br />
|-<br />
|sphere-sfml<br/>[https://github.com/Radnen/sphere-sfml source], [http://forums.spheredev.org/index.php/topic,137.0.html thread]<br />
|Win x86, OSX(?)<br />
|0.65 alpha<br />
|[http://jurassic.codeplex.com/ Jurassic]<br />
|OpenGL via SFML 2<br />
|libsndfile via SFML 2<br />
|SFML 2<br />
|-<br />
|web-sphere<br/>[https://github.com/sphere-group/web-sphere source], [http://forums.spheredev.org/index.php/topic,154.0.html thread]<br />
|Chrome, Firefox, and IE9+<br />
|[http://www.pixijs.com/ pixi.js] version: ?<br/>[http://threejs.org/ three.js] version: ?<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|}<br />
<br />
{{aside|Info|Although some engines are listed as compatible they will need a shim script to maintain compatibility with Sphere's API. For example, [[API:LoadImage|LoadImage]] may indeed return the correct [[API:image|image]] format by using a different API such as <tt>return new Image()</tt>.|template-info.svg}}<br />
<br />
===Discontinued or abandoned===<br />
(TODO)<br />
<br />
==See also==<br />
(TODO)<br />
<br />
[[Category:Tutorials]]</div>Radnenhttp://wiki.spheredev.org/index.php?title=Developing_a_Sphere-compatible_engine&diff=989Developing a Sphere-compatible engine2013-07-18T20:49:35Z<p>Radnen: /* Complete or in-progress */ added operating system to each</p>
<hr />
<div>{{aside|Notice|This [[:Category:Tutorials|tutorial article]] is incomplete, but it is also important. Do not edit it unless you've been given permission, thanks.|note.svg}}<br />
<br />
This article aims to provide a checklist and resources for developing a JavaScript-powered game engine that is compatible with [[API:Functions|Sphere's JavaScript API]].<br />
<br />
__TOC__<br />
<br />
==Introduction==<br />
Throughout this article, the original Sphere implementation shall be referred to as "vanilla" Sphere and consisted of use of an older version of [https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey] as the JavaScript engine, the first-party [http://corona.sf.net Corona library] for the software implementation of video, and the first-party [http://audiere.sf.net Audiere library] for the audio driver. Input was mapped directly in software using whatever API was native to the OS in the case of the Windows and Linux versions of vanilla Sphere. The recent Mac OS X port of vanilla Sphere used SDL to handle all input and output while still using an older version of SpiderMonkey for JavaScript.<br />
<br />
Possible frameworks to implement Sphere:<br />
* JavaScript<br />
** V8<br />
** SpiderMonkey v1.8.5<br />
** Jurassic / IronJS / JavaScript.Net / Jint<br />
* Game Libraries<br />
** SDL<br />
** SFML<br />
* Graphics libraries<br />
** OpenGL<br />
** pixi.js / three.js<br />
** DirectX (DirectDraw)<br />
** hand-rolled software renderer.<br />
* Audio libraries<br />
** Audiere<br />
** Libsndfile<br />
** BASS<br />
** Irrklang<br />
** FMod<br />
<br />
<br />
(TODO: more)<br />
<br />
==Input==<br />
<br />
GetKey() must be able to block the sphere engine. If your key queue is zero, go into a loop that just updates the game screen.<br />
<br />
=== SFML ===<br />
If you are using SFML, you need to handle the key pressed and released events. It's a good idea to use a static array for all of the keys, mouse, and joystick buttons. The array's index corresponds with a key, mouse, and joystick code with a true/false value indicating IsPressed. In order to support more than one joystick you may need to bump up that joystick array to a 2D array, where 'x' is the joystick id and 'y' is the button code.<br />
<br />
For the key queue, just use a queue data structure. Enqueue keys on the released state, and dequeue keys with GetKey.<br />
<br />
=== Key Constant Mapping ===<br />
<br />
In SDL, SFML, and other game libraries the key codes may differ from Sphere's. In order to get the correct key mapping you might need to implement a very large structure that says "this key" = "that key". This does not have to happen as it is optional so long as you keep to the same key naming conventions. What this will do is fix it so that if you saved a game with key mappings from vanilla sphere, other sphere engines can use those same codes.<br />
<br />
See key constants: (<tt>KEY_ESCAPE = 1, KEY_F1 = 2,</tt> ... etc).<br />
<br />
https://github.com/sphere-group/sphere/blob/v1.6/sphere/docs/development/keys.txt<br />
<br />
<br />
(keyboard, mouse, joystick, touch-screen?)<br />
<br />
==Output==<br />
===Video===<br />
<br />
Blitting is a process that draws the image or surface to a screen's render target prior to flipping. In web based engines this is best emulated with a "draw queue". You fill the queue with what to draw prior to a frame and update it when you are ready.<br />
<br />
(TODO: more)<br />
(TODO: multi-monitor?)<br />
(TODO: touch-screen?)<br />
<br />
===Audio===<br />
<br />
====SFML====<br />
Audio is split between sounds and music. They have the same API, but music streams intrinsically.<br />
Volume however takes a range of 0 to 100. Treat that as a percent of the 0 to 255 range Sphere uses. You might need to cache the volume into a private variable and get set from that, making sure to set the underlying volume as a percent of whatever you used.<br />
<br />
==The map engine==<br />
(TODO)<br />
<br />
===The MapEngine loop===<br />
(TODO)<br />
<br />
==Maintaining API compatibility==<br />
Sphere's original JavaScript API was written with a procedural mentality. JavaScript is a language with a powerful prototype-based inheritance system, so you may want to change Sphere's native objects such as the [[API:Color|Color object]] to allow variable creation via the ''new'' syntax; if you do this natively you must either write the equivalent loading function (in this case, [[API:CreateColor|CreateColor]]) as native code or in a scripted shim. The [[system scripts|system script]] [[Script:system/oldsphere.js|oldsphere.js]] is an example of such a shim, existing to maintain compatibility with projects written for pre-1.0 versions of Sphere. If you'd rather leave the original procedural-style loading functions but add the ability to create native Sphere objects with a working prototype constructor, visit [http://forums.spheredev.org/index.php/topic,69.0.html this forum thread] for information on doing it in script.<br />
<br />
===Compatibility with 1.5===<br />
(TODO)<br />
<br />
===Compatibility with 1.6 beta===<br />
(TODO)<br />
<br />
===Compatibility with 1.7 alpha===<br />
(TODO)<br />
<br />
===Backwards-compatibility with pre-1.5===<br />
(TODO)<br />
<br />
==List of Sphere-compatible engine implementations==<br />
===Complete or in-progress===<br />
{| class="wikitable sortable" width="100%"<br />
|+Complete or in-progress Sphere-compatible engines<br />
|-<br />
! scope="col"| Implementation<br />
! scope="col"| Operating System<br />
! scope="col"| Version<br />
! scope="col"| JS engine<br />
! scope="col"| Video driver<br />
! scope="col"| Audio driver<br />
! scope="col"| Input handler<br />
|-<br />
|vanilla Sphere<br/>[https://github.com/sphere-group/sphere source], [http://forums.spheredev.org/index.php/topic,155.0.html thread]<br />
|Win x86, OSX, Linux x86<br />
|stable: 1.5<br/>unstable: 1.6 beta 4<br/>inactive: 1.7 alpha<br />
|[https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey]<br />
|configurable<br />
|configurable<br />
|configurable<br />
|-<br />
|TurboSphere<br/>[https://github.com/FlyingJester/TurboSphere source], [http://forums.spheredev.org/index.php/topic,13.0.html thread]<br />
|Win x86/64, OSX, Linux x86/64<br />
|0.3.0<br />
|[https://code.google.com/p/v8/ V8]<br />
|OpenGL via SDL2<br />
|BASS<br />
|SDL2<br />
|-<br />
|unnamed Sphere clone in SDL<br/>[https://github.com/postcasio/sphereclone source], [http://forums.spheredev.org/index.php/topic,72.0.html thread]<br />
|?<br />
|?<br />
|[https://code.google.com/p/v8/ V8]<br />
|SDL<br />
|SDL<br />
|SDL<br />
|-<br />
|sphere-sfml<br/>[https://github.com/Radnen/sphere-sfml source], [http://forums.spheredev.org/index.php/topic,137.0.html thread]<br />
|Win x86, OSX(?)<br />
|0.65 alpha<br />
|[http://jurassic.codeplex.com/ Jurassic]<br />
|OpenGL via SFML<br />
|libsndfile via SFML<br />
|SFML<br />
|-<br />
|web-sphere<br/>[https://github.com/sphere-group/web-sphere source], [http://forums.spheredev.org/index.php/topic,154.0.html thread]<br />
|Chrome, Firefox, and IE9+<br />
|[http://www.pixijs.com/ pixi.js] version: ?<br/>[http://threejs.org/ three.js] version: ?<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|browser via pixi.js, three.js<br />
|}<br />
<br />
{{aside|Info|Although some engines are listed as compatible they will need a shim script to maintain compatibility with Sphere's API. For example, [[API:LoadImage|LoadImage]] may indeed return the correct [[API:image|image]] format by using a different API such as <tt>return new Image()</tt>.|template-info.svg}}<br />
<br />
===Discontinued or abandoned===<br />
(TODO)<br />
<br />
==See also==<br />
(TODO)<br />
<br />
[[Category:Tutorials]]</div>Radnenhttp://wiki.spheredev.org/index.php?title=Developing_a_Sphere-compatible_engine&diff=980Developing a Sphere-compatible engine2013-07-17T02:21:44Z<p>Radnen: /* Introduction */ jint not jinx</p>
<hr />
<div>{{aside|Notice|This [[:Category:Tutorials|tutorial article]] is incomplete, but it is also important. Do not edit it unless you've been given permission, thanks.|note.svg}}<br />
<br />
This article aims to provide a checklist and resources for developing a JavaScript-powered game engine that is compatible with [[API:Functions|Sphere's JavaScript API]].<br />
<br />
__TOC__<br />
<br />
==Introduction==<br />
Throughout this article, the original Sphere implementation shall be referred to as "vanilla" Sphere.<br />
<br />
Possible frameworks to implement Sphere:<br />
* JavaScript<br />
** V8<br />
** SpiderMonkey v1.8.5<br />
** Jurassic / IronJS / JavaScript.Net / Jint<br />
* Game Libraries<br />
** SDL<br />
** SFML<br />
* Graphics libraries<br />
** OpenGL<br />
** pixi.js / three.js<br />
** DirectX (DirectDraw)<br />
** hand-rolled software renderer.<br />
* Audio libraries<br />
** Audiere<br />
** Libsndfile<br />
** BASS<br />
** Irrklang<br />
** FMod<br />
<br />
<br />
(TODO: more)<br />
<br />
==Input==<br />
<br />
GetKey() must be able to block the sphere engine. If your key queue is zero, go into a loop that just updates the game screen.<br />
<br />
=== SFML ===<br />
If you are using SFML, you need to handle the key pressed and released events. It's a good idea to use a static array for all of the keys, mouse, and joystick buttons. The array's index corresponds with a key, mouse, and joystick code with a true/false value indicating IsPressed. In order to support more than one joystick you may need to bump up that joystick array to a 2D array, where 'x' is the joystick id and 'y' is the button code.<br />
<br />
For the key queue, just use a queue data structure. Enqueue keys on the released state, and dequeue keys with GetKey.<br />
<br />
=== Key Constant Mapping ===<br />
<br />
In SDL, SFML, and other game libraries the key codes may differ from Sphere's. In order to get the correct key mapping you might need to implement a very large structure that says "this key" = "that key". This does not have to happen as it is optional so long as you keep to the same key naming conventions. What this will do is fix it so that if you saved a game with key mappings from vanilla sphere, other sphere engines can use those same codes.<br />
<br />
See key constants: (<tt>KEY_ESCAPE = 1, KEY_F1 = 2,</tt> ... etc).<br />
<br />
https://github.com/sphere-group/sphere/blob/v1.6/sphere/docs/development/keys.txt<br />
<br />
<br />
(keyboard, mouse, joystick, touch-screen?)<br />
<br />
==Output==<br />
===Video===<br />
<br />
Blitting is a process that draws the image or surface to a screen's render target prior to flipping. In web based engines this is best emulated with a "draw queue". You fill the queue with what to draw prior to a frame and update it when you are ready.<br />
<br />
(TODO: more)<br />
(TODO: multi-monitor?)<br />
(TODO: touch-screen?)<br />
<br />
===Audio===<br />
<br />
====SFML====<br />
Audio is split between sounds and music. They have the same API, but music streams intrinsically.<br />
Volume however takes a range of 0 to 100. Treat that as a percent of the 0 to 255 range Sphere uses. You might need to cache the volume into a private variable and get set from that, making sure to set the underlying volume as a percent of whatever you used.<br />
<br />
==List of Sphere-compatible engine implementations==<br />
===Complete or in-progress===<br />
* vanilla Sphere (stable: 1.5, unstable: 1.6 beta 4, inactive: 1.7) ([https://github.com/sphere-group/sphere source])<br />
** JavaScript: [https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey]<br />
** Video: configurable<br />
** Audio: configurable<br />
** Input: configurable<br />
* TurboSphere ([https://github.com/FlyingJester/TurboSphere source], [http://forums.spheredev.org/index.php/topic,13.0.html thread])<br />
** JavaScript: [https://code.google.com/p/v8/ V8]<br />
** Video: SDL2<br />
** Audio: SDL2<br />
** Input: SDL2<br />
* unnamed Sphere clone in SDL ([https://github.com/postcasio/sphereclone source], [http://forums.spheredev.org/index.php/topic,72.0.html thread])<br />
** JavaScript: [https://code.google.com/p/v8/ V8]<br />
** Video: SDL<br />
** Audio: SDL<br />
** Input: SDL<br />
* sphere-sfml ([https://github.com/Radnen/sphere-sfml source], [http://forums.spheredev.org/index.php/topic,137.0.html thread])<br />
** JavaScript: [http://jurassic.codeplex.com/ Jurassic]<br />
** Video: Open GL (via SFML)<br />
** Audio: libsndfile (via SFML)<br />
** Input: SFML<br />
* web-sphere ([https://github.com/sphere-group/web-sphere source], [http://forums.spheredev.org/index.php/topic,154.0.html thread])<br />
** JavaScript: browser via pixi.js, three.js<br />
** Video: browser via pixi.js, three.js<br />
** Audio: browser via pixi.js, three.js<br />
** Input: browser via pixi.js, three.js<br />
<br />
(TODO: convert above to table?)<br />
<br />
(!) Although some engines are listed as compatible they will need a wrapper script to complete Sphere's API. For example, LoadImage may indeed return the correct image format by using a different API such as <tt>return new Image()</tt>.<br />
<br />
===Discontinued or abandoned===<br />
(TODO)<br />
<br />
==See also==<br />
(TODO)<br />
<br />
[[Category:Tutorials]]</div>Radnenhttp://wiki.spheredev.org/index.php?title=Developing_a_Sphere-compatible_engine&diff=979Developing a Sphere-compatible engine2013-07-17T02:21:01Z<p>Radnen: Added many new sections</p>
<hr />
<div>{{aside|Notice|This [[:Category:Tutorials|tutorial article]] is incomplete, but it is also important. Do not edit it unless you've been given permission, thanks.|note.svg}}<br />
<br />
This article aims to provide a checklist and resources for developing a JavaScript-powered game engine that is compatible with [[API:Functions|Sphere's JavaScript API]].<br />
<br />
__TOC__<br />
<br />
==Introduction==<br />
Throughout this article, the original Sphere implementation shall be referred to as "vanilla" Sphere.<br />
<br />
Possible frameworks to implement Sphere:<br />
* JavaScript<br />
** V8<br />
** SpiderMonkey v1.8.5<br />
** Jurassic / IronJS / JavaScript.Net / Jinx<br />
* Game Libraries<br />
** SDL<br />
** SFML<br />
* Graphics libraries<br />
** OpenGL<br />
** pixi.js / three.js<br />
** DirectX (DirectDraw)<br />
** hand-rolled software renderer.<br />
* Audio libraries<br />
** Audiere<br />
** Libsndfile<br />
** BASS<br />
** Irrklang<br />
** FMod<br />
<br />
<br />
(TODO: more)<br />
<br />
==Input==<br />
<br />
GetKey() must be able to block the sphere engine. If your key queue is zero, go into a loop that just updates the game screen.<br />
<br />
=== SFML ===<br />
If you are using SFML, you need to handle the key pressed and released events. It's a good idea to use a static array for all of the keys, mouse, and joystick buttons. The array's index corresponds with a key, mouse, and joystick code with a true/false value indicating IsPressed. In order to support more than one joystick you may need to bump up that joystick array to a 2D array, where 'x' is the joystick id and 'y' is the button code.<br />
<br />
For the key queue, just use a queue data structure. Enqueue keys on the released state, and dequeue keys with GetKey.<br />
<br />
=== Key Constant Mapping ===<br />
<br />
In SDL, SFML, and other game libraries the key codes may differ from Sphere's. In order to get the correct key mapping you might need to implement a very large structure that says "this key" = "that key". This does not have to happen as it is optional so long as you keep to the same key naming conventions. What this will do is fix it so that if you saved a game with key mappings from vanilla sphere, other sphere engines can use those same codes.<br />
<br />
See key constants: (<tt>KEY_ESCAPE = 1, KEY_F1 = 2,</tt> ... etc).<br />
<br />
https://github.com/sphere-group/sphere/blob/v1.6/sphere/docs/development/keys.txt<br />
<br />
<br />
(keyboard, mouse, joystick, touch-screen?)<br />
<br />
==Output==<br />
===Video===<br />
<br />
Blitting is a process that draws the image or surface to a screen's render target prior to flipping. In web based engines this is best emulated with a "draw queue". You fill the queue with what to draw prior to a frame and update it when you are ready.<br />
<br />
(TODO: more)<br />
(TODO: multi-monitor?)<br />
(TODO: touch-screen?)<br />
<br />
===Audio===<br />
<br />
====SFML====<br />
Audio is split between sounds and music. They have the same API, but music streams intrinsically.<br />
Volume however takes a range of 0 to 100. Treat that as a percent of the 0 to 255 range Sphere uses. You might need to cache the volume into a private variable and get set from that, making sure to set the underlying volume as a percent of whatever you used.<br />
<br />
==List of Sphere-compatible engine implementations==<br />
===Complete or in-progress===<br />
* vanilla Sphere (stable: 1.5, unstable: 1.6 beta 4, inactive: 1.7) ([https://github.com/sphere-group/sphere source])<br />
** JavaScript: [https://developer.mozilla.org/en-US/docs/SpiderMonkey SpiderMonkey]<br />
** Video: configurable<br />
** Audio: configurable<br />
** Input: configurable<br />
* TurboSphere ([https://github.com/FlyingJester/TurboSphere source], [http://forums.spheredev.org/index.php/topic,13.0.html thread])<br />
** JavaScript: [https://code.google.com/p/v8/ V8]<br />
** Video: SDL2<br />
** Audio: SDL2<br />
** Input: SDL2<br />
* unnamed Sphere clone in SDL ([https://github.com/postcasio/sphereclone source], [http://forums.spheredev.org/index.php/topic,72.0.html thread])<br />
** JavaScript: [https://code.google.com/p/v8/ V8]<br />
** Video: SDL<br />
** Audio: SDL<br />
** Input: SDL<br />
* sphere-sfml ([https://github.com/Radnen/sphere-sfml source], [http://forums.spheredev.org/index.php/topic,137.0.html thread])<br />
** JavaScript: [http://jurassic.codeplex.com/ Jurassic]<br />
** Video: Open GL (via SFML)<br />
** Audio: libsndfile (via SFML)<br />
** Input: SFML<br />
* web-sphere ([https://github.com/sphere-group/web-sphere source], [http://forums.spheredev.org/index.php/topic,154.0.html thread])<br />
** JavaScript: browser via pixi.js, three.js<br />
** Video: browser via pixi.js, three.js<br />
** Audio: browser via pixi.js, three.js<br />
** Input: browser via pixi.js, three.js<br />
<br />
(TODO: convert above to table?)<br />
<br />
(!) Although some engines are listed as compatible they will need a wrapper script to complete Sphere's API. For example, LoadImage may indeed return the correct image format by using a different API such as <tt>return new Image()</tt>.<br />
<br />
===Discontinued or abandoned===<br />
(TODO)<br />
<br />
==See also==<br />
(TODO)<br />
<br />
[[Category:Tutorials]]</div>Radnenhttp://wiki.spheredev.org/index.php?title=Developing_a_Sphere-compatible_engine&diff=976Developing a Sphere-compatible engine2013-07-16T20:40:51Z<p>Radnen: Added input comments</p>
<hr />
<div>{{aside|Notice|This [[:Category:Tutorials|tutorial article]] is incomplete, but it is also important. Do not edit it unless you've been given permission, thanks.|note.svg}}<br />
<br />
This article aims to provide a checklist and resources for developing a JavaScript-powered game engine that is compatible with [[API:Functions|Sphere's JavaScript API]].<br />
<br />
__TOC__<br />
<br />
==Introduction==<br />
Throughout this article, the original Sphere implementation shall be referred to as "vanilla" Sphere.<br />
<br />
(TODO: list possible media frameworks?)<br />
(TODO: more)<br />
<br />
==Input==<br />
<br />
GetKey() must be able to block the sphere engine. If your key queue is zero, go into a loop that just updates the game screen.<br />
<br />
=== SFML ===<br />
If you are using SFML, you need to handle the key pressed and released events. It's a good idea to use a static array for all of the keys, mouse, and joystick buttons. The array's index corresponds with a key, mouse, and joystick code with a true/false value indicating IsPressed. In order to support more than one joystick you may need to bump up that joystick array to a 2D array, where 'x' is the joystick id and 'y' is the button code.<br />
<br />
For the key queue, just use a queue data structure. Enqueue keys on the released state, and dequeue keys with GetKey.<br />
<br />
=== Key Constant Mapping ===<br />
<br />
In SDL, SFML, and other game libraries the key codes may differ from Sphere's. In order to get the correct key mapping you might need to implement a very large structure that says "this key" = "that key". This does not have to happen as it is optional so long as you keep to the same key naming conventions. What this will do is fix it so that if you saved a game with key mappings from vanilla sphere, other sphere engines can use those same codes.<br />
<br />
See key constants: (<tt>KEY_ESCAPE = 1, KEY_F1 = 2,</tt> ... etc).<br />
https://github.com/sphere-group/sphere/blob/v1.6/sphere/docs/development/keys.txt<br />
<br />
<br />
(keyboard, mouse, joystick, touch-screen?)<br />
<br />
==Output==<br />
===Video===<br />
(TODO: more)<br />
(TODO: multi-monitor?)<br />
(TODO: touch-screen?)<br />
<br />
===Audio===<br />
<br />
==List of Sphere-compatible engine implementations==<br />
===Complete or in-progress===<br />
* vanilla Sphere<br />
* TurboSphere(!)<br />
* unnamed Sphere clone in SDL<br />
* sphere-sfml<br />
<br />
(!) Although some engines are listed as compatible they will need a wrapper script to complete Sphere's API. For example, LoadImage may indeed return the correct image format by using a different API such as <tt>return new Image()</tt>.<br />
<br />
<br />
===Discontinued or abandoned===<br />
(TODO)<br />
<br />
==See also==<br />
(TODO)<br />
<br />
[[Category:Tutorials]]</div>Radnenhttp://wiki.spheredev.org/index.php?title=User:Radnen&diff=738User:Radnen2013-06-08T01:29:53Z<p>Radnen: Created my page</p>
<hr />
<div>Hi there, I'm Radnen, I live here in the USA. Sadly I haven't reached that good 'ol American dream...<br />
<br />
<br />
= About Me =<br />
<br />
I am 22 years old, serving the community with games that I have created. I have a wide area of knowledge from rpg's to mind game's and startup game's, heck, any game I can pretty much do. I can script in JavaScript, C#, C++, Java, some in Python, Ruby and Lua. I'm also fairly good with pixel artistry and simple musical composition. I like to work solo on my games, however I have worked on the Sphere Community Game, and has worked on Waudby's game Pokemon: Odyssey. Currently you'll find me working on a new Blockman release and a new Sphere Editor. I have also won one Sphere Compo with my game Hold the Line in the strategy department. You can also find me on the forums, I'll try to help as best as I can. I've used Sphere for 7+ years, so I think I know things by now (I hope)!<br />
<br />
= List of my Games =<br />
<br />
== Complete ==<br />
<br />
* Freddy Jack Nightmare in Spookland - Small NES-like 5-day game.<br />
* Hold the Line! - My first RTS game.<br />
* Pokemon Startup Game - Sphere 'startup' game, pokémon style!<br />
* Santas Little Helper - Christmas themed game.<br />
* Spherekuro - Proof of Concept Kakuro mind game.<br />
* Squared - Another Whacky mind game.<br />
<br />
== Never left the demo stage. ==<br />
<br />
* A Knights Tale - My first attempt at a real ABS.<br />
* Blockman (A + B) - My first RPG's (B is way better than A), B is a strategy/tactics styled game.<br />
* Jump - First game series I made.<br />
* Jump 2 - Second version of Jump.<br />
* Jump 3 - Last and Final version of Jump.<br />
<br />
== Abandoned ==<br />
<br />
* Bladeforge - A supposedly 350 hour epic game. An Epic Fail, that is.<br />
* Pokemon Classic - A down to the earth remake of pokémon red and blue. (Stopped while ripping)<br />
* Tyberia - A test MMO in sphere.<br />
<br />
== Future Release ==<br />
<br />
* Adventureland - A platformer. (But stopped at level construction).<br />
* Blockman "C" - My first real attempt at actually creating and finishing an RPG.<br />
* Genesis Project - A space opera RPG/simulation/shooter.</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:CreateColor&diff=678Legacy:CreateColor2013-06-04T00:22:22Z<p>Radnen: Created initial page</p>
<hr />
<div>Returns a Sphere [[API:Color|Color]] Object, to be used in color masks or drawing primitives.<br />
<br />
==Usage==<br />
<br />
{{Usage|func=CreateColor|params=r, g, b, a}}<br />
<br />
* '''r''' the red component<br />
* '''g''' the green component<br />
* '''b''' the blue component<br />
* '''a''' the alpha component<br />
<br />
==Notes==<br />
<br />
The alpha component is optional. By default it's complete opaque (255).<br />
<br />
==Examples==<br />
<br />
Create some colors:<br />
<br />
<syntaxhighlight><br />
var Red = CreateColor(255, 0 , 0);<br />
var Green = CreateColor(0 , 255, 0);<br />
var Yellow = CreateColor(255, 255, 0);<br />
<br />
var TransparentRed = CreateColor(255, 0, 0, 125);<br />
</syntaxhighlight><br />
<br />
==See also==<br />
<br />
* Sphere [[API:Color|Color]] Object<br />
* [[API:Line|Line]](x1, x2, y1, y2, color)<br />
* [[API:Point|Point]](x, y, color)<br />
* [[API:Rectangle|Rectangle]](x, y, width, height, color)<br />
* [[API:Image/blitMask|Image.blitMask]](x, y, color)<br />
* [[API:FlipScreen|FlipScreen]]()<br />
<br />
[[Category:Functions]]</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:Line&diff=677Legacy:Line2013-06-04T00:17:32Z<p>Radnen: Created initial page</p>
<hr />
<div>Draws a line to screen at location x1, y1, to location x2, y2 with a certain color.<br />
<br />
==Usage==<br />
<br />
{{Usage|func=Line|params=x1, y1, x2, y2, color}}<br />
<br />
* '''x1''' the X coordinate, start of line<br />
* '''y1''' the Y coordinate, start of line<br />
* '''x2''' the X coordinate, end of line<br />
* '''y2''' the Y coordinate, end of line<br />
* '''color''' a [[API:Color|color object]] created with [[API:CreateColor|CreateColor]]<br />
<br />
==Notes==<br />
<br />
Remember that [[API:FlipScreen|FlipScreen]] must be called before any drawing is visible on the screen.<br />
<br />
==Examples==<br />
<br />
A red diagonal line.<br />
<br />
<syntaxhighlight><br />
var Red = CreateColor(255, 0, 0);<br />
Line(0, 0, GetScreenWidth(), GetScreenHeight(), Red);<br />
</syntaxhighlight><br />
<br />
==See also==<br />
<br />
* Sphere [[API:Color|Color]] Object<br />
* [[API:CreateColor|CreateColor]](r, g, b, a)<br />
* [[API:Rectangle|Rectangle]](x, x, width, height, color)<br />
* [[API:Point|Point]](x, y, color)<br />
* [[API:FlipScreen|FlipScreen]]()<br />
<br />
[[Category:Functions]]</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:Rectangle&diff=675Legacy:Rectangle2013-06-04T00:13:56Z<p>Radnen: Created initial page</p>
<hr />
<div>Draws a rectangle to screen at location x, y, with a certain width, height, and color.<br />
<br />
==Usage==<br />
<br />
{{Usage|func=Rectangle|params=x, y, width, height, color}}<br />
<br />
* '''x''' the X coordinate, start of rectangle<br />
* '''y''' the Y coordinate, start of rectangle<br />
* '''width''' the width of rectangle<br />
* '''height''' the height of the rectangle<br />
* '''color''' a [[API:Color|color object]] created with [[API:CreateColor|CreateColor]]<br />
<br />
==Notes==<br />
<br />
Remember that [[API:FlipScreen|FlipScreen]] must be called before any drawing is visible on the screen.<br />
<br />
==Examples==<br />
<br />
Fill the screen with red. Mwahaha!<br />
<br />
<syntaxhighlight><br />
var Red = CreateColor(255, 0, 0);<br />
Rectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Red);<br />
</syntaxhighlight><br />
<br />
==See also==<br />
<br />
* Sphere [[API:Color|Color]] Object<br />
* [[API:CreateColor|CreateColor]](r, g, b, a)<br />
* [[API:Line|Line]](x1, x2, y1, y2, color)<br />
* [[API:Point|Point]](x, y, color)<br />
* [[API:FlipScreen|FlipScreen]]()<br />
<br />
[[Category:Functions]]</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:SetClippingRectangle&diff=674Legacy:SetClippingRectangle2013-06-04T00:10:57Z<p>Radnen: updated description</p>
<hr />
<div>[[Category:Functions]]<br />
<br />
Sets the drawing bounds of the screen to the width and height at the (x, y) location.<br />
<br />
==Usage==<br />
<br />
{{Usage|func=SetClippingRectangle|params=x, y, width, height}}<br />
<br />
* '''x''': the X coordinate of the clipping rectangle.<br />
* '''y''': the Y coordinate of the clipping rectangle.<br />
* '''width''': the width of the clipping rectangle.<br />
* '''height''': the height of the clipping rectangle.<br />
<br />
==Notes==<br />
<br />
Set it to 0, 0, GetScreenWidth(), GetScreenHeight() to reset it.<br />
<br />
==Examples==<br />
<br />
Clipping out a portion of a rectangle.<br />
<br />
<syntaxhighlight><br />
<br />
// restricts drawing to just this 50x50 square, at location (50, 50).<br />
SetClippingRectangle(50, 50, 50, 50);<br />
<br />
while (!IsKeyPressed(KEY_ESCAPE)) {<br />
Rectangle(0, 0, GetScreenWidth(), GetScreenHeight());<br />
FlipScreen();<br />
}<br />
<br />
</syntaxhighlight><br />
<br />
<br />
==See also==<br />
<br />
* [[API:GetClippingRectangle|GetClippingRectangle]]()<br />
* [[API:IsKeyPressed|IsKeyPressed]]()<br />
* [[API:Rectangle|Rectangle]](x, y, width, height)</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:GetClippingRectangle&diff=672Legacy:GetClippingRectangle2013-06-04T00:09:27Z<p>Radnen: updated description</p>
<hr />
<div>[[Category:Functions]]<br />
<br />
Grabs the clipping rectangle as an object with 4 properties: x, y, width, and height.<br />
<br />
==Usage==<br />
<br />
{{Usage|returns=Rectangle|func=GetClippingRectangle}}<br />
<br />
==Notes==<br />
<br />
The returned clipping rectangle has the 4 properties, x, y, width, and height.<br />
<br />
==Examples==<br />
<br />
Get the clipping rectangle (whatever it was) and print it to screen.<br />
<br />
<syntaxhighlight><br />
<br />
var clip = GetClippingRectangle();<br />
var f = GetSystemFont();<br />
<br />
var x = clip.x;<br />
var y = clip.y;<br />
var w = clip.width;<br />
var h = clip.height;<br />
<br />
while (!IsKeyPressed(KEY_ESCAPE)) {<br />
f.drawText(0, 0, "x: " + x + " y: " + y + " w: " + w + " h: " + h);<br />
FlipScreen();<br />
}<br />
<br />
</syntaxhighlight><br />
<br />
<br />
==See also==<br />
<br />
* [[API:SetClippingRectangle|SetClippingRectangle]](x, y, w, h)<br />
* [[API:IsKeyPressed|IsKeyPressed]]()<br />
* [[API:font/drawText|font.drawText]](x, y, text)<br />
* [[API:FlipScreen|FlipScreen]]()</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:SetClippingRectangle&diff=671Legacy:SetClippingRectangle2013-06-04T00:07:26Z<p>Radnen: Created initial page</p>
<hr />
<div>[[Category:Functions]]<br />
<br />
Causes the back buffer to be displayed to the screen for one time frame.<br />
<br />
==Usage==<br />
<br />
{{Usage|func=SetClippingRectangle|params=x, y, width, height}}<br />
<br />
* '''x''': the X coordinate of the clipping rectangle.<br />
* '''y''': the Y coordinate of the clipping rectangle.<br />
* '''width''': the width of the clipping rectangle.<br />
* '''height''': the height of the clipping rectangle.<br />
<br />
==Notes==<br />
<br />
Set it to 0, 0, GetScreenWidth(), GetScreenHeight() to reset it.<br />
<br />
==Examples==<br />
<br />
Clipping out a portion of a rectangle.<br />
<br />
<syntaxhighlight><br />
<br />
// restricts drawing to just this 50x50 square, at location (50, 50).<br />
SetClippingRectangle(50, 50, 50, 50);<br />
<br />
while (!IsKeyPressed(KEY_ESCAPE)) {<br />
Rectangle(0, 0, GetScreenWidth(), GetScreenHeight());<br />
FlipScreen();<br />
}<br />
<br />
</syntaxhighlight><br />
<br />
<br />
==See also==<br />
<br />
* [[API:GetClippingRectangle|GetClippingRectangle]]()<br />
* [[API:IsKeyPressed|IsKeyPressed]]()<br />
* [[API:Rectangle|Rectangle]](x, y, width, height)</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:GetClippingRectangle&diff=668Legacy:GetClippingRectangle2013-06-04T00:01:11Z<p>Radnen: Created initial page</p>
<hr />
<div>[[Category:Functions]]<br />
<br />
Causes the back buffer to be displayed to the screen for one time frame.<br />
<br />
==Usage==<br />
<br />
{{Usage|returns=Rectangle|func=GetClippingRectangle}}<br />
<br />
==Notes==<br />
<br />
The returned clipping rectangle has the 4 properties, x, y, width, and height.<br />
<br />
==Examples==<br />
<br />
Get the clipping rectangle (whatever it was) and print it to screen.<br />
<br />
<syntaxhighlight><br />
<br />
var clip = GetClippingRectangle();<br />
var f = GetSystemFont();<br />
<br />
var x = clip.x;<br />
var y = clip.y;<br />
var w = clip.width;<br />
var h = clip.height;<br />
<br />
while (!IsKeyPressed(KEY_ESCAPE)) {<br />
f.drawText(0, 0, "x: " + x + " y: " + y + " w: " + w + " h: " + h);<br />
FlipScreen();<br />
}<br />
<br />
</syntaxhighlight><br />
<br />
<br />
==See also==<br />
<br />
* [[API:SetClippingRectangle|SetClippingRectangle]](x, y, w, h)<br />
* [[API:IsKeyPressed|IsKeyPressed]]()<br />
* [[API:font/drawText|font.drawText]](x, y, text)<br />
* [[API:FlipScreen|FlipScreen]]()</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:FlipScreen&diff=432Legacy:FlipScreen2013-05-20T22:25:58Z<p>Radnen: Created FlipScreen page</p>
<hr />
<div>[[Category:Functions]]<br />
<br />
Causes the back buffer to be displayed to the screen for one time frame.<br />
<br />
==Usage==<br />
<br />
{{Usage|func=FlipScreen}}<br />
<br />
==Notes==<br />
<br />
Must be called every time you intend to draw stuff to the screen (outside the render script of the map engine).<br />
<br />
==Examples==<br />
<br />
Drawing stuff to the screen:<br />
<br />
<syntaxhighlight><br />
<br />
var a = GetSystemArrow();<br />
var f = GetSystemFont();<br />
<br />
while (!IsKeyPressed(KEY_ESCAPE)) {<br />
a.blit(50, 50);<br />
f.drawText(0, 0, "An arrow!");<br />
FlipScreen();<br />
}<br />
<br />
</syntaxhighlight><br />
<br />
<br />
==See also==<br />
<br />
* [[API:GetSystemArrow|GetSystemArrow]]()<br />
* [[API:IsKeyPressed|IsKeyPressed]]()<br />
* [[API:font/drawText|font.drawText]](x, y, text)<br />
* [[API:image/blit|image.blit]](x, y)</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:GetSystemFont&diff=431Legacy:GetSystemFont2013-05-20T22:21:57Z<p>Radnen: </p>
<hr />
<div>[[Category:Functions]]<br />
<br />
Returns A Sphere [[API:font|font]] object that is the system font.rfn found in the system/ folder of the Sphere directory.<br />
<br />
==Usage==<br />
<br />
{{Usage|returns=font|func=GetSystemFont}}<br />
<br />
==Notes==<br />
<br />
It can be changed by replacing the font.rfn file in the system/ folder in the Sphere directory.<br />
<br />
It's also useful in case you want to quickly throw up some debug numbers.<br />
<br />
==Examples==<br />
<br />
Drawing some text to the screen with Sphere's font.<br />
<br />
<syntaxhighlight><br />
<br />
var font = GetSystemFont();<br />
<br />
while (!IsKeyPressed(KEY_ESCAPE) {<br />
for (var i = 0; i < 10; ++i) {<br />
font.drawText(0, i*16, The number is: " + i);<br />
}<br />
FlipScreen();<br />
}<br />
<br />
</syntaxhighlight><br />
<br />
<br />
==See also==<br />
<br />
* [[API:IsKeyPressed|IsKeyPressed]]()<br />
* [[API:FlipScreen|FlipScreen]]()<br />
* [[API:font/drawText|font.drawText]](x, y, text)</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:GetSystemFont&diff=430Legacy:GetSystemFont2013-05-20T22:21:37Z<p>Radnen: Created GetSystemFont page</p>
<hr />
<div>[[Category:Functions]]<br />
<br />
Returns A Sphere [[API:font|font] object that is the system font.rfn found in the system/ folder of the Sphere directory.<br />
<br />
==Usage==<br />
<br />
{{Usage|returns=font|func=GetSystemFont}}<br />
<br />
==Notes==<br />
<br />
It can be changed by replacing the font.rfn file in the system/ folder in the Sphere directory.<br />
<br />
It's also useful in case you want to quickly throw up some debug numbers.<br />
<br />
==Examples==<br />
<br />
Drawing some text to the screen with Sphere's font.<br />
<br />
<syntaxhighlight><br />
<br />
var font = GetSystemFont();<br />
<br />
while (!IsKeyPressed(KEY_ESCAPE) {<br />
for (var i = 0; i < 10; ++i) {<br />
font.drawText(0, i*16, The number is: " + i);<br />
}<br />
FlipScreen();<br />
}<br />
<br />
</syntaxhighlight><br />
<br />
<br />
==See also==<br />
<br />
* [[API:IsKeyPressed|IsKeyPressed]]()<br />
* [[API:FlipScreen|FlipScreen]]()<br />
* [[API:font/drawText|font.drawText]](x, y, text)</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:GetKey&diff=429Legacy:GetKey2013-05-20T22:16:36Z<p>Radnen: /* Notes */</p>
<hr />
<div>[[Category:Functions]]<br />
<br />
Returns one instance of a KEY_* constant in the internal key queue.<br />
<br />
==Usage==<br />
<br />
{{Usage|returns=bool|func=GetKey}}<br />
<br />
==Notes==<br />
<br />
Best used with [[API:AreKeysLeft|AreKeysLeft]]() since this can block all execution until a key has been encountered.<br />
<br />
==Examples==<br />
<br />
Blocking execution from continuing. It'll count each time you hit a random key.<br />
<br />
<syntaxhighlight><br />
<br />
var font = GetSystemFont();<br />
<br />
for (var i = 0; i < 10; ++i) {<br />
font.drawText(0, 0, i);<br />
FlipScreen();<br />
GetKey();<br />
}<br />
<br />
<br />
</syntaxhighlight><br />
<br />
It can also be used to clear the key buffer.<br />
<br />
<syntaxhighlight><br />
<br />
while (AreKeysLeft()) GetKey();<br />
<br />
</syntaxhighlight><br />
<br />
<br />
==See also==<br />
<br />
* [[API:AreKeysLeft|AreKeysLeft]]()<br />
* [[API:GetSystemFont|GetSystemFont]]()<br />
* [[API:FlipScreen|FlipScreen]]()<br />
* [[API:font/drawText|font.drawText]](x, y, text)</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:GetKey&diff=428Legacy:GetKey2013-05-20T22:16:15Z<p>Radnen: Created GetKey page</p>
<hr />
<div>[[Category:Functions]]<br />
<br />
Returns one instance of a KEY_* constant in the internal key queue.<br />
<br />
==Usage==<br />
<br />
{{Usage|returns=bool|func=GetKey}}<br />
<br />
==Notes==<br />
<br />
Best used with [[API:AreKeysLeft|AreKeysLeft]() since this can block all execution until a key has been encountered.<br />
<br />
==Examples==<br />
<br />
Blocking execution from continuing. It'll count each time you hit a random key.<br />
<br />
<syntaxhighlight><br />
<br />
var font = GetSystemFont();<br />
<br />
for (var i = 0; i < 10; ++i) {<br />
font.drawText(0, 0, i);<br />
FlipScreen();<br />
GetKey();<br />
}<br />
<br />
<br />
</syntaxhighlight><br />
<br />
It can also be used to clear the key buffer.<br />
<br />
<syntaxhighlight><br />
<br />
while (AreKeysLeft()) GetKey();<br />
<br />
</syntaxhighlight><br />
<br />
<br />
==See also==<br />
<br />
* [[API:AreKeysLeft|AreKeysLeft]]()<br />
* [[API:GetSystemFont|GetSystemFont]]()<br />
* [[API:FlipScreen|FlipScreen]]()<br />
* [[API:font/drawText|font.drawText]](x, y, text)</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:AreKeysLeft&diff=427Legacy:AreKeysLeft2013-05-20T22:10:08Z<p>Radnen: Created AreKeysLeft page</p>
<hr />
<div>[[Category:Functions]]<br />
<br />
Returns true if there are keys left, false if otherwise. "keys left" in this case means: are there any unprocessed keys in the internal key queue?<br />
<br />
==Usage==<br />
<br />
{{Usage|returns=bool|func=AreKeysLeft}}<br />
<br />
==Notes==<br />
<br />
Best used in a loop to capture input.<br />
<br />
==Examples==<br />
<br />
Handling key presses:<br />
<br />
<syntaxhighlight><br />
<br />
while (AreKeysLeft()) {<br />
switch (GetKey()) {<br />
case KEY_ENTER:<br />
// do something on enter.<br />
break;<br />
case KEY_ESCAPE:<br />
// do something on escape.<br />
break;<br />
case KEY_SPACE:<br />
// do something on space.<br />
break;<br />
}<br />
}<br />
<br />
</syntaxhighlight><br />
<br />
It can also be used to clear the key buffer.<br />
<br />
<syntaxhighlight><br />
<br />
while (AreKeysLeft()) GetKey();<br />
<br />
</syntaxhighlight><br />
<br />
<br />
==See also==<br />
<br />
* [[API:GetKey|GetKey]]()</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:Sound/pause&diff=426Legacy:Sound/pause2013-05-20T22:04:51Z<p>Radnen: /* Examples */ updated example</p>
<hr />
<div>Play a loaded sound.<br />
<br />
==Usage==<br />
{{Usage|object=sound|func=pause}}<br />
<br />
* '''sound''' Sphere [[API:Sound|Sound]] object. The sound to pause.<br />
<br />
==Examples==<br />
Pausing a sound with the enter key:<br />
<br />
<syntaxhighlight lang="javascript"><br />
var my_music = LoadSound("your_sound.ogg");<br />
var toggle = false;<br />
<br />
my_music.play(true);<br />
<br />
while (!IsKeyPressed(KEY_ESCAPE))<br />
{<br />
while (AreKeysLeft()) {<br />
if (GetKey() == KEY_ENTER) toggle ? my_music.play() : my_music.pause();<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
Note that the above is different from stop which will restart the sound on play.<br />
<br />
==See also==<br />
* Sphere [[API:Sound|Sound]] object<br />
* [[API:Sound/play|Sound.play]](repeat)<br />
* [[API:Sound/isPlaying|Sound.isPlaying]]()<br />
* [[API:Sound/stop|Sound.stop]]()<br />
* [[API:AreKeysLeft|AreKeysLeft]]()<br />
* [[API:FlipScreen|FlipScreen]]()<br />
* [[API:Font/drawText|Font.drawText]]()<br />
* [[API:Font/getHeight|Font.getHeight]]()<br />
* [[API:GetSystemFont|GetSystemFont]]()<br />
* [[API:IsKeyPressed|IsKeyPressed]]()<br />
<br />
[[Category:Functions]]</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:Sound/stop&diff=425Legacy:Sound/stop2013-05-20T22:03:25Z<p>Radnen: Creates sound.stop page</p>
<hr />
<div>Play a loaded sound.<br />
<br />
==Usage==<br />
{{Usage|object=sound|func=stop}}<br />
<br />
* '''sound''' Sphere [[API:Sound|Sound]] object. The sound to stop.<br />
<br />
==Examples==<br />
Stopping and playing sound with the enter key:<br />
<br />
<syntaxhighlight lang="javascript"><br />
var my_music = LoadSound("your_sound.ogg");<br />
var toggle = false;<br />
<br />
my_music.play(true);<br />
<br />
while (!IsKeyPressed(KEY_ESCAPE))<br />
{<br />
while (AreKeysLeft()) {<br />
if (GetKey() == KEY_ENTER) toggle ? my_music.play() : my_music.stop();<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
Notice the above is different from pause which will continue where you left off.<br />
<br />
==See also==<br />
* Sphere [[API:Sound|Sound]] object<br />
* [[API:Sound/play|Sound.play]](repeat)<br />
* [[API:Sound/isPlaying|Sound.isPlaying]]()<br />
* [[API:Sound/pause|Sound.pause]]()<br />
* [[API:IsKeyPressed|IsKeyPressed]]()<br />
<br />
[[Category:Functions]]</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:Sound/pause&diff=424Legacy:Sound/pause2013-05-20T22:00:10Z<p>Radnen: </p>
<hr />
<div>Play a loaded sound.<br />
<br />
==Usage==<br />
{{Usage|object=sound|func=pause}}<br />
<br />
* '''sound''' Sphere [[API:Sound|Sound]] object. The sound to pause.<br />
<br />
==Examples==<br />
Pausing a sound with the enter key:<br />
<br />
<syntaxhighlight lang="javascript"><br />
var my_music = LoadSound("your_sound.ogg");<br />
<br />
my_music.play(false);<br />
<br />
while (!IsKeyPressed(KEY_ESCAPE))<br />
{<br />
while (AreKeysLeft()) {<br />
if (GetKey() == KEY_ENTER) my_music.pause();<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
==See also==<br />
* Sphere [[API:Sound|Sound]] object<br />
* [[API:Sound/play|Sound.play]](repeat)<br />
* [[API:Sound/isPlaying|Sound.isPlaying]]()<br />
* [[API:Sound/stop|Sound.stop]]()<br />
* [[API:AreKeysLeft|AreKeysLeft]]()<br />
* [[API:FlipScreen|FlipScreen]]()<br />
* [[API:Font/drawText|Font.drawText]]()<br />
* [[API:Font/getHeight|Font.getHeight]]()<br />
* [[API:GetSystemFont|GetSystemFont]]()<br />
* [[API:IsKeyPressed|IsKeyPressed]]()<br />
<br />
[[Category:Functions]]</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:Sound/pause&diff=423Legacy:Sound/pause2013-05-20T21:58:36Z<p>Radnen: Created the sound.pause page</p>
<hr />
<div>Play a loaded sound.<br />
<br />
==Usage==<br />
{{Usage|object=sound|func=pause}}<br />
<br />
* '''sound''' Sphere [[API:Sound|Sound]] object. The sound to pause.<br />
<br />
==Examples==<br />
Pausing a sound with the enter key:<br />
<br />
<syntaxhighlight lang="javascript"><br />
var my_music = LoadSound("your_sound.ogg");<br />
<br />
my_music.play(false);<br />
<br />
while (!IsKeyPressed(KEY_ESCAPE))<br />
{<br />
while (AreKeysLeft()) {<br />
if (GetKey() == KEY_ENTER) my_music.pause();<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
==See also==<br />
* Sphere [[API:Sound|Sound]] object<br />
* [[API:Sound/play|Sound.play]](repeat)<br />
* [[API:Sound/pause|Sound.isPlaying]]()<br />
* [[API:Sound/stop|Sound.stop]]()<br />
* [[API:AreKeysLeft|AreKeysLeft]]()<br />
* [[API:FlipScreen|FlipScreen]]()<br />
* [[API:Font/drawText|Font.drawText]]()<br />
* [[API:Font/getHeight|Font.getHeight]]()<br />
* [[API:GetSystemFont|GetSystemFont]]()<br />
* [[API:IsKeyPressed|IsKeyPressed]]()<br />
<br />
[[Category:Functions]]</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:Sound/isPlaying&diff=422Legacy:Sound/isPlaying2013-05-20T21:55:10Z<p>Radnen: /* See also */</p>
<hr />
<div>Play a loaded sound.<br />
<br />
==Usage==<br />
{{Usage|object=sound|func=isPlaying}}<br />
<br />
* '''sound''' Sphere [[API:Sound|Sound]] object. The sound to get info from.<br />
<br />
==Examples==<br />
Waiting for a sound to finish:<br />
<br />
<syntaxhighlight lang="javascript"><br />
var font = GetSystemFont();<br />
var my_music = LoadSound("your_sound.ogg");<br />
<br />
my_music.play(false);<br />
<br />
while (my_music.isPlaying())<br />
{<br />
font.drawText(0, 0, "I'm playing!");<br />
FlipScreen();<br />
}<br />
</syntaxhighlight><br />
<br />
==See also==<br />
* Sphere [[API:Sound|Sound]] object<br />
* [[API:Sound/play|Sound.play]](repeat)<br />
* [[API:Sound/pause|Sound.pause]]()<br />
* [[API:Sound/stop|Sound.stop]]()<br />
* [[API:AreKeysLeft|AreKeysLeft]]()<br />
* [[API:FlipScreen|FlipScreen]]()<br />
* [[API:Font/drawText|Font.drawText]]()<br />
* [[API:Font/getHeight|Font.getHeight]]()<br />
* [[API:GetSystemFont|GetSystemFont]]()<br />
* [[API:IsKeyPressed|IsKeyPressed]]()<br />
<br />
[[Category:Functions]]</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:Sound/isPlaying&diff=421Legacy:Sound/isPlaying2013-05-20T21:53:30Z<p>Radnen: /* Examples */ small mistake</p>
<hr />
<div>Play a loaded sound.<br />
<br />
==Usage==<br />
{{Usage|object=sound|func=isPlaying}}<br />
<br />
* '''sound''' Sphere [[API:Sound|Sound]] object. The sound to get info from.<br />
<br />
==Examples==<br />
Waiting for a sound to finish:<br />
<br />
<syntaxhighlight lang="javascript"><br />
var font = GetSystemFont();<br />
var my_music = LoadSound("your_sound.ogg");<br />
<br />
my_music.play(false);<br />
<br />
while (my_music.isPlaying())<br />
{<br />
font.drawText(0, 0, "I'm playing!");<br />
FlipScreen();<br />
}<br />
</syntaxhighlight><br />
<br />
==See also==<br />
* Sphere [[API:Sound|Sound]] object<br />
* [[API:Sound/play|Sound.play]]()<br />
* [[API:Sound/pause|Sound.pause]]()<br />
* [[API:Sound/stop|Sound.stop]]()<br />
* [[API:AreKeysLeft|AreKeysLeft]]()<br />
* [[API:FlipScreen|FlipScreen]]()<br />
* [[API:Font/drawText|Font.drawText]]()<br />
* [[API:Font/getHeight|Font.getHeight]]()<br />
* [[API:GetSystemFont|GetSystemFont]]()<br />
* [[API:IsKeyPressed|IsKeyPressed]]()<br />
<br />
[[Category:Functions]]</div>Radnenhttp://wiki.spheredev.org/index.php?title=Legacy:Sound/isPlaying&diff=420Legacy:Sound/isPlaying2013-05-20T21:52:54Z<p>Radnen: Created sound.isPlaying page</p>
<hr />
<div>Play a loaded sound.<br />
<br />
==Usage==<br />
{{Usage|object=sound|func=isPlaying}}<br />
<br />
* '''sound''' Sphere [[API:Sound|Sound]] object. The sound to get info from.<br />
<br />
==Examples==<br />
Waiting for a sound to finish:<br />
<br />
<syntaxhighlight lang="javascript"><br />
var font = GetSystemFont();<br />
var my_music = LoadSound("your_sound.ogg");<br />
<br />
my_music.play(false);<br />
<br />
while (my_music.isPlaying())<br />
{<br />
font.drawText(0, 0, I"m playing!");<br />
FlipScreen();<br />
}<br />
</syntaxhighlight><br />
<br />
==See also==<br />
* Sphere [[API:Sound|Sound]] object<br />
* [[API:Sound/play|Sound.play]]()<br />
* [[API:Sound/pause|Sound.pause]]()<br />
* [[API:Sound/stop|Sound.stop]]()<br />
* [[API:AreKeysLeft|AreKeysLeft]]()<br />
* [[API:FlipScreen|FlipScreen]]()<br />
* [[API:Font/drawText|Font.drawText]]()<br />
* [[API:Font/getHeight|Font.getHeight]]()<br />
* [[API:GetSystemFont|GetSystemFont]]()<br />
* [[API:IsKeyPressed|IsKeyPressed]]()<br />
<br />
[[Category:Functions]]</div>Radnen