Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
27. August 2013

 

YoYoGames have released update 1.2 for their popular GameMaker cross platform 2D game engine, which was used to make such titles as Hotline Miami and gamemakerlogoHome.  Included in this update is one pretty bold claim…  New YoYo compiler runs projects up to 100x fasterI!  That’s a pretty big claim, and I have to say… if you’ve got room for a hundred fold improvement in speed… you had some pretty serious issues before hand!

 

 

Anyways, here is more information from the release:

 

 

  • New YoYo Compiler Runs Projects Up to 100x Faster
  • New Shader Support Allows Creation and Cross-Platform Publishing of Shaders

 

YoYo Games today announces the general availability of GameMaker: Studio version 1.2. With today’s update, developers will be able to harness the full speed of the CPU with the new YoYo Compiler, allowing projects to run up to 100x faster across all native platforms supported. Fully-integrated, totally cross platform Shader support allows developers to write shaders once and then deploy them across all platforms that support them.

 

"Today’s update raises the bar in the visual quality and the complexity of games that can be made in GameMaker: Studio,” said Russell Kay, chief technology officer at YoYo Games. “Our goal with today’s update and all future enhancements to GameMaker: Studio is that the imagination be the limiting factor in the game development process, not the technology.”

The YoYo Compiler

The YoYo Compiler unlocks new possibilities in CPU-intensive areas such as artificial intelligence, procedural techniques, real time lighting, enhanced physics, real time geometry deformation, collision and data manipulation, immensely raising the quality bar. The YoYo Compiler is free for customers of GameMaker: Studio Master Collection and is otherwise available as an add-on priced at $299.

Cross Platform Shader Support

Fully integrated, totally cross platform shader support allows full access to low level shaders, while still letting GameMaker: Studio do the heavy lifting. The built-in editor has been extended to have full color syntax highlighting and “intellisense” for shaders, making creation a breeze.

 

The rapid adoption of GameMaker: Studio as the preferred 2D games development framework has exceeded YoYo Games’ expectations. Today, GameMaker: Studio has been downloaded more than one million times and is quickly approaching 20,000 daily active users. To learn more about the GameMaker: Studio family of products and to get GameMaker: Studio version 1.2, please visit www.yoyogames.com.

 

Certainly an important release for GameMaker developers.

News


4. August 2013

 

I just received the following email:

Dear You,


We recently became aware of suspicious activity relating to some of Crytek’s websites, and acted quickly to take those websites offline for security reasons.
The sites listed below are currently offline:

  • Crytek.com
  • Mycryengine.com
  • Crydev.net
  • MyCrysis.com

 

The following Crytek sites remain online and are not affected by these issues:

  • GFACE.com
  • Crysis.com
  • Warface.com

 

If you have an account at crydev.net or mycrysis.com, you will be asked to change your password next time you log in. If you use your current password anywhere else online, we would also suggest that you reset it at those sites.
We are working on getting all websites fully operational again as soon as possible. Please accept our sincere apologies for any inconvenience.

The Crytek Team

 

If you visit any of those sites, you see:

image

 

Considering that you had to register to evaluate CryEngine, if you’ve looked at it, you are compromised.  You need to authenticate to use CryEngine, so I wonder if all the devs are now dead in the water?  What really annoys me about this announcement is they don’t tell you if the passwords were encrypted.  At this point in time, any website that compromises user information without encrypting it, should be liable for any damages that occur!  This is getting far too common.

News


22. July 2013

 

For a point release, this one’s pretty good.Unity42

 

As mentioned in the title, probably the biggest change is the addition of 3 new platforms, Windows 8 ( as in the app store ), Windows Phone 8 and Blackberry 10.  Windows Phone 8 “Pro” is available free to Unity Pro subscribers.

 

Probably the biggest new feature isn’t new at all.  A number of previously “pro” level features are now available free.  Nav mesh baking ( used for AI pathfinding ), realtime shadows and text based serialization of assets for integration with version control have all become free features.  Those are perhaps the most cited missing features from the “basic” version, so if you are on a budget, that’s great news.

 

Other big features include:

  • OpenGL ES 3.0 support
  • Perforce source control integration
  • iOS crash reporter
  • Anti-aliased RenderTextures.
  • Numerous new image effects ( Blur, Bloom, Edge Detection, etc… )
  • Stencil buffer access (pro only)
  • Shuriken particle system callback scripting interface
  • Added the Quad primitive!

 

Of course, this is just a highlight of the features added, you can check them all out here.  Or of course you can just go ahead and download it, as all Unity basic versions are now free.

News


