Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

21. July 2012

Now that we have a cocos2D app being served from NodeJS and being hosted in the cloud we now need to get down to the application itself.

 

One of the biggest parts of this app is actually the plumbing behind the scenes.  Essentially I need to be able to upload images to a server and retrieve them on demand.  For each image I need to be able to add a description.  So that is what we are going to create here.

 

If you were ever wondering how to create a full web application using just JavaScript on the client and server, the end result of this exercise is going to show you exactly that.

 

There are a few warnings before hand!

 

1- Heroku doesn’t persist files.  So anything you upload to this example application, it will eventually be lost.  In my actual application I am going to be hosting the actual images to my Dropbox account or using a private Redis database, but in either case, it’s not information I want to share publically.  If you have questions about how I do either, I will gladly answer them.

 

2- THIS ONE IS IMPORTANT!!! I have shared full access to this application to everyone.  That means anyone at any time can upload any picture they want!  So, be aware before you click any links, who knows what you might see!  Also, anyone can delete all the existing images too, so again, don’t expect your uploads to survive long.  It is live for demonstration purposes only, if you want to run something similar, fork it and host your own privately.  Use at your own risk!  GameFromScratch.com takes no responsibility for any content that might be updated.

 

Finally, please be civilized about it.

 

Alright, the warnings and disclaimers out of the way, let’s continue.

 

We are going to take our existing cocos2D audio sample application and add a settings button to the top right corner, like so:

image

 

In order to do so, we are going to make the following changes to Index.html, the file that is served if people request the root of our application:

index.html

<html>
<body style="padding:0; margin: 0; background: #fff;">
<div stype="width:100%;height:50px">
    <form>
        <div align=right>
            <input align=right type=button value=settings id=settings
                  onclick="document.location.href='/settings';"  />
        </div>
    </form>
</div>
<div style="text-align: center; font-size: 0">
    <canvas id="gameCanvas" width="600" height="600">
        Your browser does not support the canvas tag
    </canvas>
</div>
</body>
</html>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js">
</script>
<script src="classes/cocos2d.js"></script>

 

Really, the only major changes here is the addition of a form, with a button inside with a crude JavaScript redirect to /settings.

 

In our node server application, we now need to handle this new route:

Add the following to server.js

server.get('/settings',function(req,res){
   res.sendfile('settings.html');
   console.log('Send settings.html');
});

This will now cause any requests to /settings to return settings.html.  This document is the webpage where most of the new functionality occurs.  It allows you to select multiple images ( at once using CTRL or SHIFT click ), apply a description to each, and upload it to the server.  It also allows you to review the existing images, as well as clear them all.

 

Let’s take a look at the code. 

settings.html

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>First This Settings</title>
    <script src="http://yui.yahooapis.com/3.5.1/build/yui/yui-min.js"></script>
    <script>
        YUI().use('uploader', function(Y){
            var uploader =
                new Y.Uploader(
                        {type:"HTML5",
                        uploadURL:"/upload/",
                        multipleFiles:true
                        }
                );

            uploader.render("#selectFiles");

            uploader.after("fileselect", function(event){
                var files = event.fileList;
                var table = Y.one("#filenames tbody");

                if(files.length > 0)
                {
                    Y.one("#buttonUpload").set("disabled",false);
                }

                Y.each(files,function(file){
                    table.append("<tr>" +
                            "<td>" + file.get("name") + "</td>" +
                            "<td>" + file.get("size") + "</td>" +
                            "<td><input type=text id=" + file.get("name") + "></td></tr>");
                });
            });

            uploader.on("alluploadscomplete", function(event) {
                // Hackish page reload
                alert("Files added successfully");
                document.location.href="/settings";
            });

            Y.one("#buttonUpload").on("click", function(){
                if(uploader.get("fileList").length > 0){
                    var perFileVars = {};
                    Y.each(uploader.get("fileList"),function(curFile){
                        perFileVars[curFile.get("id")] =
                        {description:Y.DOM.byId(curFile.get("name")).value};
                    });
                    uploader.set("postVarsPerFile",
                        Y.merge(uploader.get("postVarsPerFile"),perFileVars));


                    uploader.uploadAll();
                }
            });


        });

        YUI().use('io-base','node',function(Y){
            Y.io('/getPhotos',{
                on: {
                    complete:function(id,response){
                        var files = JSON.parse(response.responseText);
                        Y.log(files);
                        var table = Y.one("#existingFiles tbody");
                        for(var key in files)
                        {

                            table.append("<tr>" +
                                    "<td><a href=/image/" + files[key].name + ">"
                                    + files[key].name + "</a></td>" +
                                    "<td>" + files[key].size + "</td>" +
                                    "<td>" + files[key].description + "</td></tr>");
                        }
                    }
                }
            });

            Y.one("#buttonClear").on("click", function(){
                Y.io('/clearAll',{
                    on:{
                        complete:function(id,response){
                            document.location.href="/settings";
                        }
                    }
                });
            });

        });
    </script>
