Sphere/Grounds Up

From Spheriki

Jump to: navigation, search
Image:Note.svg
Originally found on sphere.sf.net as Grounds Up, author Brandon Mechtley (malis)


Contents

Introduction


NOTE: This tutorial is RIDDLED WITH MISTAKES as has been pointed out to me. Currently I am not in the process of fixing it. PLEASE visit us in #sphere on esper.net if you have questions! Also, before reading this document, I recommend you read the article entitled "A Guide to Sphere" first.


I've noticed lately that there appears to be a lack of documentation for Sphere, so I decided to type up a quick tutorial to introduce you to the SDE and do a brief run-through of JavaScript and the Sphere functions. This document is always changing, so please come back here often.

This tutorial is written in a learning form, meaning that as it goes on, I will remind you how to do certain tasks but will stop doing so eventually. This is to save my time and your time as I'm sure you'll figure out how to do things the first time around, anyway. Many of the basic JavaScript chapters use W3Schools as a reference, changed to fit the style of my tutorial, changed to what I want to teach, and changed to work with Sphere. Please visit that site for some extra information.

If you would like to contact me, you can reach me at fobben at halflingmafia.com.

--Brandon Mechtley (malis)

First Things First

(originally found at http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=2)

Before you can use Sphere, you obviously need to get it. Get the latest release of Sphere and the SDE from sphere.sf.net in the "Downloads" section. It'll be under "Official Releases", obviously. Just get the newest version. This tutorial was written for Sphere 0.96b, but will most likely (slight possibility scripting will change) work with newer versions.

Note: Sphere has been upgraded to at least v1.13 since the writing of this article. Links to the latest official release can be found at Sphere:Latest. --NeoLogiX 20:52, 27 November 2007 (GMT)

Once you've downloaded it, unzip it. First, notice the directory structure. Among others, there's a directory called "startup", a directory called "system", and a directory called "games".

Games
"Games" holds all of your game projects. Each subdirectory under this is a separate game that can be played. Generally when a Sphere game is released, just its own project directory is released.
Startup
Like "games", this directory simply holds a Sphere game project, but unlike the other projects, this "game" is run automatically when engine.exe is run. So, don't ask in #sphere, to get rid of the menu and have your game "stand-alone", just take all the files out of your project directory, get rid of the files in the startup directory, and put them in here :)
System
Under this, there is a directory entitled "scripts". These are what we call "system scripts". If a game's readme says anything about needing a system script be added to this directory, this is where they go. More on these later.

Now, run engine.exe, there's a default menu that comes with Sphere as a startup project. This menu gives you access to all the current games in the "games" directory.

menu.png

Configuring Sphere

(originally found at http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=3)

"Sphere doesn't work on my computer! What do I do?" Hopefully you aren't saying this, but config.exe may be your answer. Run "config.exe" within the base Sphere directory.

config.png

Under the "Video" tab, there are a few DLL files listed. These are different drivers that Sphere can use to display video. I'm not going to explain each of these, but try them out if you're having problems. sphere_gl usually runs a bit faster, but some machines won't support it/display it strangely.

Note: standard16 and standard32 are 16-bit and 32-bit (respectively) software drivers that are guaranteed to work on every target computer, so if your chosen driver doesn't work choose one of these. For 2x scaling, use interpolate16 and interpolate32 respectively. --NeoLogiX 20:58, 27 November 2007 (GMT)

Your First Project

(originally found at http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=4)

In the Sphere base directory, run editor.exe. This is the SDE (Sphere Development Environment). Before you run to #sphere complaining, yes, it is unstable. That's being worked on.

Note: v1.13 (the version at the time of this edit) is quite stable on Windows machines, though could stand to use some improvements which are being included in an upcoming version. --NeoLogiX 21:12, 27 November 2007 (GMT)

  1. Anyway, go to File->New->Project. A window will appear with two fields: Project Name and Game Title. Project Name is the name of your project, i.e., what the directory for your project is called. Game Title is exactly that (and what the menu displays). I'm going to call the project "Demo" and the Game Title "Fooland". Click OK.
    newproject.png

    This will now create a directory sphere/games/demo
  2. You now have a window with a bunch of folders and an item that says "Game Settings".
    projecttree.png

    Double click this. Four fields: Game Title (explained already), Main Script, Screen Width, and Screen Height.
    • Main Script - There are no scripts right now, so don't worry about this.
    • Screen Width/Height - This is the screen resolution you want to run at. Sphere can run at any resolution your video driver can handle. Example resolutions, of course, are 320x240, 640x480, 800x600, 1024x768, 1280x960, 1280x1024, etc. I don't recommend running a Sphere game above 800x600. I even found 800x600 (using sphere_gl with a geforce 2 ultra) on a PII400 to be quite taxing. Typical console RPGs (SNES, etc) run at 320x240, which might not look the best. However, I'm going to select the default of 320x240. Click OK. You'll come back here in a while.
  3. Okay, so now there are all these folders you saw earlier. What are all of them for? Let me give you a brief overview of the structure of a Sphere game:
    • Maps - Maps are towns, overworld maps, dungeons, etc. Maps are composed of many evenly-placed tiles to create a world. Your character walks around on these, etc.
    • Spritesets - Spritesets (entities, sprites, whatever) are what you might use for people in your game. Your character has a spriteset, the shopkeeper has a spriteset, and even the monsters can be spritesets.
    • Scripts - This is what controls the action in your game. Your battle system, item, equipment, spell, etc system will all be defined by a script. Scripts are in the JavaScript scripting language using Spidermonkey with added functions for Sphere.
    • Sounds - Just that. Anything from a "ka-ching!" to confirm items bought to a gentle melody for a town.
    • Fonts - The look of the text in your game.
    • Window Styles - Think of an RPG. There are always boxes around most text like menus, speech, etc. These boxes are themed by a "window style".
    • Images - BMP, PNG, JPG, GIF, whatever. These are images you might use for your game. An example might be a title screen or a monster you fight.
    • Animations - AVI, MNG, etc. FMV, monster animations (depending on how you set that up), etc.
      Note: As of this edit, v1.13 only supports MNG and FLIC/FLC/FLI format animations. There was a hack by Beaker to allow for AVI movie playing, but that has yet to be included in official releases. --NeoLogiX 21:12, 27 November 2007 (GMT)