17. July 2013

 

In this tutorial we are going to look at how to handle Input using Lua scripting ( we will look at C++ later ).  I assume you have read the prior tutorials, so you should have the ability to create a new project and populate it with a new entity using the crate model we made earlier.  You do not need to export it again, you can simply copy the MODEL and texture files over to the root of your newly created project.  So, do that now, create a new project, create a default scene and add the crate model to your scene.  Next add a script component to your newly created crate entity.  If you have any problems with the above instruction, please refer to prior tutorials in this series.

 

In this tutorial we cover:

  • Polling for keyboard input
  • Polling for mouse input
  • Creating input maps to handle input in an abstract manner

 

By the way, this tutorial starts by demonstrating a way you shouldn’t use!  Be sure to read the entire post before you do anything.

 

 

Handling Keyboard Input

 

The following script shows how to handle basic keyboard input using Lua.  I attached the script to our entity and implement it it’s OnThink callback.

 

function OnThink(self)
  if Input:IsKeyPressed(Vision.KEY_UP) then
    self:IncPosition(0,1,0)
  elseif Input:IsKeyPressed(Vision.KEY_DOWN) then
    self:IncPosition(0,-1,0)
  elseif Input:IsKeyPressed(Vision.KEY_LEFT) then
    self:IncPosition(-1,0,0)
  elseif Input:IsKeyPressed(Vision.KEY_RIGHT) then
    self:IncPosition(1,0,0)  
  end 
end

The key is the Input object, which is an instance of VScriptInput_wrapper, which as the name suggests, wraps input functionality and makes it available in Lua.  Another thing of note is the Vision object ( well… table if I am going to use the proper terminology ) contains a number of constant defines, in this case we access the values for various key codes, such as Vision.KEY_LEFT.  In the event of an arrow key being pressed, we move our entity calling the IncPosition() function, moving along either the X or Y axis, depending on which key is pressed.

 

The key thing to realize about the IsKeyPressed function is it will report true every time a key is hit.  Therefore with the above code, if you hold down the key it will fire every time OnThink() is called.  What do you do if you want to only respond when the key is pressed the first time?  In that case you use SetKeyOnHit, like so:

 

 

function OnCreate(self)
	Input:SetKeyAsSingleHit(Vision.KEY_UP,true)
end

function OnThink(self)
  if Input:IsKeyPressed(Vision.KEY_UP) then
    self:IncPosition(0,100,0)
  end
end

 

Using the above code, with the added call SetKeyAsSingleHit changes it so IsKeyPressed for KEY_UP will only return true when the UP arrow is initially pressed, and wont return true again until the key is released and pressed again.  You can toggle this behaviour off by calling SetKeyAsSingleHit again but passing false instead.

 

 

One very important point!

 

When testing input code, it is very important that you run your game in “Play the Game” mode, otherwise vForge will still capture and handle all the input events.  You run in Play The Game mode by clicking the down arrow next to the play icon and selecting Play The Game:

image

 

When you are done testing your game, hit the ESC key.

 

Handling Mouse Input

 

Now let’s quickly look at how you handle mouse events.  I created a new scene in the same project, added the create model and once again attached a Lua script component to it.  The Vision engine has the ability to poll the mouse for activity, which is exactly what we are about to demonstrate.

 

-- new script file

function OnThink(self)
	local mouseX,mouseY = Input:GetMousePosition()
  local mouseDeltaX,mouseDeltaY = Input:GetMouseDelta()
  local mouseWheelDelta = Input:GetMouseWheelDelta()
  local isLeftButtonDown = Input:IsMouseButtonPressed(Vision.BUTTON_LEFT)
  local isRightButtonDown = Input:IsMouseButtonPressed(Vision.BUTTON_RIGHT)
  
  
  local outString = "Mouse Position:" .. mouseX .. "," .. mouseY .. 
                  " Mouse Delta:" .. mouseDeltaX .. "," .. mouseDeltaY .. " Mouse Wheel Delta:" .. mouseWheelDelta

  if isLeftButtonDown then 
    outString = outString .. " Left Button Down"
  end

  if isRightButtonDown then 
    outString = outString .. " Right Button Down"
  end
  
  Debug:PrintLine(outString)
end

 

The code is quite straight forward.  Each frame in OnThink() we poll the location of the mouse using GetMousePosition(), the amount the mouse has moved since the prior frame using GetMouseDelta(), the amount the mouse wheel has moved using GetMouseWheelDelta() and finally check to see if either mouse button is pressed using IsMouseButtonPressed().  Once again, the mouse button constants are defined in Vision.

 