</head>
<body>
<form>
<div style="border:50px">
    <div id=selectFiles>
    </div>
    <div>
        <table id="filenames">
            <thead><tr>
                <th width=350px align=left>File Name</th>
                <th align=left>File Size</th>
                <th align=left>Description</th>
            </tr></thead>
            <tbody></tbody>
        </table>
    </div>
    <div align=right>
        <br /><br />
        <hr />
        <button disabled="true" type="button" id="buttonUpload"class="yui3-button"
                style="width:250px;height:40px;align:right;">Upload Files</button>
    </div>
    <div>
        <br /><hr />
        <table id="existingFiles">
            <thead><tr>
                <th width=150px align=left>File Name</th>
                <th align=left width=60px>File Size</th>
                <th align=left>Description</th></tr></thead>
            <tbody></tbody>
        </table>
    </div>
    <div align=right>
        <br /><br />
        <hr />
        <button type="button" id="buttonHome"class="yui3-button"
                onclick="document.location.href='/'"
                style="width:250px;height:40px;align:right;">Done</button>
        <button type="button" id="buttonClear"class="yui3-button"
                style="width:250px;height:40px;align:right;">Clear All Files</button>
    </div>
</div>

</form>
</body>
</html>

 

Please ignore the wonky formatting, it was done to fit it to this blog width.

As you can see right off the hop, this code makes use of the YUI libraries, a handy set of utilities to perform many common tasks.  In this case I am using them for the Uploader control, as well as for making networked requests back to the server with Y.io.  The YUI libraries are beyond the scope of this document, but fortunately their documentation is extremely good. If you would prefer to use jQuery instead, feel free.

 

In a nutshell, here is what we are doing ( from the top ):

  • create a YUI closure Y, with the uploader module functionality supported
  • create a new uploader, HTML5 style (instead of Flash), set its upload path ( the url it will submit to ) to /upload and finally tell it to support multiple files at once.  This is a big part of why I chose it in the first place, as otherwise with the standard HTML controls, you need to upload files one by one.
  • we then set the uploader to render to the selectFiles div we will define shortly. This simply tells the control where to draw itself.
  • We then wire up an event handler for after the user has selected files. If the user has selected at least one file, we enable the upload button, we then loop through the selected files and dynamically populate the table named filenames.  Perhaps most importantly, for each table row, we create a text field for entering the description, with the filename as it’s id.
  • Next we wire up an event handler for the “alluploadscomplete” event, which is fired predictably enough, when all uploads are complete. In this case we just display a message and redirect to the settings page.
  • We then wire up a click handler for the upload button.  This loops through all of the files select, and grabs the description value we specified in the text field and merges in to the data that is going to be posted back to the server.  Essentially this means the data you enter is each description field is going to be posted along with your files back to the server.  Finally we actually perform the upload by calling uploadAll().
  • Next I create a different YUI closure with different dependencies ( io-base and node ).  I do this simply as personal preference, as I find it makes code easier to move around.  If you preferred, you could have made a single call to YUI().use.
  • This code is basically going to be executed on page load or there abouts ( we don’t really care when ), which makes a network request to /getPhotos, which is a web service that returns a JSON structure of all the photos on the server.  We then loop through the results and display them to another table, existingFiles.
  • next we wire-up another button handler, this one is if the user clicks the Clear All button, which calls the clear all web service, which predictably enough, clears all the photos. Finally it reloads the page, so the tables will be redrawn.
  • Everything else is just standard HTML.

 

