SPHERE SCRIPTING TUTORIAL PART 1

The beginning of scripting in sphere, from nothing to talking...

  • Rhuan
  • 03/13/2011 01:37 AM
  • 4541 views
I'll be blunt. I'm writing this largely out of a desire to do something relaxing, and only partly out of a desire to provide a tutorial. I do however like to do whatever I do to a high standard, so hopefully it will still be useful.

The Premise
I have a vague hope that more people will, out of a desire to have more flexibility in their games, try sphere instead of RPG Maker.

So, I'm going to assume now that my reader is giving Sphere a try, but has no idea how to get a game going. They can click around in the editor, they quickly see that they can import rpg maker character sets to be sphere sprite sets, they can import rpgmaker chip sets to be sphere tile sets, and they can get to work with the map maker (side note, whilst it isn't technically legal to use rtp resources for non-rpgmaker games, many other rpg maker resources, can be used), but how do they get a game to do anything? Where is the data base of character stats? How do you define who the main character is and what map he should start on? Where do you set up enemies? the questions could continue in this vein for some time...

All of these questions are jumping the gun somewhat with Sphere. Sphere does not have a default stat system, a default menu system or a default battle system, it doesn't even have a default talking system. I intend to show you how that is a good thing as it gives you great flexibility, the entire tutorial or which this is part 1 will show you how to make everything up to battle systems in sphere, nothing you see in this part 1 will be particularly fancy but if you are willing to stick with it, great things await :)

The Beginning
So, as you may have guessed from the above, or may already know, with Sphere one has to make many of the systems one would take for granted in RPG Maker oneself. To do this one writes Javascript scripts. A sphere game begins with it's main script, if you double click on the "Game Settings" option in the editor, one of the few things you can choose is what the game's main script is, then when you try to run the game, it will execute that script, everything else you want to have happen must branch out from that script.

I will now assume that you have created your first script file and it is set as your game's main script (Sphere automatically sets the first script you create as the game’s main script, you can change it in the Game Settings), I will further assume that it is currently a blank file. If you try running the game at this point sphere quit with the error "game is not defined".

A sphere script will normally contain various "functions", Sphere expects a game's main script to contain a function called "game", after reading in the main script it will attempt to run the function called game, the above error therefore is due to the absence of this function, to remove the error we must create it, a function is defined as follows:
function name_of_function (parameters)
{//this marks the beginning of a specific block of code
  //stuff you want it to do
}//this marks the end of a specific block of code