If you run this code you will see:

 

image

 

Once again, like the keyboard demonstration, you need to run in Play The Game mode for Engine View to receive the input.

 

Creating Input Maps

 

Now that we’ve covered how to directly poll the mouse and keyboard for input, we will now look at handling input using a InputMap instead.  Using an input map allows you to put a layer of abstraction between you and the input devices, allowing you to map multiple control schemes to a single action.  Let’s jump right in and take a look.  I am once again creating a new scene, adding the crate model and applying a script to it.

 

-- Inputmap demo

function OnAfterSceneLoaded(self)
  self.map = Input:CreateMap("crateInputMap")
  self.map:MapTrigger("Up", "KEYBOARD", "CT_KB_SPACE")
  self.map:MapTrigger("Up", "MOUSE", "CT_MOUSE_RIGHT_BUTTON")
  self.map:MapTrigger("Up", {0,0,100,100}, "CT_TOUCH_ANY", {once=true})

  -- arrow keys mapping for left/right
  self.map:MapTriggerAxis("MoveX", "KEYBOARD", "CT_KB_LEFT", "CT_KB_RIGHT")
  -- WASD mapping for left/right
  self.map:MapTriggerAxis("MoveX", "KEYBOARD", "CT_KB_A", "CT_KB_D")
  -- gamepad mapping for left/right
  self.map:MapTriggerAxis("MoveX", "PAD1", "CT_PAD_RIGHT_THUMB_STICK_LEFT", "CT_PAD_RIGHT_THUMB_STICK_RIGHT")
  
  end




function OnThink(self)
	if self.map:GetTrigger("Up") == 1 then
    self:IncPosition(0,0,10)
  end

  if self.map:GetTrigger("MoveX") < 0 then
    self:IncPosition(10,0,0)  
  elseif self.map:GetTrigger("MoveX") > 0 then
    self:IncPosition(-10,0,0)  
  end
end

 

This time we are creating a map to handle input using the function Input:CreateMap().  If you create another map using the same name, the previous map will be destroyed.  Once we have a map, it’s a matter of defining triggers.  Essentially this means we are giving a string key and mapping it to an input event.  For example MapTrigger(“Up”,”KEYBOARD”,”CT_KB_SPACE”) is saying when the spacebar is pressed on the keyboard, trigger the trigger named “Up”.  As you can see, you can map multiple devices/keys to the same trigger.  In this example, we mapped the SpaceBar, Right Mouse Button and touching the screen in between the coordinates (0,0) and (100,100) all to the trigger “Up”.  So now instead of handling all the different control schemes in code, we can simple deal with “Up”.  If you look at the  CT_TOUCH_ANY trigger ( which we will cover in more detail later ), you can pass in a table of optional parameters in as well, in this case we are saying we want the event to only fire once per touch.

 

Sometimes however you want to bind an axis to an event, such as pressing left or right arrow keys, or using the thumbstick on a gamepad.  In that case you can use MapTriggerAxis().  In this case you pass in the name of the trigger, the device to use, then the values representing the negative and positive ranges of the axis.  In the first example, we are mapping the LEFT and RIGHT arrow keys to the X axis, with CT_KB_LEFT representing the negative value and CT_KB_RIGHT representing the positive value.  We also bound the A and D keys from a traditional WASD layout to the X axis, as well as the right thumbstick on a gamepad, if present.  The code will warn you that a given device isn’t present, but will run anyway.

 

Now in on think you can see handling triggers is extremely simple, you simply call your map’s GetTrigger method, passing in the name of the trigger you created.  Therefore if any of the triggers we defined are true ( RMB pressed, Spacebar hit or certain region of the screen is touched ), it will return 1 get you check the “Up” trigger.  Dealing with axis is virtually identical, except it returns a value from –1 to 1, depending on direction pressed.  Using a map allows you to easily handle multiple control schemes using a single code base.

 

In this tutorial, we looked mostly at traditional desktop controls… not really much use in mobile development.  In the next part however, we are going to look at work with mobile input.

Programming


10. July 2013

I'll be the first to admit the expression "cloud computing" is overly abused these days. The reality is, while a bit abused by marketing types, cloud computing is a huge deal for developers.  Gamers simply expect certain functionality in your game that eventually is going to require you to have a server side component.  You may think to yourself…  well, rolling my own server isn't all that difficult.  If you have the skill set to do so, creating say… a server side score board is not all that difficult.  Frankly, it isn't either, in fact I covered exactly that topic in a prior tutorial series.  Easy, right?  Ok… now where are you going to host it and what is that going to cost you?  How secure is it?  Is it encrypted?  How well does it scale?  What about back-ups and fault tolerance?  Who is going to administrate your servers?  What about reporting?  Suddenly this simple little task quickly becomes a much more costly and complicated process and takes time and money away from doing what you set out to do… actually developing a game.

 