There is actually quite a bit of functionality packed in to a fairly small amount of code.  As we saw, we added a number of new functions to the server, lets take a look at them. 

 

server.js

var express = require('express'),
    server = express.createServer(),
    files = {};

server.use('/cocos2d', express.static(__dirname + '/cocos2d') );
server.use('/cocosDenshion', express.static(__dirname + '/cocosDenshion') );
server.use('/classes', express.static(__dirname + '/classes') );
server.use('/resources', express.static(__dirname + '/resources') );

server.use(express.bodyParser());

server.get('/', function(req,res){
    res.sendfile('index.html');
    console.log('Sent index.html');
});

server.get('/settings',function(req,res){
   res.sendfile('settings.html');
   console.log('Send settings.html');
});

// API calls
server.get('/image/:name', function(req,res){
    if(files[req.params.name])
    {
        res.contentType(files[req.params.name].contentType);
        res.sendfile(files[req.params.name].path);

        console.log("Returning file" + req.params.name);
    }
});

server.get('/getPhotos', function(req,res){
    res.json(files);

});

server.get('/clearAll', function(req,res){
    files = {};
    res.statusCode = 200;
    res.send("");
})

server.post('/upload',function(req,res){
    files[req.files.Filedata.name] = {
        "name":req.files.Filedata.name,
        "path":req.files.Filedata.path,
        "size":req.files.Filedata.size,
        "contentType":req.files.Filedata.type,
        "description":req.body.description };
        console.log(req.files.Filedata);

    console.log(Object.keys(files).length);
    res.statusCode = 200;
    res.send("");
});
server.listen(process.env.PORT || 3000);

 

First off, we have added the files var, which is going to hold our file data in memory.  The server.post() handler for upload is probably the most significant change.  This code takes the uploaded form information and populations our files data.  One key addition though was:

server.use(express.bodyParser());

This tells express to install a piece of middleware, that actually processes the form data, and is what makes the /upload method actually have data.

/clearAll is handled by simply erasing our files data, while /getPhotos simply returns that data in JSON format.

 

 

At this point if you are following along at home, you may be wondering how to submit your changes up to heroku.  The process is fairly simple, from a command prompt in your app folder:

heroku login ( give username and password )

git add .

git commit –m “description of changes”

git push master heroku

 

 

In a nutshell these commands a) log you in to heroku b) adds all the new files to your local git repository c) commits the changes you have made into your git repository d) pushes that repository up to heroku. Heroku will automatically restart your app.

 

Here then is our application running on heroku.  Click the settings link in the top right corner to bring up the new settings page we just created.

 

 

In the next part, now that we have a server, a client and some data to work with, we will get down to the actual task of creating our simple game.

 

Here ( assuming it is running ), is our application.  Again, I warn you about whatever content might be live!

General, Programming , , , ,

17. July 2012

 

One of the catches with a web application is finding a place to host it.  If you just have a couple static pages this is pretty simple, there area  few thousand different hosting companies that will serve your pages for a few dollars a month.  However, once you start talking about server side programmability, things get much more complicated.  In this case you generally need a dedicated server or at least, a shared server.  However, the recent move towards cloud computing gives you another option.

 

Such as Heroku.

 