So let's get to it!

Bridgeville (the map)

(originally found at http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=5)

Let's make a map.

  1. Go to File->New->Map. Width and Height are -not- in pixels, but tiles. If you look at most any SNES RPG, you'll notice that each town, dungeon, etc is composed of a bunch of repeating tiles, no matter how much they try to trick you. Tiles can be various sizes, but, by default in Sphere, they're 16x16 pixels. We're going to leave the width and height both at 64. This is going to be a tiny town. An overworld might be gigantic, whereas a house might have a map of 15 tiles by 15 tiles. . . . if you had one house in a map for some reason.
    The next field is "Tileset". We'll leave this blank for now because we want to create a new one, but let me explain what a Tileset is. Each map consists of many repeating tiles. But some maps consist of different repeating tiles obviously. An industrial place might have walls with bolts in them, etc, whereas a dungeon might have walls made of stone and water that is red like blood. . . . or something. So each of these different "map themes" can be a different tileset. For this project, we'll only have one tileset.
    So why use multiple tilesets? What if you want to reuse them for different maps? Well, if you actually get far in your project, you'll find that you end up creating a ton of tiles and it can get hairy wading through the tileset to find what you want. Be organized before you realize you have to go through and redo everything.
    Click OK. A dialog will come up questioning your sanity. Click Yes.
  2. "Holy crap, all these little tiny annoying windows came up!" Let's organize a bit. Maximize the main window entitled "Untitled". Resize the tool windows so they're a bit smaller and don't waste space. Drag all this to the gray space under "Base" to the left so it doesn't obstruct your view.
  3. So now you have a black map. First, before we create anything, we need to create some tiles! Click on the tiles tool window, right click, and choose "append tile". Click on the second tile (it's black, but you can guess where it is, heh) and then click on the "Tileset" tab back in the main window.
  4. Now to make a tile. Over to the right you have a color palette. Click on the black square underneath the colors for your typical Windows palette.
    Choose a green color, because we need a grass tile. Click on the paint bucket in the "Image Tools" window (NOT the "Map Tools" paint bucket) and then click out in your editing box. We now have a green tile! Yay. Choose a lighter green and make some lines with the pencil tool. Choose a dark green and make some dots. Now we have a crappy, but understandable grass tile.
    grasstile.png
  5. Well we can't live on grass alone. We need some water. So right click on the "Tiles" tool window again and append another tile. Click on the third tile (there should be a black one, a grass one, then another black one, the one we want) and now you're editing the third tile. Choose a blue and fill with the paint bucket. Choose a lighter blue and use the line tool to create some blue lines across the tile. Or, if you're creative, use the pencil tool to make some curved lines that represent small waves. (This is going to be a town, not an ocean! :) Now we have some water!
    watertile.png
  6. Okay, let's stick with these tiles for now and go back to the "Map Tab". Currently, you have a black map. Well, since this is a town, we want this entire place to be filled with grass. Right click on the map editing area (area with "ST", more on that in a second, in the upper-left) and choose Fill. Say Yes to the dialog. Yay! Now we have a bunch of grass. Cool.
  7. But the grass doesn't look like it will in the RPG! It's a bit small, probably (depending on your resolution), so right click on the map area again. Go to Zoom->2x. That's a bit better while not distracting.
  8. Now we'll make a creek/river or whatnot going through the middle of this map. Click on the "5x5" button in the "Map Tools" window. Click on our water tile in the "Tiles" tool window. Now click somewhere. Yay. A 5x5 tile square of water came up. Drag all the way across the map to make the river. So now we have two lands separated by water.
  9. To cross this water, let's make a bridge. Go back into the "Tileset" tab. Append a new tile. Choose a brown and fill the tile. Choose a darker brown and make some evenly-space horizontal lines across the tile. Then choose a lighter brown and make some dots. We have a bridge with planks now!
    bridgetile.png
  10. Go back into the "Map" tab and choose the "3x3" button from the "Map Tools" window. Draw a bridge going across the river. Cool.

That's enough for now. We want to test this, but we need a character to walk around. Save your map by going to File->Save As. Save it in the "maps" subdirectory of the "Demo" directory (or whatever you named your project). I'm going to save this map as "bridgeville.rmp".

They Call Me Hero (the sprite)

(originally found at http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=6)

In a general game, you have some character. Let's call him our Hero. Well, Hero can be facing left, right, up, down, and even sometimes directions in between those. When facing each direction Hero has a few positions he is in. He can be walking, he can be laughing, crying, or even dead. For now, our Hero is only going to walk. Unfortunately, since I have absolutely no skill in creating sprites, I'm going to direct you to a site on how to make sprite art: go to the "Links" section on sphere.sf.net, and choose Tsugumo's "So You Want to Be a Pixel Artist?" This is an EXCELLENT tutorial for sprites and tiles. I'm going to use a dumb arrow for our hero, but I'll still explain how to create a sprite in the SDE:

editsprite.png
  1. Click on File->New->Spriteset. A window comes up with 8 rows with a blank image next to each. The first row is called "North", so this is the set of frames the character will be in when facing up.
  2. Next, amongst the familiar tool windows, you have a "Spriteset Images" tool window. This is how entities in Sphere work: You have a set of spriteset reference images in no particular order. Think of it like this, let's say each of these reference images has a number set to it. I have images 1, 2, 3, 4, 5, 6, 7, 8. Then, there are these fields for directions and extra frames. These are your rows. Well, each of these rows/directions/whatever can have as many of these reference images in them as they want. Say I want North to have images 1, 3, and 5 in it. When you walk North, now, this sprite will cycle through reference images 1, 3, and 5 in order that you put them in. Reference images can be reused how ever many times you want in whatever rows you want. Also, you can delete rows by right clicking on the white space with their label and choosing "Delete". If you only want a character to be able to face up, down, left, and right, just copy those directions to the intermediate ones (which is what I'm going to do). This way the character will only be able to -face- (he can still move in these) up, down, left, and right. (Gives me less work for drawing, too :)
  3. So you already have a blank image. Click on the "edit" tab. Draw your sprite facing up. (Do your work, I suck too much to give you an overview.) You can use the slider to set the opacity of a pixel. Otherwise your character will have black surrounding him. You dont want that, so choose any color (opacity will not be represented in the "Frames" tab, so, to avoid confusion, just use black) and lower the slider to 0. Then fill in around your character. The checkerboard pattern represents transparency. If you remember, this slider was in the tile editor too, so we'll learn how to use it in tiles later.
  4. Click on the "Frames" tab. Notice now that the image you just made is set to every direction! That's not what you want, but why it does that is because you only have one spriteset reference image. So, by default, it sets all the directions to use that. So right click (just like the "Tiles" tool window in the map editor) in the "Spriteset images" tool window and click "insert image". Click on the image you just added (notice the checkerboard pattern; it, by default, is completely transparent). Uh oh! The "North" frame now is transparent. So click back on the frame you drew earlier in the "Spriteset images" tool window. Phew. It's back to normal. But, now you want to edit what Hero looks like when facing East. So, in the Frames tab in the main window, click on the frame next to the "East" label. Now select the new image you made in the "Spriteset images" tool window.
  5. You don't want him to be clear when walking east, so go to the "Edit" tab and draw him facing east.
  6. Repeat steps 3-5 accordingly for each direction.
  7. Now you want to animate him. Click on the "North" row's frame. Right click and choose "Append". Make a new reference image and assign it to this frame. Do this for each. Make it look like he's walking, or something. (For my Hero [if you recall, it's an arrow], the arrow wiggles.) You can have as many frames of animation as you want.

Save your sprite in the "spritesets" subdirectory of your project directory as "hero.rss". Now we are almost to the point where we can test our demo.

Just Do What I Say

(originally found at http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=7)

We need a script to startup when the game starts up. The script tells the Sphere engine what to do. It's okay if you don't understand a thing I'm doing right now, just do what I say.

Click on File->New->Script. A blank text editing place comes up. Type the following:

function game() {
	CreatePerson("Hero", "hero.rss", false);
	AttachInput("Hero");
	AttachCamera("Hero");
	MapEngine("bridgeville.rmp", 60);
}

Whew. If you know JavaScript, let me explain what each line does.

  1. First, we have our "game" function. This is the first function that is called by the Sphere engine when you run this script as a startup script. This is where you intialize everything, etc.
  2. CreatePerson creates a Person (entity) for the map to use. We are naming this Person "Hero" and using the "hero.rss" (it automatically assumes its in sphere/demo/spritesets/) and telling it not to destroy the person when it leaves the map.
  3. AttachInput attaches keyboard input (you'll move this Person) to the Person "Hero".
  4. AttachCamera attaches the camera (so the camera/screen/whatever follows you around while you walk Hero about.) to Person "Hero".
  5. MapEngine starts the map engine (the engine in Sphere that controls all map management, walking about in towns etc.) at 60 frames per second.

Once the script is written, do the following:

  1. Save this script as "start.js" in the "scripts" subdirectory.
  2. Go back to the project window with all the folders. Double click on Game Settings. Under the field startup script, select "start.js".
  3. Make sure everything is saved etc, and either click the lightening bolt in the toolbar or run engine.exe and choose Fooland from the list.
  4. The character will start in the upper-left of the map and you can walk him around -- even over the water. We want to do away with this ability. That's next.
play1.png

Obstructions

(originally found at http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=8)

In any game, there's going to be somewhere you don't want your Hero to go. Sure, he possesses magical powers and superb fighting skills, but he can't walk through walls. So let's make it so he can't.

  1. Go to your project tree window, extend the maps folder, double click on bridgeville.rmp. Click on the water tile in the "Tiles" tool window. Right click on it and choose "Properties."
  2. Ignore animation for now, we'll get to that. Right now, click on "edit obstructions".
  3. You see your tile there, with a drop down box to the right. ("Presets"). Obstructions in Sphere are vector based, meaning you just draw some lines and when your character reaches those lines, he cant go past them. So to obstruct an entire tile, you'd just draw (try it, but get rid of what you draw by right-clicking) lines all the way around the tile. The easiest way to do some of the most common obstructions is by clicking on "Presets". Click on that and choose "Blocked".
  4. If you were to try out the game right now, your Hero would still be able to walk over water, even though we obstructed it. Think for a moment. An obstruction occurs when the obstruction vector of the tile meets the obstruction vector/box of the. . . . hey, our Hero has no obstruction that we know of! Go to your project tree window, extend spritesets, and double click on "hero.rss".
  5. Click on the "base" tab. It is easiest to edit the base of a "North" frame. Click and drag a box (it appears in pink, just like obstruction vectors) around his feet. This box will be invisible, but will define a spot on your spriteset that cant move past obstructions. In other words, his feet can't go past obstructions, but his head and such can (like if he's "in front" of a house).
  6. Now run the game and notice that our Hero can't walk over water anymore. Never fear, though! The bridge will aid him in his quest.
  7. To change where your character starts on the map (instead of the upper-left), right click somewhere on the map and click "Set Entry Point". The "ST" mentioned earlier will move to the tile you chose as the entry point.

Animation

(originally found at http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=9)

Remember that water tile? Remember the animation thing we saw in its properties? Go back.

  1. Right click on the "Tiles" tool window and choose "Append Tile."
  2. Edit the water tile, but right click on it and choose "copy."
  3. Edit the blank new tile, right click, and choose "paste."
  4. Edit this new tile as needed to make the water look like it has an east-going current. (An easy way to do this is by right clicking on the edit window and choosing Slide->Right 8 times.) Also, make sure you edit its obstructions so it is blocked, like the other water tile.
  5. Right click on the first water tile in the "Tiles" tool window. Choose "Properties."
  6. Check the box labeled "Animated."
    animmislead.png

    You'll notice that the title of this dialog says "Tile Properties 2/5." This title is misleading. You are editing Tile #2 (keep in mind that the first tile is Tile #0) out of 5 -total- tiles. That does NOT mean that #5 is the last tile. The last tile is actually #4.
  7. How an animation works is like this: Each tile as an index. The current tile you are editing has an index of 2, for instance. Then, if animated, each tile has something like a pointer, basically, pointing to the next tile in the animation. Our two water tiles are #2 and #4. So, we want #2->#4 and #4->#2, right? Right.
  8. For "Next Tile", enter "4" into the field. Delay is the time, in milliseconds, that this tile will be shown in the animation. I'm putting "100."
  9. Now, click the "Next" button until you reach #4 (title of dialog will be "4/5"). For "Next Tile" enter in "2" and for Delay, again, enter in "100."
  10. Now click OK and test the game. The water should gently "flow" to the right.

On the Rocks (layers and alpha)

(originally found at http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=10)

Well, hopefully the water in your area isn't a thick blue liquid. That'd be rather gross. Most water is translucent with a bluish tint, right? So should our water be.

  1. First we need a tile for the rocks underneath the water. We will have the wall of the creek (to indicate depth) and the actual base. Append a new tile. Edit it, fill it gray. Right click the editing area and select Filter->Noise. Do that again. Now, select Filter->Blur. You now have some rockish base.
    rocks.png
  2. Append another tile. Copy the tile you just made, edit the new blank tile, and paste. Now, about 8 pixels deep, starting at the top, choose the filled rectangle image tool and click and drag a brown rectangle covering half of the tile horizontally. Choose two more shades of brown and make some crags and such. Right click on the rock portion of this tile and choose "Color Selector." then, randomly, on the last row of pixels of the brown section, make the rock portion stick up a little by putting a couple 2-pixel lines in this row.
    rockdirt.png
  3. So now we have these two tiles. Take the tile that's half dirt/half rock and replace the top row of water in the map with this tile.
  4. Replace all the other water in the map with the pure rock tile.
  5. We don't just want a rocky pit, though. We need the water still. Here's where layers come in. Right click on the "base" button with the eye next to it and select "Insert Layer." Ack! The screen turned black! Don't worry.
  6. Append a new tile. Edit it. Turn the translucency slider all the way to 0 and fill the entire tile with this transparent color.
  7. Go back to the "Map" tab, click on the "Unnamed Layer" layer button (right click and hit "properties" to rename; I renamed it "water." A strange bug in .96b and earlier releases has it so that when you edit the layer properties, the "Reflective" check box is selected. Make sure to uncheck this. Play around with this feature if you want. Actually, reflection would look quite appropriate on water), right click on the map and choose "Fill". Hit Yes to the dialog. Whew, it's all safe and sound now.
  8. Now (make sure the "water" layer is depressed, not the "Base" layer) take the first water tile, and draw in over the rocks and rock/dirt tile. So now you ask "what the heck did I do that for? All that work on the rocks for nothing?" It was for something. Edit the first water tile. Choose any color and slide the opacity bar down to "128." Now, right click on the editing box and choose Fill->Alpha. This, ignoring color, fills in the entire tile with the "alpha" (opacity) level you chose on the slider.
    alphawater.png
  9. Do the same for the second water tile.
  10. If you were to play now, your character would walk under the water, completely ignoring the obstructions. Why? Entities only observe the obstructions on their layer. If you recall, when we set the entry point (the layer of our entitiy "Hero"), we only had the layer "Base", so our Hero is now on the base layer. We want him to walk above water, so click on the "water" layer button, right click where you want to set the entry point, and set it. It's now on that layer.
  11. Play the game and observe the alpha coolness.
play2.png

A Break from the Norm (JavaScript introduction)

originally found at the following locations:

http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=11 Chapter 10 - A Break from the Norm (JavaScript introduction)
http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=12 Chapter 11 - Javascript: Variables
http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=13 Chapter 12 - Javascript: Operators
http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=14 Chapter 13 - Javascript: Strings
http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=15 Chapter 14 - Javascript: Arrays
http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=16 Chapter 15 - Javascript: Math
http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=17 Chapter 16 - Javascript: Conditionals
http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=18 Chapter 17 - Javascript: Loops
http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=19 Chapter 18 - Javascript: Functions
http://sphere.sourceforge.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=3&page=20 Chapter 19 - Javascript: Objects

Unfortunately, we're going to take a small break from our game right now to teach you JavaScript, the high-level scripting language that Sphere uses.

  1. Open up your "start.js" and take out all the code you wrote in there earlier. Don't worry, we'll eventually get to the point where you type all that back in.
  2. Now for the introduction :)

If you have no experience in coding, hopefully I can lighten the load on you by explaining a few things: A script consists of many lines of code that tell the Sphere engine to do things. These things could include going to another line of code, repeating some lines of code often, drawing on the screen, starting the map engine, creating a character, etc. Each script consists of many functions most likely that are used to separate specific things you want to do.

Let's say you have an item system. Some functions might be GiveItem, to give an item to a character, DropItem to destroy an item you don't want, or UseItem to drink the potion etc. Each startup script (the script that the Sphere engine first looks at when it runs your game) has a function called game, as explained earlier:

function game() {
	//stuff you want to do.
}

We'll go more into why functions look like that in a bit, but that's what I want you to type in for now. You don't have to type in the //stuff you want to do. part, because that is a comment. Comments are lines of code that the engine passes up when reading your JavaScript. They're basically just little notes. Comments can be in the form of:

this is not a comment //this is a comment. The next line will not be a comment

or

/* this is a comment
this is too!
and so is this */
but this is not!

Comments show up green in the Sphere text editor.

Let's write some text to the screen:

function game() {
	GetSystemFont().drawText(0, 0, "Hello World!");
	FlipScreen();
}
  • function game(){: this is you defining your game function which was explained earlier.
  • GetSystemFont().drawText(0, 0, "Hello World!");: I'll explain the GetSystemFont(). part in a bit, but just know that this will draw the text "Hello World!" at the very upper left corner (0,0) of the screen.
  • FlipScreen(); takes all of the stuff you drew after the last FlipScreen (in this case there was no last FlipScreen, so everything you've drawn [the text]) and draws it to the screen.

Also, semicolons (;) at the end of lines are optional (though highly recommended --NeoLogiX 21:58, 27 November 2007 (GMT)). I think it organizes my thinking a bit, so I'll use them. If you think they're confusing and/or ugly, get rid of them. Anyway, save "script.js" and run it. Your first Sphere script :)

helloworld.png

Variables

A variable is a container that stores data. This value, hence the name variable, can change throughout the script. A variable, besides being assigned values, can be referenced during the script by name, too. Say you had a character. A character might have a variable called HP. HP could be numerous things. HP could have the value 5 or even 99999. Maybe your character has a name. name could be "Hero" or "Malis".

Each variable has a name, like HP or name. Variable names are case sensitive. If you have a variable HP, Hp is a different variable. Also, variable names can only begin with an underscore (_) or a letter — a variable name like 4th would not work and would generate a nasty error. However, fourth or _4th would work. Variable names should also be clear and descriptive. fourth is an ugly variable name because it makes me think "Fourth what?" A better variable name might be fourth_player.

A variable can be created using the var statement:

var HP = 5;
would create a variable named HP with a value of 5.

Now, whenever you refer to HP, you're basically referring to the number 5.

Variables can be created without the var statement as well: name = "Ruprecht"; works fine. When you refer to name, you refer to "Ruprecht".

So, = is an expression you can use to set a variable. The variable on the left side is set equal to the value on the right side. For instance:

name = "Ruprecht";
name2 = "Robert";
name = name2;

This results in two variables, name and name2, both with the value of "Robert". However, the following would not work:

"Ruprecht" = name;

Since "Ruprecht" is not a variable, you can not assign a value to it. You can only assign values to variables.

When you declare a variable within a function, the variable can only be accessed within that function. When you exit the function, the variable is destroyed. These variables are called local variables. You can have local variables with the same name in different functions, because each is recognized only by the function in which it is declared.

If you declare a variable outside a function, all the functions on your page can access it. The lifetime of these variables starts when they are declared, and ends when the game ends.

Operators

JavaScript has many operators. An example of an operator would be =, like when it was used last chapter. Here is a list of operators and what they do:

Arithmetic Operators

These operators return values. Keep in mind for later that any nonzero number is considered true 0 is always considered false

+ and -
These are used used for addition and subtraction, respectively. An example might be:
x=1;
x=x+1;
This would result in one variable, x, with a value of 2. x+2 returned the value of 2, so the variable on the left side (x) is set equal to this returned value.
* and /
These are used for multiplication and division, respectively. An example might be:
x=1;
x=x/2;
x=x*4;
This would result in one variable, x with a value of 2. The variable is first set equal to 1, then is divided by 2, making it equal to .5. The variable is then multiplied by 4, making it equal to 2.
%
This is the modulus operator. This operator returns the whole number remainder left when the value on the left of it is divided by the value on the right. For instance:
x=10%3;
This would result in one variable, x, with a value of 1. 10 is divided by 3 and the remainder of 1 is returned.
++ and --
These are the increment and decrement operators, respectively. They will add or subtract 1 to the variable upon which they operate. For example:
x = 2;
y = 3;
x++;
y--;
This results in two variables, x and y, with values of 3 and 2 respectively. x increments by 1, and y decrements by 1.

Assignment Operators

These operators assign variables returned values.

=
This sets the variable on the left side equal to the value on the right side.
+= and -=
These increment the variable on the left side by the variable on the right side. x+=5 would be equivalent to x=x+5 and x-=3 would be equivalent to x=x-3
*= and /=
Like += and -=, x*=5 would be equivalent to x=x*5 and x/=4 would be equivalent to x = x/4.
%=
x%=4 would be equivalent to x = x%4. For example:
x = 4;
x%=4;

This would result in one variable, x, with a value of 0. x was set equal to 4, but then set to the remainder of 4/4, which is 0.

Comparison Operators

These operators will test two different values.

==
This returns true if the value/variable on the left is equal to the value/variable on the right. Otherwise, it returns false.
!=
This returns true if the value/variable on the left is NOT equal to the value/variable on the right. If the two are equal, it returns false.
>
This returns true if the value/variable on the left is GREATER than the value/variable on the right. If the value/variable on the left is less than or equal to the one on the right, it returns false.
<
This returns true if the value/variable on the left is LESS than the value/variable on the right. If the value/variable on the left is greater than or equal to the one on the right, it returns false.
>= and <=
These are similar to > and <, but return true if the two values/variables are equal to each other as well.

Logical Operators

These operators test the truth of values and, based on that, return true or false.

&&
This is the and operator. It returns true if BOTH of the values on each side of it are true. For example:
(1 && 2)	//true
(0 && 2)	//false
(0 && 0)	//false
((5==5) && (4==4))	//true
As you can see, also, you can do compound statements with many different operators.
||
This is the logical or operator. It returns true if ONE OR BOTH of the values on either side is true.
!
This is the logical not operator. It returns true if the value on the right of it is false, etc. Example:
x = 1;
y = 2;
(x != y)	//returns true
(!x)	//false, x has a nonzero value
As you can see, this is the basis for operators like !=.


Whew.

Strings

Notice that in Chapter 11 we had name = "Hero". "Hero" is now a string. Also, after the statement name = "Hero" has been executed, name represents a string.

Strings can be operated on just like numbers. Here are some examples:

string1 = "Hi";
string2 = " there!";
string3 = string1+string2;
string1+=string2;
string2=string1+string2;

You now have three variables, string1, string2, and string3, that all have the value of "Hi there!".

You can get the length of a string like this:

string1 = "Foo";
lengthofit = string1.length;

This results in two variables, string1 and lengthofit. string1 is a variable with the value "Foo". lengthofit is a variable with the value of 3, because "Foo"(string1) is 3 characters long.

You can search a string with the function indexOf like this:

string1 = "Foo Bar Baz";
locationoffoo = string1.indexOf("Foo");
locationofbar = string1.indexOf("Bar");
locationofbaz = string1.indexOf("Baz");
locationofgux = string1.indexOf("Gux");

You now have five variables, string1, locationoffoo, locationofbar, locationofbaz, and locationofgux. string1 has a value of "Foo Bar Baz". locationoffoo has a value of 0 (keep in mind that the first character's index in the string is 0), because "Foo is found at the first character of the string. locationofbar has a value of 4 because "Bar" is found at the fourth character of the string. locationofbaz has a value of 8 because "Baz" is found at the eighth character of the string. However, locationofgux has a value of -1 because "Gux" was not found in the string.

You can grab a specific part of a string using either substr or substring. Here's how you use both:

string = "foo bar";
foo = string.substr(0,3);
bar = string.substring(4, 7);

You now have three variables, string, foo, and bar. string has a value of "foo bar". foo has a value of "foo" because substr took the string inside string that starts at character 0 and is 3 characters long. bar has a value of "bar" because substring took the string inside string that starts at character 4 and goes up to, but not including character 7 (which in this case doesn't exist).

To put double quotes (") in a string you use \". For example: This is a "string" would literally be: "This is a \"string\"". There are many others like this, but most commonly used are: \t - tab, \n - line break, and \\ - a backslash.

There are a few more string functions, but I don't really care to discuss them in this tutorial.

Arrays

Say you have an item system in a game. Well, thinking about it right now, you might think, "Yeesh, am I going to have to have item1, item2, item3, etc? O_o" Well, the answer is no! :) You can use arrays. An array is a variable used to set a list of values under one variable name. Imagine it like a petition. You have the petition, or petition, with a list of names underneath it. Each one of these names is an entity, element, index, whatever within the array. The first name is name 0, then name 1, etc.

petition = new Array();	//variable amounts of names can
	//be stored in here. Put 5 
	//between the ()'s if you want 
	//only 5 names.
petition[0] = "Henry";
petition[1] = "John";
petition[2] = "Chad";

You now have a petition array with 3 elements, "Henry", "John", and "Chad". So, an array is defined like this: varname = new Array(arraylength) where arraylength is optional.

Still, it gets tedious to go through with [1], [2], [3], etc. So, we'll use the push function:

petition = new Array();
petition.push("Henry");
petition.push("John");
petition.push("Chad");

The petition might look like this now:

0 - Henry
1 - John
2 - Chad

push inserts the value to be pushed as the next free array index.

Say you wanted the petition to be alphabetical, but didn't want to go through and alphabetize it yourself. You could use the sort function:

petition = new Array();
petition.push("Henry"); petition.push("John"); petition.push("Chad");
petition.sort();

Now, you have an array called petition that might look like this:

0 - Chad
1 - Henry
2 - John

This is because you sorted it. You can also sort numbers.

Maybe you wanted this sorted list to go Z-A instead of A-Z. You could use the reverse function:

//Keep the code from the last example
petition.reverse();

You now have an array that might look like this:

0 - John
1 - Henry
2 - Chad

because you reversed the array.

You can also have 2D arrays, or even 3D arrays. We'll cover a 2D array right now. A 2D array would be a matrix set up like this maybe:

00 - John   01 - Rebeckah   02 - Scott
10 - Henry  11 - Jenny      12 - Brian
20 - Chad   21 - Elizabeth  22 - Ben

It can be any size. Let's see how me might do this particular matrix:

petition = new Array(3); //we have 3 rows
petition.push(new Array(3)); //three columns in row 0
petition.push(new Array(3)); //three columns in row 1
petition.push(new Array(3)); //three columns in row 2
petition[0].push("John"); petition[0].push("Rebeckah"); petition[0].push("Scott");
petition[1].push("Henry"); petition[1].push("Jenny"); petition[1].push("Brian");
petition[2].push("Chad"); petition[2].push("Elizabeth"); petition[2].push("Ben");

You now have one array, comprised of many arrays inside it that may look like the array above.

There are more array functions. I recommend you look into those as well.

Math

This is just a brief overview of the Math object. This allows you to do a few mathematical operations and such.

Math.abs(x): This will return the absolute value of x.
Math.acos(x): This returns the arccosine of x.
Math.asin(x): This returns the arcsine of x.
Math.atan(x): This returns the arctangent of x.
Math.atan2(x): This returns the angle from the x axis to a point (x, y)
Math.ceil(x): This rounds x up to the next integer.
Math.cos(x): This returns the cosine of x.
Math.exp(x): This returns the value of e to the x
Math.floor(x): This rounds x down to the next integer.
Math.log(x): This returns the natural log of x.
Math.max(x,y): This returns the value of whichever number (x or y) is larger.
Math.min(x,y): This returns the value of whichever number (x or y) is smaller.
Math.pow(x,y): This returns the value of base x raised to exponent y.
Math.random(): This returns a random number between 0 and 1, to get a random number between 0 and 10 you might do Math.random()*10.
Math.round(x): This rounds x to the nearest integer.
Math.sin(x): This returns the sine of x.
Math.sqrt(x): This returns the square root of x.
Math.tan(x): This returns the tangent of x.

You'll find these to come in quite handy.

Conditionals

Well, you can't have your game just do stuff. You want it to do different things at different times. If your HP == 0, you want your character to die. If the princess is not yet saved, you want to have to save her. If, if, if, if. Here's an introduction to the if conditional statement.

The if statement will run if the condition is true and either run something else or run nothing if the conditional is false. Here's the general structure of an if statement:

if (conditional) {
	// stuff
} 
else if (conditional) {
	// other stuff
} 
else if . . . 
else if . . . 
else {
	//stuff that runs if NONE of those are true
}

A conditional might be (HP==0):

if (HP==0) {
	KillCharacter();
}
else if (Paralyzed) {	//if Paralyzed is true
	KillCharacter();
}
else {
	//continue battle
}

As you can see, else if is used when the conditional(s) above it are not met. Same as else.

Well, a bunch of else ifs might get messy, so here's what we call a switch statement:

var font = GetSystemFont();
switch (money) {
	case 0: font.drawText(0,0,"you are broke"); break;
	case 50: font.drawText(0,0,"you are low on money"); break;
	case 100: font.drawText(0,0,"you're rich!"); break;
	default: font.drawText(0,0,"money is some value");
}

If money equals 0, "you are broke" is printed to the screen. If money equals 50, "you are low on money" is printed to the screen. If money equals 100, "you're rich!" is printed to the screen. If money is not any of these, it resorts to using default, and prints "money is some value" to the screen. Without the breaks, the Sphere engine would go straight through and print all four things to the screen.

JavaScript also contains a conditional operator that assigns a value to a variable based on some condition. It is in the format: varname=(condition)?value_if_true:value_else. If condition is met, varname is assigned value_if_true. If condition is NOT met, varname is assigned value_else.

Loops

You may want to execute some code many times in your game. A prime example of this is what, in game design, is called the main game loop. A loop is a body of code executed many times over consecutively. . . . well, that's how I'll define it. Okay, okay, just copying and pasting isn't a loop. But here's an example of a for loop:

var font = GetSystemFont();
for (i=0; i<10; i++) {
	font.drawText(0, i*20; "line " + i);
}
FlipScreen();
forloop.png

Every for loop is initiated with "for". Then, you need a control variable for the loop. In this case, it is i. A control variable controls how many times a loop will execute its body of code. The first argument in a for loop initiates such a variable. We're starting i at 0. The next argument specifies a condition for if the loop should execute its body of code or not. The condition we have is "i must be less than 10." The next argument is a step or increment. This indicates what will happen to the control variable each time the loop executes its body of code. In this situation, i (our control variable) is increased by 1. So, in other words, this for loop's body will be executed until i is equal to 10, i raising by 1 each time. This loop will execute its body 10 times. FlipScreen() is executed outside of the body because we only want it executed once. Otherwise we're only going to see "line 9" on the screen.

Another type of loop you can do is a while loop. A while loop simply executes its body while a certain condition is true. For example:

i = 10;
while (i > 0) {
  --i;	// can also put ++ or -- before a variable
  // do stuff
}

The body of this will be executed while i is greater than 0. Keep in mind no control variable is absolutely necessary here. I just use one in this case to show when the loop will terminate. Notice that my control variable's decrement is located within the body.

Functions

A function was explained earlier as this: If you have an item system, you might want to GiveItem, DropItem, and UseItem. Here's the basic structure of a function:

function funcname(arg1, arg2, arg3 . . . ) {
	// stuff you want to do
	return somevalue;
}

First, you have the declaration function. Every function has this. Then, you have the name of the function. In this case, it is funcname. The function would be called (executed somewhere else in your script) with funcname(). Then, in parentheses, you have your arguments. Arguments are variables that hold values that are used in your function and passed to it. Then, you have some lines of code to do something, and if you did something to the arguments that you want to return, do so with return followed by the value you wish to return. return can only be called once and will exit the function. For example, I'll make a function that finds the average of 4 numbers:

function avgfour(num1, num2, num3, num4) {
	var ret = (num1+num2+num3+num4)/4;
	return ret;
}
 
function game() {
	numbers = new Array(4);
	numbers.push(5); numbers.push(6); numbers.push(10); numbers.push(12);
	GetSystemFont().drawText(0,0,avgfour(numbers[0], numbers[1], numbers[2], numbers[3]));
	FlipScreen();
}

This program should display 8.25 on the screen. If it doesn't, the first four characters should be 8.25 and there should be an amount of 0s followed by a non-zero digit. Notice that your own custom functions are called just like JavaScript/Sphere built-in functions.

A function can also be a variable:

function somefunction(f, arg) {
	f(arg);
}
 
a = function(someargument) {
	//dosomething
}
 
somefunction(a);	//and can be passed 
                	//just like a variable

Objects

In an item system, each item may have different properties to it. cost, effect, name, description, and type are all worthy candidates. However, you wouldn't want to just create an array of items costs, effects, names, etc. The easiest way to make use of this is through an object.

An object is basically just a function with member functions and variables. Here's a simple object that I'll explain:

gMoney = 100;
 
function item(name, description, cost, effect, type) {
	this.effect = effect;
	this.type = type;
	this.name = name;
	this.description = description;
	this.cost = cost;
}
 
item.prototype.use = function() {
	eval(effect);
}
 
item.prototype.buy = function() {
	gMoney -= this.cost;
}
 
item.prototype.sell = function() {
	gMoney += this.cost/2;
}
 
function game() {
	powbox = new item("Pow Box", "it goes pow!", 50, "GetSystemFont().drawText(0, 0, "Pow!")", 1);
}

"Wow, that's a lot!" Let me explain it all. First of all, we set up gMoney as a global variable because it is declared outside of any function (as explained earlier). We want our money to be global because we're probably going to be accessing it quite a bit throughout many functions. Then, we declare a function with arguments. If you were to just call item(), it wouldn't do anything. But if you initiate a variable as it, such as powbox, the variable you initialize as an item now shares all the same characteristics.

"What's the prototype thing?" That's how I choose to declare member functions. When an object is initiated, it then shares all the same characteristics as someobject.prototype. So, since item.prototype.sell = function() . . ., so does powbox.sell. Member variables are accessed inside the function via this.varname. The way an object works is you have the object itself, then all of its members to the right of it, connected with a period. Notice, this is the exact same behavior as the Math object and even strings. Strings are predefined objects. So, when powbox is initialized with those arguments, all of its member variables are set accordingly.

The next step is all the prototype functions. I'm assuming you understand the use of each one, with possibly the exception of use. buy simply lowers your money by the cost of the item, and sell gives you half of the cost. Heh, and you get no item. What a jerk shopkeep :) Oh well, you have the item anyway. use uses this eval statement. eval will evaluate a string of code as if it were real code. So eval("i=1") is the same as saying i=1. This is useful for storing functions in arrays and such. Another way to do it is just by defining this.effect as a function, like we did the prototypes. Keep in mind that in JavaScript, you can pass and create functions just like variables.

To destroy an object, you simply use delete varname just like any other variable.

Okay, that was a real piss-poor excuse for an explanation, but I hope you get the idea. We have more stuff to get to. In fact, next chapter, you get to go back to making Fooland! :)

Personal tools