At the end of the day, for many developers letting someone else take care of all of these things generally makes a lot of sense.  This is the exact problem that Scoreoid sets out to solve.  You can essentially think of them as a your game's server in the cloud.  Using a fairly simple REST based api you can easily accomplish pretty much anything you could want from a dedicated server and they take care of the infrastructure and day to day operation for you.  In this post we are going to take a closer look at how Scoreoid works and what it does for you.

 

From a developers perspective, Scoreoid can be thought of as a product in two parts.  First you have the developer portal/dashboard where you can monitor, access and maintain your data.  Then you have the REST based API that the programmer uses to work with Scoreoid.

 

WARNING TIME!

To illustrate the various abilities I put together a web application that demonstrates much of Scoreoid's functionality.  This application is hitting live data and you the viewers have the ability to update and create new data.  This means I have NO IDEA what you might encounter when using the application and take no responsibility for anything written.   Please guys, be mature about it.  If you see something hateful or excessively stupid, let me know and I will remove it.

 

The Scoreoid Dashboard

First let's take a quick look at the Scoreoid web interface.  If you haven't already, you need to sign up for a Scoreoid account.  Don't worry, it's completely free and they don't spam you with emails.  Once you are signed up, log in and you will arrive at the main Dashboard page:

 

Dashboard

 

Here you get a top level overview of activity for your game.  In this case you can see that Henry is a very prolific and talented player of Test Game!

Across the top are a series of tabs.  These provide you a way to drill down into data for each category, for example, below is the result of clicking the Player tab.

DashPlayers

 

Here you can modify or delete any value in the Players database.  Scores, Games, Stats and Notifications work similarly, allowing you to access and modify data using a graphic interface.  The one I didn't mention was Console, and this is a handy little tool.  Console allows you to make Scoreoid API calls using a form.

 

ScoreoidConsole

 

Using the Console you pick the API call to make, and the form below is populated with the available parameter fields.  Once you execute it, you see the results below in the results panel, in either XML or JSON format.  You can make use of the entire Scoreoid API using the console.

 

Finally, let's take a look at adding a game.  Click on the Game tab and click the Add New Game button.  You need at least one game to use Scoreoid, but you can of course make many if you wish.  You pass the Game ID as a parameter to a number of the API calls.  Creating a game is simple enough:

CreatingAGame

 

Finally the Help link brings you to the documentation.  You can access the documentation without the need to log in if you want to take a look at the API.  The documentation is complete and has examples in multiple languages for each API call.  Now, let's get down to some coding.

 

 

Programming with Scoreoid

 

Scoreoid is accessed using a REST based interface.  The nice part about a REST based api is, if your application can programmatically access the web, it can use the API.  The actual programming language you use doesn't matter.  In this example, I am going to mostly use JavaScript.  In my case I like working with the YUI library, but you can easily use whatever library you want, the methodology stays very similar although the syntax changes slightly.

 

There are a couple things to note up front.  In the name of keeping the code easy to understand, I've performed a couple programming no-no's in this example.  First I gave you all access to my Scoreoid token…  in your application you obviously would not want to do this.  If you create a JavaScript based Scoreoid application, be sure to read about using an auto generated proxy for securing your application.  Next, I used the HTTP calls instead of the HTTPS ones.  In a secured application, you would want to obviously use the encrypted option.  Finally I made only synchronous networking calls… this means my networking calls cause programming execution to stop until results are returned.  In a real application you would generally want to make asynchronous calls.  As a result of these decisions, the code should however be fairly easy to understand.

 

Let's jump right in to the sample app.  We will be looking at portions of the code as we go.  However a great deal of the code has nothing to do with Scoreoid in particular ( YUI3 or markup related code ), while a lot of it is very repetitious in nature.  Therefore instead of listing it all here, I created a github for it. You can also download a zip of the project here

 

The application requires a server to be run due to the AJAX calls.  Therefore I have included a simple Node based server.  If you have Node installed, you can run the application by typing:

node server.js

Then you can access it in your browser at http://localhost:3000. The vast majority of interesting code for this application is in the views folder, while the templates folder contains the markup. Again, keep in mind this application is working with live data, so play around, but please be mature about it:

 

( Below is the application, not a screen shot :) )

 

 