We are now going to look at uploading our cocos2D JavaScript web application to Heroku.  First things first, you need to sign up.  Don’t worry, you don’t need to pay nor give them a credit card, the entry tier is free.

 

Now that you are signed up, we need to make a couple really small alterations to our project, don’t worry, both are pretty minor.  First create a file named package.json

{
    "name": "firstthis",
    "version": "0.0.1",
    "dependencies": {
        "express": "2.5.x"
    },
    "engines": {
        "node": "0.8.x",
        "npm":  "1.1.x"
    }
}

Package.json is a JSON format config file that tells Node what dependencies you have.  You need to tell it what libraries you need ( generally all the things you  “require”ed in code).  The second section is also very important, as it tells what version of Node you want to use.  This is very important with Heroku as if you do not specify a version, you will get Node 0.4.x, which isn’t compatible with our project.  When you run your Heroku app, package.json will determine what is installed.

 

You also need to create a file called Procfile ( with no extension ), like this:

web: node server.js

Think of this like a BAT or SH file that is run on Heroku’s servers when you run it.  You will see this in action shortly. 

 

Now that our application is configured and ready for Heroku, lets get the tools installed.  Head on over to the Heroku toolbelt page and install the version that is right for you.  They have a Windows, Linux and Mac version, all of which should follow basically the same instructions.  For this tutorial I will be using the Windows version, but you should be able to follow along without issue no matter what OS you run.

 

image

 

 

After install completes, open a command prompt ( or terminal… ) and type:

heroku login

Log in using the email address and password you signed up with. If prompted to create an SSH key, allow it.  If you need to generate an SSH key manually, you can do so with the following command:

ssh-keygen –t rsa –C “your@emailaddress.com

You can then tell heroku to use this key with the command:

heroku keys:add

Now it’s time to set up a git repository, which is how we deploy to Heroku.  Don’t worry, its not all that scary.  Again, at the same command line, switch to your application directory ( this part is very important, make sure you cd to your application code directory ) and enter:

git init

git add .

git commit –m “This is a commit comment, put whatever you want”

This combination of commands creates a git repository, adds everything from the current directory and below to it, then commits the changes.  If you look in your directory, you will now notice a .git folder. 

 

Now lets create and deploy our app to heroku. First enter:

heroku create

git push heroku master

If prompted for a security question about trusting heroku, type yes.  These two lines essentially created the app on heroku’s servers, then pushed our git archive to heroku.  At this point, your code is now deployed to Heroku’s servers… almost there!

Now we fire up a copy of our app on their server.  This is where the Procfile we defined earlier comes in.  Essentially you are going to run the command you defined in web: in your Procfile, do this with the command:

heroku ps:scale web=1

Finally, since we are using express, we need to set an environment variable:

heroku config:add NODE_ENV=production

 

And your app is now deployed and live.

 

So… um… where is it?  Ah yeah… type:

heroku apps

image

These are your app server names.  In your case you will have just a single one right now.  Simply take this name and add .herokuapp.com to it.

 

For example, when you open http://radiant-planet-8015.herokuapp.com you see:

image

 

At this point we are running a cocos2D app, served by Node, hosted on Heroku!

 

You can try it out yourself, but I make no promises the server will still be running, so do not consider that URL permanent.  At this point you should be able to deploy your own app to Heroku.

 

The next part is now live.  In this section we will add the ability to populate our application with data.

General , , ,

17. July 2012

 

Google’s cross platform PlayN game library has just released version 1.4.  PlayN enables you to target desktop, iOS, Android, HTML5 and Flash using a single Java code base.

 

 

Details of this release:

 

 

PlayN 1.4 highlights:


- You can now find out when your Android or iOS game is paused and
resumed via PlayN.LifecycleListener.


- WebSocket support has been added (only works on HTML and Java
backends right now).


- Custom GLSL shaders are now supported on all GL-based backends
(HTML5/WebGL, iOS, Android, Java).


- You can use JavaPlatform for your unit tests without having to wire
up the LWJGL native libraries: use JavaPlatform.registerHeadless.