The key word function tells sphere that what it's about to examine is a function. It's name must not contain any spaces or special characters, just letters, numbers and underscores are permitted, it's name must not begin with a number. Parameters are bits of information the function should expect to receive we'll get onto those later (Note, he game function can't take parameters as there is nothing to give it the parameters it being the start of the game). You'll note I put a // in front of the "stuff you want it to do" a // tells sphere that anything else on that line is a comment, and sphere should ignore it, comments are useful if someone else needs to use your code or if you are going to come back to it later. You can use them to explain what the code does. Comments can be spread across multiple lines or inserted in the middle of a line by starting with /* and ending with */ instead of using //.

Back to our game function then, a basic game function that does nothing at all would be as follows:
function game()
{
  //there is nothing here
}

Remember to save the script before trying to run the game again. With this as your main script, sphere will no longer throw an error it will just quit without doing anything. Obviously this isn't quite what we want...

Doing Something
At this point I'd like you to remind you that Sphere is a game making engine and it does come with various in built facilities. There is an important file in the Sphere docs folder called api.txt, which if you use sphere a lot you should come to love, it lists all of Sphere's in-built functions that you can call from a script.

I'm now going to assume that you have some sort of sphere map made, and a sphere spriteset ready for use.
Using four functions from api.txt you can alter your game function as follows (note I've assumed your spriteset is called my_spriteset.rss and your map is called my_map.rmp, either re-name them or alter those names in the below:
function game()
{
  CreatePerson("Jeff", "my_spriteset.rss", false);//create an entity called Jeff with the spriteset "my_spriteset.rss"
  AttachInput("Jeff");//Set the arrow keys to make Jeff walk around
  AttachCamera("Jeff");//make the camera follow Jeff, so as he walks around a large map the camer will move him
  MapEngine("my_map.rmp", 60);//open the map "my_map.rmp" with a max frame rate of 60
}

This should give you a person using your spriteset who you can move around your map with the arrow keys until you press escape, note this will be 8 direction pixel by pixel movement, if you want a different sort of movement system, that can be done (e.g. tile by tile movement, 4 directional movement, isometric directions instead of compass points, etc) though will require a bit more work.

To give a bit more detail on the above code:
CreatePerson(name, spriteset, destroy_with_map) makes an entity or person that can move around on a map, the name you give it is merely a way of referring to it at a future point and won't necessarily be displayed on the screen in game at any time. The spriteset you tell it to use must exist in the game's spriteset folder, destroy_with_map should be either true or false, if true this entity is to be deleted when you change map, if false it isn't. You can place entities on maps in the map editor, which are automatically kept only on the map you place them on, so using this command with the true option would take very specific circumstances, perhaps if you always teleport to a specific map for your battle system you may want to create entities on it and later delete them (this isn't how I'd do a battle system).

AttachInput(person_entity) Tells sphere that the person_entity specified is to be moved aorund by the arrow keys and also that they are to count as they input person for activating contact events, (i.e. bumping into another entity to start a battle or talk to them)

AttachCamera(person_entity) Tells sphere that if the person_entity walks around the map the camera should follow him, otherwise in attempting to explore a large map you'll walk off of the side of the screen, you may want to detach the camera for cut scenes, or attach it to someone else, for this reason there is the partner function DetachCamera(), it requires no parameter as it just removes it from whoever it's attached to.

MapEngine(map, fps) Tells sphere to open the Map Engine with the specified map and to try and run at the specified frames per second, if the computer is not fast enough it will just run a bit slower.

Making Progress
A person walking around on a map is obviously not the whole of a game... Unfortunately there is quite a bit to learn before we can do a lot more, unless I just give you scripts to copy and paste, but then that would not be a tutorial it would be a resource.

The next thing to learn is going to seem very abstract, I need to teach you about data types. The different types of information that you can manipulate in a sphere script. We have so far directly used four different data types:

1. function, as I explained it above I won't go into much detail now, a function is a block of script/code with a name that you can call by typing: name_of_function(parameters); We have used 4 of Sphere's in-built functions and made one of our own above.

2. string, a string is some text between quotation marks, so we used a string to name the entity we had walk around the map "Jeff", we also then used that same string to refer to him later. We further used strings to specify the spriteset to use and the map to use.

3. integer, an integer is a number with no decimal places, we used an integer above to tell Sphere what frame rate to run the map engine at: 60.

4. boolean, a boolean is either: true or false, we used one to tell Sphere that if we were to change map at a future point we would want "Jeff" to move onto the new map. Note a boolean does not ahve quotation marks around it, put quotation marks around it and you get string instead.

There are however several other types of data that we will need:

1. undefined, undefined is exactly that, undefined, if you wish to specify that something should be undefined you should type the word undefined. (note if you put quotation marks around it, it becomes a string instead of being undefined) Most often this will show up in error messages, when your script has tried to use something you've forgotten to define.

2. number, I mentioned integers above you can also use numbers with decimal places in Sphere, and if in fact you do a sum on an integer that would produce a non-integer numbers, e.g. 3/2 = 1.5, Sphere will give a non-integer as the answer, for many purposes in Sphere integers and non-interger numbers are interchangeable, though some things are required to be integers, such as the frame rate for the map engine.

3. array, an array is a numbered list of different things, I will introduce how to use arrays in Sphere later on, to see the basic idea though, look at the list of data types that you are reading, it is an array...

4. object, an object is a collection of different types of data, lots of things you use in sphere are objects, you can create your own types objects, I would generally use an object to represent all the stats of a character. There are also many in-built types of objects, in some sense, most sorts of data you use in sphere including some of those I've listed above are really special types of objects (but you don't really need to know that at the moment), special sorts of object we'll be looking at soon are: fonts, window styles and images.

I now need to introduce variables, a variable is something in which you can store some data, it has a name by which you can refer to it and then the data it contains, our game function above is in fact a variable, it has a name: game, and then data, in this case, the stuff it does. A given variable can contain any one of the types of data we mentioned above, the correct way to create a variable is as follows:
var name_of_variable = data;

A passing comment, the semi-colons at the end of most lines of code, they are optional in sphere, though should make things run fractionally faster and are good practise to carry over to other forms of scripting/coding, generally any line of code that isn't a { or } and isn't followed by a { should end in a semi-colon.

Now, you probably want to do something you can see by now, how about putting text on the screen?
var font = GetSystemFont();//load sphere's default font and stick it in a variable called font

function game()
{
  font.drawText(5, 5, "Hello this is some text");//draw some text on the back-buffer at x = 5, y = 5
  FlipScreen();//replace the current screen with back-buffer
  GetKey();//wait for a key press
}


The new functions I've used can all be found in api.txt. note if you wish to use your own choice of font, the Sphere editor features a tool that will convert any font installed on your computer to a sphere font file, to use a different font, you simply replace: GetSystemFont(); with LoadFont("my_font.rfn");

Two other things may seem odd to you:

1. font.drawText
Wasn't font just a font? How is it suddenly in some way a function we can call? When sphere loads a font it creates an object, part of that object is the font itself, but the object also contains some functions, drawText is one of these, variable_name.name_of_component is the way one accesses a component of the object variable_name.

2. The idea of a back-buffer, why don't things you draw just instantly appear on the screen? Well, imagine you wish to lay up a very complicated screen with several pictures and bits of text in different places you wouldn't want a slight blur as they all appeared one after another would you? Instead whatever is on the screen at the moment remains briefly and then it is cleared and everything you've draw is shown instead with the FlipScreen command.

Putting together what we've learnt so far we could create some sort of lame introduction for a game:
var font = GetSystemFont();//load sphere's default font and stick it in a variable called font

function game()
{
  font.drawText(5, 5, "Along time ago in a galaxy far far away...");//draw some text on the back-buffer at x = 5, y = 5
  font.drawText(15, 40, "Not much was going on.");//draw some text on the back-buffer at x = 15, y = 40
  FlipScreen();//replace the current screen with back-buffer
  GetKey();//wait for a key press
  font.drawText(30, 50, "Untill...");//draw some text on the back-buffer at x = 30, y = 50
  FlipScreen();//replace the current screen with back-buffer
  GetKey();//wait for a key press
  font.drawText(40, 60, "A man walked on a map!!!");//draw some text on the back-buffer at x = 40, y = 60
  FlipScreen();//replace the current screen with back-buffer
  GetKey();//wait for a key press
  CreatePerson("Jeff", "my_spriteset.rss", false);//create an entity called Jeff with the spriteset "my_spriteset.rss"
  AttachInput("Jeff");//Set the arrow keys to make Jeff walk around
  AttachCamera("Jeff");//make the camera follow Jeff, so as he walks around a large map the camer will move him
  MapEngine("my_map.rmp", 60);//open the map "my_map.rmp" with a max frame rate of 60
}


Talking
The first thing an RPG needs is the ability for someone to talk to your main character. You probably want text to appear in a box. So, the first question is how do we make a box? Boxes are handled in a similar fashion to text:
var box = GetSystemWindowStyle();//load Sphere's default  box
box.setColorMask(CreateColor(200, 100, 0, 200));//change the colour of the box

function game()
{
  box.drawWindow(10, 50, 100, 40); //draw a box at x = 10, y = 50 that is 100 pixels wide and 40 pixels high
  FlipScreen();
  GetKey();
}

Note, changing the colour of the box is optional, you can of course make your own box and use LoadWindowStyle("my_box.rws"); if you don't want to, changing the colour is a good second best, setColorMask is a component of any window style object (or font object for that matter) that will alter it's colour, it requires a color object as its parameter, CreateColor makes a color object, the four numbers are values for red, green, blue and alpha, each is out of 255, with 255 being the most possible, alpha is opaque-ness, 0 alpha makes something invisible, 255 makes it completely opaque, any number in between and it will be to some extent transparent so you will see something of what is underneath it.

As talking is something you'll probably want a lot of in an rpg, and you won't want to type a lot of code each time you want people to talk, you should make a separate function for talking:
var box = GetSystemWindowStyle();//load Sphere's default  box
box.setColorMask(CreateColor(200, 100, 0, 200));//change the colour of the box
var font = GetSystemFont();//load sphere's default font and stick it in a variable called font
var screen_width = GetScreenWidth();/*find out the dimensions of the game, these can be set in the Game Settings, you
could enter them manually here as integers instead of using these functions*/
var screen_height = GetScreenHeight();

function game()
{
  Talk("Bob", "You have no idea how to even hold a sword yet, how on earth do you expect to go and kill the demon king," + 
  " this is so out of your league it's not even funny, you nincompoop");//Bob tells you how it is
}/*note the text was split into two to stop it going off the edge of the page in the tutorial,
sphere will combine two strings separated by a +*/

function Talk(name, text)
{
  box.drawWindow(5, Math.floor(screen_height * (3/4)), screen_width - 10, Math.floor(screen_height *(1/4)));
  font.drawTextBox(5, Math.floor(screen_height * (3/4)), screen_width - 10, Math.floor(screen_height *(1/4)), 0, name + ":\n\t" + text);
  FlipScreen();
  GetKey();
}

drawTextBox gives you word wrapped text, as opposed to the standard drawText which just gives you a single line of text however much you type. it's parameters are x, y, width, height, offset and then text, offset draws the text down or up a certain amount of pixels from the top of the box, anything outside of the box is not displayed, if you want to draw a large amount of text and have it scroll in the box so part of it is visible to begin with and a different part later, you could use a loop (I'll introduce those in a bit) and keep increasing the offset, for now I'm assuming your text will fit in one box.

Math is not a sphere object, it's a standard component of javascript, Math.floor rounds down a number to the nearest integer, I use it here as drawWindow and drawTextBox both require integer parameters. / means divide, * means multiply.

+ means add, with strings this puts one onto the end of the one before it, the ":\n\t" means :, new line, tab, a nice-ish text format.

You probably want to know how to use this on a map. The first thing to do is to create an entity on your map in the map editor, and give it an "OnActivateTalk" script: Talk("James", "Hello, I'm called James.");

The next thing you need is SetTalkActivationKey(key), this specifies a key to trigger an an entities OnActivateTalk if you're standing next to said entity, (the names of keys to use in sphere are given in keys.txt in it's docs folder) then you want to change your game function back to the one that sticks you on the map, finally there is something to add to your Talk function, namely you want it to draw the map behind the text box, as it will seem very weird if you go from being on a map to a black with a text box and then back to the map when you close the text box. To handle this simply you'll need the RenderMap() function, if you're only ever going to call Talk from maps that is all you need, if you may call it when you're not on a map you need a way to check you're on a map, enter the if statement:
if (some_condition)
{
  //if some condition is true we do this
}
else // this part is optional
{
  // if it's not true we do this instead
}