There is a tab for each area of functionality we want to look at, Game, Player, Score and Cloud.  Under each is a form for interacting with Scoreoid.  At the bottom of each form is a field showing the raw XML or JSON results returned by the server.

 

Before we continue too far, let's take a quick look inside Index.html at the following lines.

        //Global Y variables
        Y["SCOREOID_KEY"] = "bde61648959d0c364b04b93e257035abd5ee3b26";
        Y["GAME_ID"] = "3e99cf43ab"
 

These are two values we will be needing over and over again.  First is my Scoreoid token… you should KEEP YOURS PRIVATE!  The second is the ID of a game I created earlier using the dashboard.  Once again, Scoreoid can support multiple games at once, but in this case I am using only one.  So in the code when you see Y.SCOREOID_KEY and Y.GAME_ID, this is where those values are set.

 

Now let's take a look at the Game tab in the application:

Game

First we will look at the code that executes when the user clicks the Get Game Information button in game.View.js.

        getGameData:function(){
            // This is a blocking web request... in real world, BAD!
            var requestCfg = {
                sync:true,
                data : {
                    api_key: Y.SCOREOID_KEY,
                    game_id: Y.GAME_ID,
                    response:"JSON"
                }
            };
            var request = Y.io("http://api.scoreoid.com/v1/getGame", requestCfg);
 
            Y.Global.fire('displayResults', {msg:request.responseText});
        }
 

Y.io() is what you use to make a HTTP request in YUI3.  The data object within the requestCfg object is where you pass the parameters to Scoreoid.  We pass in our api_key, game_id ( both defined earlier in index.html) as well as response.  The response variable tells Scoreoid what format you want the results returned in, either JSON or XML.  For the vast majority of examples, we are going to go with JSON as it's a bit easier to read and lighter weight.  Finally you call the function in the form of the URL you pass to Y.io, in this case http://api.scoreoid.com/v1/getGame which calls the getGame() method.  There is a wiki page for every API call ( here is getGame for example ), that lists the possible parameter fields as well as the values that will be returned.

 

Click the button and in the results area you should see:

[{"Game":{"user_id":"51b8b1dcfd8978203e000b9d","name":"Test Game","short_description":"This game is so amazingly awesome, it doesn't exist!","description":"Really, it doesn't exist.  The game is a lie.","players_count":6,"scores_count":7,"status":1,"created":"2013-06-12 19:39:07","updated":"2013-06-12 19:39:07"}}]

 

This is the return value of getGame() in JSON format.  JSON is a handy format, as it is basically just a JavaScript object encoded in string from.  You can turn a JavaScript object into JSON by calling JSON.stringify(myObject) and you can turn a JSON string back into a JavaScript object by calling JSON.parse(myString).  Pretty much every programming language under the sun has a JSON parsing library.  For those that don't you can always get Scoreoid to return XML ( we look at an XML example later ).

 

If YUI calling convention is alien to you, and you are more comfortable using jQuery, you can make the above call using the following jQuery code:

$.post("http://api.scoreoid.com/v1/getGame", { api_key:Y.SCOREOID_KEY,game_id:Y.GAME_ID,response:"JSON"},

   function(response) {

     //response will now contain the JSON data returned by Scoreoid

     //note, this is an async call

   });

 

As you can see, it's pretty simple to make REST based calls.  The other two examples in the Game tab are Get Players and Get Highest Gold Amount.  Below is the code for GetPlayers:

        getGamePlayers:function(){
            // This is a blocking web request... in real world, BAD!
            var requestCfg = {
                sync:true,
                data : {
                    api_key: Y.SCOREOID_KEY,
                    game_id: Y.GAME_ID,
                    response:"JSON"
                }
            };
            var request = Y.io("http://api.scoreoid.com/v1/getPlayers", requestCfg);
 
            Y.Global.fire('displayResults', {msg:request.responseText});
        }
 

As you can see the code is basically identical, the only difference is you call a different URL.  getPlayers() returns a list of all of the players of your game, unless of course you tell it to limit the results returned.  Get Highest Gold Amount is also virtually identical:

        getGameTop:function(gameField){
            var requestCfg = {
                sync:true,
                data : {
                    api_key: Y.SCOREOID_KEY,
                    game_id: Y.GAME_ID,
                    response:"JSON",
                    field:gameField
                }
            };
            var request = Y.io("http://api.scoreoid.com/v1/getGameTop", requestCfg);
 
            Y.Global.fire('displayResults', {msg:request.responseText});
 
        }
 