TriplePlay 1.4 highlights:


- Page turn and (iOS-style) flip transitions that use custom shaders
to achieve real 3D perspective (check out the demo on a WebGL-capable
browser: http://threerings.github.com/tripleplay/widgetdemo.html).


- The long awaited particle system has arrived, break out the
fireworks. This currently only works on GL-based backends, but may
some day work on non-GL backends (less performantly).


- There are a couple of not-yet-finished cool new things:

  • a mechanism for syncing persistent storage across multiple clients
    with conflict resolution (so people can play your games on all their
    devices with the same save game state)
  • a player for our Flash animation exporter
    (https://github.com/threerings/flump), so you can export animations
    from the Flash authoring tool and use them in PlayN games

 

Full release notes available here.

 

I have created a number of getting started guides for PlayN, start here for Eclipse and right here for Netbeans.  Of course, be sure to update the version number in either guide.  Once you get through the install process, it’s a very nice library to work with.

News ,

16. July 2012

 

I wrote earlier about getting PssStudio ( now PsmStudio ) running on Windows 8, but at the time I could not get it to actually debug on my Vita or run the simulator.  Both of these issues were caused by the same thing, the failed Vita driver install.

 

In the end, there was a fix available all along.  I tried an earlier suggestion to do it with a policy change, but that no longer works.  The above link though, it does the job.

 

So between following this post to get Studio running ( and to fix MSBuild incompatibilities with .NET 4.5 ) and the above link to install the drivers, I know can develop Vita applications on my Windows 8 laptop.

 

Woot.

 

 

Why you ask?  Well, because it’s shiny and new of course!  Why else?

General , ,

15. July 2012

 

Here at GameFromScratch.com, we have run a number of guides on how to create games but nothing on how to actually make money off them.  The following is a guest post by Ben Chong, an HTML5 game developer and founder of marketJS.com.

The advice, views and opinions expressed below are not necessarily those of GameFromScratch.com.

 

It’s been 6 months since the last guide about monetization was written. Considering how fast things are moving with HTML5 games, it’s timely to write a new one. Please note, this guide chooses the path of least resistance to the money.


Chrome Web Store

Probably the easiest to begin with. Host your game, run ads on it. Two ad networks to trust are

  • Google Adsense - variable rates, but it depends a lot on what’s on your game page. Try inserting HTML5 related keywords, because companies are spending more money on HTML5-related ads. You’ve probably seen countless “Ludei ❤ HTML5 “ and “CocoonJS” ads. Capitalize on this, and make sure some of that ad spend trickles into your pocket.
  • Ad4Game - this network displays pure game ads. You’ll be promoting other games from large game studios. eCPMs of about $1.50 - 2.00, and they do very timely NET30 Paypal payments. Contact Angelica, tell her that your game’s on the Chrome Web Store. She’ll be delighted to set you up.

If you’re feeling brave, try out Google’s In-App Payments API. It might take an hour to figure out and a few more to integrate with your game. That is, assuming that your game actually functions well with in-app purchases.


Being featured matters a lot in the Web Store.


A normal featured game fetches about 1000 plays/day. A game featured on the front page of the games section, right at the top gets about 60,000 plays/day, or 60x.


Google loves it when you showcase what their engineers have built. If you want to get your game featured, remember to integrate some of Google’s APIs: WebGL, Chrome Fullscreen, Web Audio, etc. You can’t obviously integrate all of them, but having a few will give you a boost over other game devs. Once you’re ready, start pitching playable games to Google developer advocates. You can find them all here.


Costs: your server hosting fees, integration time and pitching time


iOS and Android

Deploy your game using one of the many wrapper tools out there, like appMobi, Ludei’s CocoonJS, GameClosure and Spaceport.

Ludei seems to be the only one publicly telling the world how great their engine is. They’ve got the entire monetization suite ( iAds and in-app purchases ), which is always a bonus for developers.

The upside is, once you manage to successfully master one of the tools above, you get access to virtually 100% of the mobile app market. Whether people will actually download your game is an entirely different topic.

Before launching your game, remember that you have only one shot at this. If your game flops in the App Store, you might be able to save it by doing free-app-a-day promotions/price manipulations. However, the download spikes you get from promotions do not last. Your game will be piled under 1000 new games being published each day. Find your niche, and market wisely via developer forums like TouchArcade. Don’t forget to pitch to blogs like Kotaku, they always enjoy a good story.


Costs:

  • appMobi charges $99 for a game dev toolkit.
  • Spaceport takes 10% of anything you earn.
  • CocoonJS and GameClosure are free, but you need to personally contact the companies.
  • hours in learning how to use the tools and integrating with your game.
  • iOS dev account costs $99/year.
  • Google Play account costs $25/year.

Facebook

Facebook canvas games don’t get the attention they deserve, but they’re still wildly profitable if done right. The virality from game invites/activities are what you should be focusing on when designing a Facebook game.

Ads and virtual goods (Facebook Credits) work well here. Note that Facebook doesn’t allow google ads running, so you need to look for other game-focused ad partners like Ad4Game.

Another caveat: not all HTML5 games will work perfectly on Facebook, because they still have a percentage of users that have older browsers. What to do? Your best bet is to politely ask them to download and use Chrome, or the Google Chrome Frame plugin.


Costs:

  • server hosting fees
  • integration time with Facebook APIs

Mac App Store

Not as popular as the iOS App Store, but worth a shot. One of the earliest HTML5 games we noticed here was Onslaught Arena.


Google+ Games

Google is a bit picky when it comes to selecting partners, on grounds of maintaining the user experience. You need to have a reputation and a hit game to be considered ( think Triple Town ).


Intel App Up Store

Intel gives you access to the PC app market. No hard numbers on revenue, but they run a small fund to encourage developers.


Pokki Store

Pokki gives you access to the desktop games market. Wrap your game inside their SDK and deploy! We don’t have hard numbers of how well their games monetize. Last we know, they ran a HTML5 games contest which proved lucrative.


Mozilla App Marketplace

Should launch in late Q3 2012. Firefox has about 25-28% of the browser market. Putting your games here should theoretically produce similar revenue numbers to that of the Chrome Web Store. Mozilla has bigger plans ahead, particularly in mobile. Would be interesting to see if this ties in well with the App Marketplace.


Sell distribution rights

An increasing number of publishers are looking to pepper their own game portals with fresh HTML5 content.

These publishers are looking to license games that run on the web and mobile ( yes, games that run on the mobile safari/android). There are a few ways you can capitalize on this:

  • sell exclusive rights for a high price ( $1500 - 2000+ ) to one publisher/
  • sell non exclusive rights for $500+, to multiple publishers.
  • sell distribution rights to publishers, and take 60-80% from all ad/virtual goods revenue generated

You are free to negotiate any type of deal with publishers. Most developers prefer upfront payments, but if you think the publisher has impressive reach, doing a revenue split from ads/virtual goods might be a smart move. A top developer recently made 4 figures a month from Google ads alone.

Costs

  • time to optimize your game for the mobile web.
  • time to integrate your game with the publisher’s APIs ( if required ).

How do I find these publishers?
  • Our startup, marketJS connects HTML5 game developers with publishers. It’s free to use, and we’ve got a good database of publishers hungry for games. Upload a game, and start negotiating!

So many choices

There’s no single best option to monetize your games. Build a team, adopt a shotgun approach, analyze results and seek advice from other developers.


Can I go full-time making HTML5 games?

Yes, you can make a high 5 figures/year by making HTML5 games. This excludes development contracts and funded projects. Snag a few of those, and you might even hit 6 figures.

Pick your battles, test each market, and keep polishing. The games industry is very competitive, but extremely fulfilling.

General ,

Month List

Popular Comments