The condition we'll want is IsMapEngineRunning() (note we could instead of using this function have added an extra parameter to Talk called map, and then always specified either true (draw the map) or false (don't draw the map) when calling Talk, but this would involve a lot of extra typing throughout the making of an entire game, so it's a bad idea, another option would be two seperate functions (Talk and Talk_not_on_map or some equivalent names), but why duplicate code...

Putting all this together your main script should now be:
var box = GetSystemWindowStyle();//load Sphere's default  box
box.setColorMask(CreateColor(200, 100, 0, 200));//change the colour of the box
var font = GetSystemFont();//load sphere's default font and stick it in a variable called font
var screen_width = GetScreenWidth();
var screen_height = GetScreenHeight();

function game()
{
  SetTalkActivationKey(KEY_ENTER);//use the return key to talk to people
  CreatePerson("Jeff", "my_spriteset.rss", false);
  AttachInput("Jeff");
  AttachCamera("Jeff");
  MapEngine("my_map.rmp", 60);/
}

function Talk(name, text)
{
  if (IsMapEngineRunning())//see if the map engine is running
  {
    RenderMap();//draw the map, note if this is called when no map is in use sphere will probably quit, hence the condition being used
  }
  box.drawWindow(5, Math.floor(screen_height * (3/4)), screen_width - 10, Math.floor(screen_height *(1/4)));
  font.drawTextBox(5, Math.floor(screen_height * (3/4)), screen_width - 10, Math.floor(screen_height *(1/4)), 0, name + ":\n\t" + text);
  FlipScreen();
  GetKey();
}

Assuming you've added an entity with an OnActivateTalk script that calls Talk and provides two strings, a name and a block of text, you'll now be able to talk to them with the enter key.

This is a bit of a side note but if you write complicated scripts a vital one, to do with making scripts look nice, you'll note after each { I indent the next line by two spaces more than the current indentation, and then drop back by two when placing a }, different people use different amounts of spaces, some use tabs, when editing a script in the sphere editor it will maintain your indention when moving from one line to the next so you only have to use spaces for indenting when placing a { or a }, these spaces are purely cosmetic but make the code so much easier to read as each logic block is indented a bit so you can see easily what belongs together.

At this point you could place several people on a map and have them all say different stuff, not much of a game yet, but it's a start.

Posts

Pages: 1
Starscream
Conquest is made from the ashes of one's enemies.
6110
Nice to see some Sphere love here. Keep up the good work, Rhuan!
LEECH
who am i and how did i get in here
2599
Ill read this later. Tiead* now.


*edit: So tired i cant spell apparently... ):
Oh boy that's so great for me thank you very much.
Pages: 1