Once again, we call a different URL. In this case we are also passing in an additional parameter field.  Field tells the method which value we want to get the highest value of when calling getGameTop.  As you can see when we called getGameTop(), the value that was passed in was gold.

            container.one("#buttonGetWealthiest").on("click",function(){
                this.getGameTop("gold");
            },this);
 
There are a number of valid options for field ( bonus, best_score, gold, money, kills, lives, time_played, unlocked_levels ).  Once again, you can get a list of valid options in the documentation for getGameTop.  If you press the Get Highest Gold Amount button, you should see:
 
GetHighestGold
 
Of course, since you guys have full access to all the data in the application, the actual value returned might change.
 
Now let's take a look at working with Player data:
 
 
Player
 
The code behind this form is player.View.js.
 
Creating a player is once again a very straight forward process.  First the code that is called when the user clicks the Create Player button:
 
            this.get('container').one("#buttonCreatePlayer").on("click",function(){
                this.createPlayer(Y.one('#playerName').get('value'));
            },this);
 
 

This simply gets the value of the playerName text field ( see player.Template in the templates folder for HTML markup ) and passes it to the function createPlayer().  Now let's look at createPlayer:

 

        createPlayer:function(playerName){
            var requestCfg = {
                sync:true,
                data : {
                    api_key: Y.SCOREOID_KEY,
                    game_id: Y.GAME_ID,
                    username: playerName,
                    response:"JSON"
                }
            };
            var request = Y.io("http://api.scoreoid.com/v1/createPlayer", requestCfg);
            Y.Global.fire('displayResults', {msg:request.responseText});
        }
 

Once again, the actual code remains almost identical.  The URL we are calling is now http://api.scoreoid.com/v1/createPlayer and we pass the new player's name in the field username.

 

Next we will look at working with XML data instead.  If you click the Get All Players button, the following grid will appear:

GetPlayers

 

The YUI grid binds to an XML results set, so this time we are going to call /getPlayers, but instead we want it to return XML results instead of JSON.  This code is going to look a bit more daunting then it really is.  This is what executes when the user presses Get Players:

this.get('container').one("#playerGetAll").on("click",function(){
 
                var requestCfg = {
                    method:"POST",
                    data : {
                        api_key: Y.SCOREOID_KEY,
                        game_id: Y.GAME_ID,
                        response:"XML"
                    }
                };
 
                var ds = new Y.DataSource.IO({source:"http://api.scoreoid.com/v1/getPlayers"});
                ds.plug(Y.Plugin.DataSourceXMLSchema, {
                        schema: {
                            resultListLocator: "player",
                            resultFields: [
                                { key:"Username", locator:"@username" },
                                { key:"Email", locator:"@email" },
                                { key:"TimePlayed", locator:"@time_played" },
                                { key:"Gold", locator:"@gold" },
                                { key:"BestScore", locator:"@best_score" }
                            ]
                        }
                    });
                ds.sendRequest({
                    callback:{
                        success: function(e)
                            {
                                var dt = new Y.DataTable(
                                    {
                                    columns:[{key:"Username"},{key:"Email"},{key:"TimePlayed"},{key:"Gold"},{key:"BestScore"}],
                                    data: e.response.results,
                                    summary:"List of all players in the game",
                                    caption:"Players"
                                    });
                                // Clear the table, in case one already exists
                                Y.one("#dataTable").setContent("");
                                // Now populate
                                dt.render(Y.one("#dataTable"));
 
                                Y.Global.fire('displayResults', {msg:e.data.response});
                            },
                        failure: function(e){
                            Y.log(e);
                        }
                    },
                    cfg:requestCfg
                });
 
            },this);
 

Once again we are making a call to the getPlayers url. Notice however that we set Response to XML.  This time instead of getting data using Y.io(), we instead want to populate an XML dataset using Y.DataSource.IO().  The actual call is made when we call sendRequest and we pass in the requestCfg here.  The remaining code is about selecting which fields from the XML we want to have displayed in the grid.

 

Speaking of XML, here is the results of getPlayers() in XML form:

<?xml version="1.0" encoding="UTF-8"?>
<players>
<player username="Henry" unique_id="" first_name="" last_name="" email="[email protected]" bonus="0" achievements="" gold="9000" money="0" kills="0" lives="0" time_played="300" unlocked_levels="" unlocked_items="" inventory="" last_level="" current_level="" current_time="0" current_bonus="0" current_kills="0" current_achievements="" current_gold="0" current_unlocked_levels="0" current_unlocked_items="" current_lives="0" xp="" energy="" boost="" latitude="" longtitude="" game_state="" platform="" rank="0" best_score="90003" created="2013-06-21 16:39:10" updated="2013-06-24 16:33:05">
</player>
<player username="Mike" unique_id="" first_name="" last_name="" email="" bonus="0" achievements="" gold="4512" money="0" kills="0" lives="0" time_played="42" unlocked_levels="" unlocked_items="" inventory="" last_level="" current_level="" current_time="0" current_bonus="0" current_kills="0" current_achievements="" current_gold="0" current_unlocked_levels="0" current_unlocked_items="" current_lives="0" xp="" energy="" boost="" latitude="" longtitude="" game_state="" platform="" rank="0" best_score="0" created="2013-06-21 16:27:33" updated="2013-06-25 15:56:07">
</player>
------------------------------ RESULTS SNIPPED ------------------------------------
</players>

 

As you can see, there is a great deal more information available than what we are choosing to display.  Switching between JSON and XML results is a trivial task.

 

The final part of the Player page illustrates how to retrieve and update a single field of an individual player.  The code is pretty much identical to what we have seen thus far.  See the getPlayerField() and setPlayerField() functions for more details of how this code works.  The fields in the um… Field drop down is set in the players.Template code.  It is simply a combo box filled with the available values.  Once again, valid values can be obtained  from the documentation. 

 

One of the most common tasks that game programmers require a server for is online leader boards.  Making an online scoreboard with Scoreoid is a pretty simple affair, as we will see looking at the Scores tab:

 

Score

 

The code controlling this form is available at score.View.js.  Using this form you can get high scores, get scores sorted high to low and low to high, get the average over all score and create a new high score.  At this point in time, the code should be intimately familiar, as the logic is identical, just the URLs and parameters change.  The first three buttons call the method /getScores.  The only difference is for the sorted results we pass the parameter order_by with the value either "asc" for ascending or "desc" for descending results.  Get Average Score calls the method /getAverageScore ( predictably enough… ).  The /getScores method has a number of parameters we didn't use here for fine tuning your results.  You can fine tune the results by specifying difficulty level, date range, platform as well as limit your results to N number of values returned.  In the end, implementing a complete scoreboard is pretty simple.

 

Finally, let's take a look at the Cloud tab.

 

Cloud

 

Sometimes you just need to store "stuff" ( technical term there! ) in the cloud.  This is a key/value database stored at the game level ( more globally ) instead of the player or score level.  Most of the code here makes use of the /getGameData() and /setGameData() methods.  You can access the code behind this form in cloud.View.js.

 

If for example you click the Set Cloud Data, the value you pass is going to be written to the hard coded key "myData".  Perhaps the most interesting aspect of Scoreoid cloud storage is it supports JavaScript "dot" notation.  So for example, you can set data for monster, such as monster:orc, but also like monster.hp = 42.  Here for example are the current results in JSON format if you hit Get Monster from the cloud:

 

{"monster":{"alignment":"Lawful Evil","maxHitPoints":"42"}}

 

This makes storing structured hierarchical data easy.

 

So, that's the basics of using Scoreoid.  The API is remarkably consistent, so once you've made a single call you pretty much know how to use the entire API.  The rest is a matter of looking at the documentation for what parameters and results you can expect.  The rest is just a matter of parsing the results that are returned.

 

As I mentioned earlier, a REST based API is usable by any programming language capable of making programmatic web requests.  So far, I've entirely focused on JavaScript, but now I will give an example using a different programming language.  In this case, C# for the PlayStation Mobile platform.  The following example shows how you would access a scoreboard in a PS Vita application.  Since the PSM SDK doesn't included a JSON parser, but does include an XML one, I've gone with XML for the return value.

 

 

 

using System;
using System.Collections.Generic;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Graphics;
using Sce.PlayStation.Core.Input;
using Sce.PlayStation.HighLevel.UI;
using System.Net;
using System.Linq;
using System.Xml.Linq;
using System.IO;

namespace Scoreoid
{
	public class AppMain
	{
		private static GraphicsContext graphics;
		private const string SCOREOID_KEY = "bde61648959d0c364b04b93e257035abd5ee3b26";
		private const string GAME_ID = "3e99cf43ab";
		
		public class ScoreEntry
		{
			public string Name;
			public string Score;
		}
		public static void Main (string[] args)
		{
			graphics = new GraphicsContext();
			UISystem.Initialize(graphics);
			
			var scene = new Sce.PlayStation.HighLevel.UI.Scene();
			var panel = new Panel() {
				Width = graphics.Screen.Width,
				Height = graphics.Screen.Height };
			
			
			var textOut = new Label();
			textOut.Width = panel.Width;
			textOut.Height = panel.Height;
			textOut.HorizontalAlignment = HorizontalAlignment.Center;
			textOut.Text = "High Scores Go Here";
			panel.AddChildFirst(textOut);
			scene.RootWidget.AddChildFirst(panel);
			
			var request = HttpWebRequest.Create (@"http://api.scoreoid.com/v1/getScores?response=XML&api_key=" +
			                                     SCOREOID_KEY +
			                                     "&game_id=" +
			                                     GAME_ID);
			request.ContentType = "application/xml";
			request.Method = "GET";
			
			using (HttpWebResponse response = request.GetResponse() as HttpWebResponse) {
				if (response.StatusCode != HttpStatusCode.OK)
					Console.Out.WriteLine("Error fetching data. Server returned status code: {0}", response.StatusCode);
				else {
					using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
						var content = reader.ReadToEnd();
						if (string.IsNullOrWhiteSpace(content)) {
						System.Diagnostics.Debug.WriteLine("Scoreoid returned no results");
						}
						else {
							XDocument doc = XDocument.Parse(content);
							var scores = (from e in doc.Root.Elements("player").Elements("score")
							select new ScoreEntry {
								Name= (string)e.Parent.Attribute("username"),
								Score= (string)e.Attribute("score")
							}).ToList();
							
							string text = "";
							foreach (var score in scores) {
								text += score.Name + " " + score.Score + "\n";
							}
							
							textOut.Text = text;
						}
					}
				}
			}
			
			UISystem.SetScene(scene);
			
			while(true){
				graphics.Clear ();
				UISystem.Update(Touch.GetData(0));
				UISystem.Render ();
				graphics.SwapBuffers();
			}
		}
	}
}

 

If you run this code, you will see:

ScreenShot

 

If you look closely at the code, the actual Scoreoid calls take only a few lines of code.  You create a HttpWebRequest passing the URL as well as the parameters in the URL ( this time we are doing a GET request instead of a POST request ).  Then its simply a matter of getting the results using GetResponse().  The remaining code is about parsing the XML results and PSM specific display code.

 

 Other Info

 

There are a few downsides to outsourcing your game server that you need to be aware of up front.  What happens if something happens to your provider or you want to switch providers?  Here is Scoreoid's policy on data from their website:

With Scoreoid your data belongs to you, we respect that you retain ownership of your data. Scoreoid isn’t another game network taking away your most valuable asset your players and game data. Our bulk storage engine is MongoDB, our preferred method of returning your data to you is via zipped ‘mongodump’.

MongoDB is a freely available open source NoSQL database with binaries available on Windows, Mac, Linux and Solaris. 

The next most obvious question… what does it cost?

This one is a bit trickier to answer, as as of right now, the pricing hasn't been set.  The good new is, right now it's completely free!  There are a number of live games currently using Scoreoid.  That then leaves the question, what will it cost?  For that, we go to the FAQ:

How much will the pro accounts cost?

We're currently focusing on adding new features and we're still working on the pro account options of course there will always be a freemium option.

Scoreoid's mission statement is to provide a free version to every developer which includes updates and new features. We believe every game developer should have an option to use Scoreoid helping them save time and cost while allowing them to improve there game titles and brand.

As for pricing we will offer a number of plans that will fit every developers budget. Currently looking at having 3 main plans between $15 to $50 per month and then a 4th enterprise plan for big publishers and big game studios.

We're also looking at the possibility of have a $5/$8 month option for developers who use very little data or bandwidth.

Our goal is be very cost effective and help game developers, most users will be fine with the free or lower end plan. Transparence is very important to us especially with our pricing model we will notify all users in advanced before we active the pro options.

We also plan on doing active surveys before we activate the pro plans as we would like to get as much feedback as possible from our users giving you a chance for direct input and influence.

 

I have been using Scoreoid since it launched what will happen when pro accounts are activated?

All current users who are using Scoreoid for active games (who have at least one live game that is using Scoreoid) and decide to upgrade to a pro account will receive major discounts and additional benefits. We will also include you in our "loyalty program".

We will keep your current plan and limits for set time limit grandfathering you into a new plan sets. Don't forgot Scoreoid will always offer a freemium option.

 

So basically, the prices aren't set yet, they will be tiered from free on up and if you publish now you will get a discount once pricing goes live. Perhaps most important of all for smaller publishers, there will always be a free tier.

 

So if you are looking at adding server side functionality to your game and don't want to roll your own solution, consider checking out Scoreoid.

Programming


AppGameKit Studio

See More Tutorials on DevGa.me!

Month List