Explore Free LimeJS Tutorials – GameDev Academy https://gamedevacademy.org Tutorials on Game Development, Unity, Phaser and HTML5 Fri, 17 Feb 2023 21:15:25 +0000 en-US hourly 1 https://wordpress.org/?v=6.1.1 https://gamedevacademy.org/wp-content/uploads/2015/09/cropped-GDA_logofinal_2015-h70-32x32.png Explore Free LimeJS Tutorials – GameDev Academy https://gamedevacademy.org 32 32 How to Make an HTML5 Game https://gamedevacademy.org/how-to-make-a-html5-game/ Thu, 06 Jan 2022 09:30:39 +0000 https://gamedevacademy.org/?p=1585 Read more]]> Although Flash games have departed from this world, there is still a significant demand for browser-based and cross-platform games. Whether you yourself actively play them or not, more and more games from professional and indie developers alike come out each day.

This phenomenon is largely thanks to HTML5 games which have filled the gap to keep up with these eager gamers. In addition, thanks to the advancement of technology and new frameworks, HTML5 game development has reached extensive heights, allowing for multiplayer experiences, 3D graphics, and more! It is not unwise to say that gaming is now just as viable via a browser as it is on many other devices!

Assuming this sounds like an exciting prospect to you as a game developer, in this guide we’re going to delve into the topic of HTML5 game development and give you the run-down of how you can make your own games! Sit back, relax, and prepare to enhance your game development skills in entirely new ways!

What exactly is an HTML5 game?

Let’s start from total zero. What is HTML5? that’s a tricky question. There is an official definition of HTML5, which simply stands for the latest revision of HTML (the markup language used all over the world to build websites), and the more hyped definition (what most people understand when HTML5 is mentioned) which is all the “new” features of the web technologies that have come out in the last few years (JavaScript API’s like the Canvas or WebAudio, semantic HTML tags, etc).

For our purpose, we’ll use bits of the two. HTML5 is HTML in its latest version, which includes a whole bunch of cool features that make web technologies an open standard with endless possibilities combining HTML, CSS and JavaScript.

Having HTML along with all these superpowers that go beyond making a simple website allows us to make, among other things, games. These are HTML5 games.

BUILD YOUR OWN GAMES

Get 250+ coding courses for

$1

AVAILABLE FOR A LIMITED TIME ONLY

 Building blocks

The very basic building blocks of a HTML5 game are those of the web:

  • HTML
  • CSS
  • JavaScript

Similarly to what happens with HTML5, when people talk about CSS3 they usually refer to the new things that come with CSS’s latest specifications, but in an analog manner, CSS3 is simply the latest CSS. Ignoring for a second the semantics of these definitions and thinking of the hyped versions of these terms, we also may need, in order to make HTML5 games:

  • HTML5 (JavaScript API’s)
  • CSS3

With the above you can make awesome games that will run on modern web browsers on mobile and desktop, but some games might require more features, so there are more building blocks that you can add.

For instance, you may want to make 3D games. If that is the case there is also WebGL, which is a JavaScript API to render 2D and 3D graphics on the browser, using the GPU for greater performance.

Road crossing game made with HTML5

Server side

If you want your games to saved data remotely you’ll need a server-side for your game. You can develop your own backend using any server-side language, you’ll need well a server in this case.

  • JavaScript (NodeJS)
  • PHP
  • Java
  • Python
  • Ruby

Or you can use a third-party Backend-as-a-Service provider such as Firebase or Parse. Some have free versions you can use and they’ll start charging you once you surpass certain limits. Some of these providers are particularly focused on games, some are mostly conceived for mobile apps but can be used for games too.

How to distribute a HTML5 game

The easiest way to distribute a HTML5 is to simply put it out there! By being built as a website, you can just embed it in on a page and publish it. Just like that.

If you want to distribute it through proprietary platforms you have to go through a process called wrapping. Basically, you create a native app for the platform you wanna distribute it to (iOS, Android, etc) and put your game inside so that this app acts like a web browser and “runs” your game.

For desktop platforms such as Windows, Mac or Linux there is a tool called NWjs that allows you to pack your HTML5 games for these platforms.

We can only cover the basics here, but we encourage you to read our more in-depth advice about publishing games.

Match 3 game made with HTML5

HTML5 game frameworks

Most games share some concepts, that of sprites (graphic elements that represent enemies, players, elements in your game), scenes or stages, animations, sound, loading graphic assets, etc. Since most game developers want to focus on their actual game and not in creating this whole abstraction layer, it is recommended you use a HTML5 game frameworks.

HTML5 game frameworks and libraries that contain building components you can use to create your own games. These libraries are Open Source projects created and maintained by people who want to contribute to the HTML5 gamedev environment. In many cases they created the frameworks for their own games, and after realizing that other people would want to not only use it but also contribute to it they released them as Open Source code, so everybody wins.

Picking what game engine to use is an important decision, so make sure you do proper research before making your choice. No matter what engine you pick, you will have to get familiar with its code and inner working if you want to use properly, so they shouldn’t be treated as black boxes.

What can help you make your choice:

  • Is your game for desktop, mobile or both?
  • Do they have an active community?
  • Are there many people using the framework nowadays?
  • Is it being maintained or the Github page looks like an abandoned town?

Sometimes looking at real games gives you more insight than just words. This project compares different engines by making the exact same Breakout game in all of them.

Some popular free frameworks are:

Solar system project made with Babylon.js

HTML5 game development courses

Video courses are a great way to learn new technologies. The main difference between a video course and just watching YouTube videos is that there is more structure. Good courses have a clear goal and build on to it step by step. Below a list of courses and tutorials by Zenva that can give you the tools you need to create HTML5 games.

General Game Development

Phaser

WebGL, 3D, and XR

HTML5 Skills

At the GameDev Academy, as you know already we have a bunch of HTML5 game development tutorials, mostly on Phaser, LimeJs, Quintus and BabylonJS. There are other great places to find good quality HTML5 gamedev tuts:

HTML5 for Schools

Are you a teacher looking to help students get into frameworks like Phaser or teach them core and relevant web development skills? Try out Zenva Schools – an online platform offering coding-based courses for use in the classroom. The platform comes with video lessons, text summaries, quizzes, classroom management features, reporting, and more to help support learning HTML5!

HTML5 gamedev communities

You can find plenty of active communities on the Internet, some focus on gamedev in general and some others just in HTML5 gamedev.

Web:

Facebook:

Other Communities:

HTML5 gamedev challenges

  • The Global Game Jam® is an annual event, usually occurring in January every year. Participants work concurrently around the globe, and around a central theme, and then work together to create a game.
  • j13k competition: the competition is over but you can still read the Blog, subscribe to the Newsletter, and check the Resources for tools.

 HTML5 gamedev podcasts

I just know Lostcast, a podcast created by the guys from Lost Decade Games (whom we’ve interviewed in the past). In the podcast episodes they talk about they HTML5 games and game development in general.

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

]]>
Create a Maze Engine in HTML5 https://gamedevacademy.org/create-a-maze-engine-in-html5/ Mon, 16 Sep 2013 22:06:26 +0000 https://gamedevacademy.org/?p=1326 Read more]]> In this tutorial, you will learn how to create a maze-like navigation system which you could apply to “point and click”, graphical adventures games, and more innovative genres as well. This system was used in my game Me Mnemonic, an HTML5 action memory game for Android, Firefox OS devices and web. At the end of this tutorial, you will be able to create any maze structure, with just few lines of codes, and navigate through it with keyboard arrows, mouse click or touch.

Requirements

You should be familiar with HTML, CSS, JavaScript and basic object oriented concepts. I will be using limeJS, which is the one most used game frameworks. Please check the documentation on their
web site and install it.

What to expect

You can download the game files here. The root folder contains the non-compiled files, which you can open and read. You’ll need limeJS installed if you want to run them. There is also compiled version, in the “compiled” folder, which you can run standalone in your web browser (“compiled” in the limeJS lingo really means “minified” so that all the dependencies are in a single JavaScript file). Now we will browse through the files and I will explain how this all works.

How it works

Here is the list of files that we will be using:

  • direction.js
  • Level.js
  • Level_1.js
  • maze.css
  • maze.html
  • maze.js
  • Room.js

and a short explanation:

  1. maze.html is a game view, run this to see the maze in action
  2. maze.js is the starting point of the game, something like the main controller. There, we will create the Director, who’s job is to manage the game screens. It will load our maze screen.
  3. The maze screen is created by the class maze.Level_1. All you have to do is populate the array this.rooms, in the constructor, with maze.Room objects.
  4. The rest will be done by it’s parent class maze.Level. Based on the list of rooms, in the array this.rooms, it will create a maze and set up navigation events/controls.

That’s it.

Let’s go deeper

maze.js

maze.start = function() {
    // create game director to manage screens
    var director = new lime.Director(document.getElementById('maze'), maze.size.width, maze.size.height);
    // create maze first level
    var level = new maze.Level_1(); // in constructor you set up the maze rooms, see maze.Level_1 class
    level.create(); // we start the engine to build the maze
    director.replaceScene(level); // show it!
    director.setDisplayFPS(false);
}

Nothing special here, just create and show the maze.

maze.Level_1.js

/** 
 * @constructor
 * @extends {maze.Level}
 */
maze.Level_1 = function() {
    goog.base(this);
    this.rooms = [
        new maze.Room([maze.direction.UP, maze.direction.RIGHT], [0, 0]),
        new maze.Room([maze.direction.RIGHT, maze.direction.LEFT], [0, 1]),
        new maze.Room([maze.direction.LEFT], [0, 2]),
        new maze.Room([maze.direction.UP, maze.direction.DOWN], [1, 0]),
        new maze.Room([maze.direction.RIGHT, maze.direction.DOWN], [2, 0]),
        new maze.Room([maze.direction.UP, maze.direction.LEFT], [2, 1]),
        new maze.Room([maze.direction.RIGHT, maze.direction.DOWN], [3, 1]),
        new maze.Room([maze.direction.UP, maze.direction.LEFT], [3, 2]),
        new maze.Room([maze.direction.UP, maze.direction.DOWN], [4, 2]),
        new maze.Room([maze.direction.RIGHT], [5, 0]),
        new maze.Room([maze.direction.RIGHT, maze.direction.LEFT], [5, 1]),
        new maze.Room([maze.direction.DOWN, maze.direction.LEFT], [5, 2])
    ];
}

This is the maze setup. The maze is a set of “rooms”, where we see only one at the time (see demo). Every maze.Room object has to know where is the exit (to up, right, down or left) to other rooms (first parameter array) and its position in the maze (second parameter array).

Room directions

For direction, we use enum maze.direction

/** 
 * Constants for direction
 * @enum {string}
 */
maze.direction = {
    UP: 'up',
    RIGHT: 'right',
    DOWN: 'down',
    LEFT: 'left'
}

In order for this to work, you have to use directions always in the same order: up, right, down or left. So [maze.direction.LEFT, maze.direction.DOWN] is not going to work, but [maze.direction.DOWN, maze.direction.LEFT] is OK. I like to use enums like this because then you make less errors while typing.

Rooms positions

Here is the maze map, the letter Z:

map

To create this structure in the code, we use an array with 2 dimensions for the room position – the first index is for row, and the second for column. It’s like we are building the table with rows and columns, from bottom to top:

  • [0, 0] means 1st row, 1st column,
  • [0, 1] means 1st row, 2nd column,
  • [0, 2] means 1st row, 3rd column,
  • [1, 0] means 2nd row, 1st column,

Directions and positions

Putting it all together:
new maze.Room([maze.direction.UP, maze.direction.RIGHT], [0, 0]) means that this room has 2 directions, to UP and RIGHT, and its position is 1st row, 1st column. This is the maze starting room, the bottom left room. By default, the starting room is always the first item in this.rooms array.

The engine

Class maze.Level will, based on it’s subclass maze.Level_1, create the maze. maze.Level_1 is just a setup or configuration, but maze.Level is the engine. Let see some of the methods:

/**
 * Create maze.
 */ 
maze.Level.prototype.create = function() {
    /** @type {maze.Room} */
    var room;
    for (var i = 0; i < this.rooms.length; i++) {
        room = this.rooms[i];
        // set room image and move room outside of the screen
        room.setFill(room.getImage()).setPosition(-1000, 0).setSize(480, 320).setAnchorPoint(0, 0);
        if (i == 0) {
            // set first room as starting point
            room.setPosition(0, 0);
            maze.Level.currentRoom = room;
        }
        // set room neighbours, so we can know which room to show based on direction
        room.setNeighbours(this.getNeighbours(room, i));
        this.appendChild(room);
    }
    // add click/touch navigation
    this.setTouchNav();
}

This is the place where maze is created. It loops through all rooms and add them to the screen.

/**
 * A flag which tells whether room animation is in progress.
 * We need this to NOT interrupt moving to another room.
 * @type {bool}
 */
maze.Level.moving = false;

/**
 * Move to another room based on direction.
 * @param {maze.direction} direction
 */
maze.Level.prototype.move = function(direction) {
    // check if room has this direction and if animation is in progress
    if (goog.array.contains(maze.Level.currentRoom.directions, direction) === false || maze.Level.moving === true) {
        return;
    }
    var nextRoom = maze.Level.currentRoom.neighbours[direction];
    /** @type {goog.math.Coordinate} */
    var coordinate;
    // based on direction, set next room starting position and coordinates where should animation end
    switch(direction) {
        case maze.direction.LEFT:
            nextRoom.setPosition(-maze.size.width, 0);
            coordinate = new goog.math.Coordinate(maze.size.width, 0);
            break;
        case maze.direction.RIGHT:
            nextRoom.setPosition(maze.size.width, 0);
            coordinate = new goog.math.Coordinate(-maze.size.width, 0);
            break;
        case maze.direction.UP:
            nextRoom.setPosition(0, -maze.size.height);
            coordinate = new goog.math.Coordinate(0, maze.size.height);
            break;
        case maze.direction.DOWN:
            nextRoom.setPosition(0, maze.size.height);
            coordinate = new goog.math.Coordinate(0, -maze.size.height);
            break;
    }
    // move both, next and current, rooms 
    // we can see current room is going away and next room is coming
    var moveAction = new lime.animation.MoveBy(coordinate).setDuration(0.5);
    moveAction.addTarget(maze.Level.currentRoom);
    moveAction.addTarget(nextRoom);
    moveAction.play();
    // we don't want to interrupt current animation
    maze.Level.moving = true;
    // set event to know when animation is finished
    // so we can set next room to current and maze.Level.moving that animation is finished
    goog.events.listen(
        moveAction, 
        lime.animation.Event.STOP, function(){
            maze.Level.moving = false;
            maze.Level.currentRoom = nextRoom;
        });
}

This method is responsible for the moving animation. Based on room neighbours, it will set next room and move it along with the current one, so we get a felling that we are moving through the maze.

Where to go now?

Now you can try to make your own maze. Create maze.Level_2 and populate this.rooms array with maze.Room. Ok, that’s fine, now we know how to create maze, but this is not a game yet. We are missing the game logic. Maybe in a future, we can add some bad guys, monsters or any other obstacle to beat and play.

If you have any questions, you can contact me on Twitter: @bmilakovic

Other LimeJS tutorials at the GameDev Academy:

]]>
Dash – Visual Game Dev Tool is Looking for Funding https://gamedevacademy.org/dash-visual-game-dev-tool-is-looking-for-funding/ Wed, 17 Jul 2013 19:16:46 +0000 https://gamedevacademy.org/?p=718 Read more]]> Dash is an free online game creation tool built upon the HTML5 game development framework LimeJS. At the GameDev Academy, we’ve had the great pleasure to have spoken with the founder, Priyadarshi Chowdhary, who has shared more information about this project with our readers.

Before we begin the interview, I’d like to invite you all to check out and support his current crowdfunding campaign at Indigogo.

Can you tell us about your project Dash? what is it and who is it aimed for?

DASH is a visual programming tool and a game creator. It is HTML5 based software and web service which can run on any device. DASH is a complete set of tools and courses that can help people learn how to write code in a simple and creative way, age no bar. This tool is idle for students, teachers, hobbyists and designers.
We are also going to make a number of video courses for teaching game programming fundamentals using Dash.

What kinds of games can you make with Dash?

Dash is right now well suited for creating simple 2D arcade titles.  DASH supports following features:

  • Dynamic creation of objects
  • 2D Physics support
  • Particles
  • Scene Editor
  • Animation Editor

Using these features player can create any kind of 2D game except multi-player game which DASH doesn’t support yet.
We have created various demos at DASH website to showcase its capabilities.

Can the HTML5 code of the game be downloaded as well?

We are planning to add this feature to accompany the Video Courses. One or more courses will be focused on understanding this code and how some of it is applicable to other game engines in general.

What tools are you using to build Dash? (languages, programs)

Dash is built entirely in JavaScript and uses various features of HTML5. This allows it to run on any device with an HTML5 enabled browser.

The tool itself is made in the JavaScript game engine LimeJS. Games made with Dash run in the Gamvas game engine. Both LimeJS and Gamvas are open source engines.

Our development and testing environment consists of Notepad++ and the excellent Developer tools that are bundled with most modern browsers.

How is it different from other drag and drop tools to make games?

1. Multi-platform support. DASH is the first software which supports so many platforms. User can create games on any platform for any platform.
2. Close to real world programming language. Unlike others software we tried to keep the flow of DASH as close to object oriented programming language.
3. 2D Physics. DASH is using box2d physics engine for creating physics based games
4. Scene and Animation Editor: DASH inbuilt scene and animation editor makes it different and powerful than other software’s.

When will it be available to try?

Currently we are in BETA stage and access is available on invitation only.

But others can get BETA access by simply supporting our crowdfunding initiative

You can visit http://www.dashplay.net to try it out. You can try it as a guest but your project will not be saved on our server.

How can people get in touch with you about this great initiative?

Visit us at – http://www.dashplay.net Even if you haven’t received a BETA invite you can still use the forum.

Please use the Indiegogo website to provide feedback on our crowdfunding initiative.

]]>
HTML5 Mobile Game Development for Beginners https://gamedevacademy.org/html5-game-development-for-beginners/ Fri, 05 Jul 2013 13:09:04 +0000 http://rapid.wp-theme.pro/?p=58 Read more]]>

This course will guide you through the creation of games that run on iPhone, iPad, Android and Desktop using the open source LimeJS HTML5 game development framework.

The course is a 100% video based tutorial so that you can see in real time how games are created from scratch. Several game demos of different game genres are included in this course.

You’ve always wanted to make your own games. Don’t keep on postponing it. Start TODAY with HTML5 game development for iOS, Android, BlackBerry 10 and Windows 8.

Some of the things you’ll be learning here are:

  • Creating a game that works on iPhone, iPad, Android and Desktop
  • Using the touchscreen in your games.
  • Creating cool animations and transitions.
  • Adding sound to your games.
  • Creating your first spaceship game.
  • Using 2D physics in your games.
  • Creating a virtual pet game from scratch.
  • Creating a farming game from scratch.
  • BONUS TRACK: transform your game to a native app using Appcelerator and sell your game in the App Stores.

More great stuff:

  • We’ll be using 100% free tools and frameworks.
  • Good support.
  • Code snippets at the end of each lesson that you can use as starters for your own games.

https://academy.zenva.com

]]>
Create a Virtual Pet Game with HTML5 https://gamedevacademy.org/create-a-virtual-pet-game-with-html5/ Fri, 31 May 2013 22:16:37 +0000 https://gamedevacademy.org/?p=298 Read more]]> Intro

Once upon a time, kids used to play with real, “flesh and bone” animals like dogs, cats and hamsters. Today’s kids play with elaborated algorithms that simulate living beings and carry out actions such as eating, playing and even popping. We call these misguided inventions “virtual pets”.

I’m exaggerating. Kids still play with real animals and yes, they play with virtual pets too just like many grown ups do. And there is nothing wrong with that. Virtual pets are one more of the many types of video games you can find nowadays, and this tutorial is going to teach you how to make a simple virtual pet using which will run on any HTML5 supporting device.

HTML5 Game Development

One of the great things about HTML5 is that all you need to make games are a text editor, a web browser and of course a program to create the artwork. That part is not even necessary anymore with sites like OpenGameArt.org that provide awesome game artwork you can use for free.

We’ll be building this simple virtual pet game using a JS framework called LimeJS. You can download this framework and install it following the official guide at www.limejs.com.

The official guide provides you with a good starting point when it comes to the installation and usage of the framework. The community is also a great place to find information.

If you are looking for a guided and comprehensive alternative which teaches you all the basics of this great framework starting from scratch (well, assuming you have basic JS knowledge), I’ve prepared an online course titled HTML5 Mobile Game Development for Beginners, which you are welcome to check out (using the provided link will give you 30% off the course price).

 

Project Setup

After installing LimeJS as per the official guide or my online course, our next step will be to create the project. We are gonna open our terminal, cd to the limejs folder any type:

bin/lime.py create virtual_pet

This will create a folder called “virtual_pet” inside our limejs folder with some startup files. Let’s open virtual_pet.html and add some styling tags to the head section. This will give us a black background on the page and a little hack to fix an issue when changing scenes (we won’t use this in this tutorial, but it’s something I always add).

.lime-scene {display:block !important;}    
   body {background-color:black;}

Open virtual_pet.js and replace it’s contents by the following:

 //set main namespace
  goog.provide('virtual_pet');

  //get requirements
  goog.require('lime.Director');
  goog.require('lime.Scene');
  goog.require('lime.Layer');

  // entrypoint
  virtual_pet.start = function(){
      //object to store game-level properties
      var gameObj = {
          width: 320,
          height: 480,
          renderer: lime.Renderer.CANVAS
      };

      var director = new lime.Director(document.body,gameObj.width,gameObj.height);
      var gameScene = new lime.Scene().setRenderer(gameObj.renderer)
      var gameLayer = new lime.Layer().setAnchorPoint(0,0);
      gameScene.appendChild(gameLayer);

      director.makeMobileWebAppCapable();
      director.replaceScene(gameScene);
  }

  //this is required for outside access after code is compiled in ADVANCED_COMPILATIONS mode
  goog.exportSymbol('virtual_pet.start', virtual_pet.start);

This will give us an object called “gameObj” that we’ll use to store game-level properties and the basic elements all LimeJS projects have, like a director, a scene and a layer. The director takes care of the big picture, just like in a movie. Things like telling the app what scene is currently being shown are carried out by the director (“replaceScene”). Layers are containers that allow us to place elements into. The elements are placed in the layer’s own coordinates.

The Pet

I’m sure you have a cute pet in mind, something like a cartoonish hamster or a dog. Maybe some of you are thinking of out of the ordinary virtual pets, like a politician or Psy. No worries, the pet we’ll be having is something much simpler: how about a circle?

Our pet (lets call it Zenvita) will have two numeric properties:

  • Health. I thought it would be cool to have the circle grow in size as the pet gets healthier, and diminish if it becomes unhealthy (although with human beings it’s usually the opposite), until it reaches 0 and dies.
  • Happiness The happier the pet, the greener the circle. If the pet goes sad it will become brownish, until it eventually becomes red and dies.

Lets create a new file called pet.js with the following content:

goog.provide('virtual_pet.Pet');
goog.require('lime.Circle');

virtual_pet.Pet = function(gameObj) {
  goog.base(this);

  this.gameObj = gameObj;
  this.happiness = 100;
  this.health = 100;

  this.setPosition(this.gameObj.width/2, this.gameObj.height/2);
  this.updateLook();
};

goog.inherits(virtual_pet.Pet,lime.Circle);

/**
 * update the pet's look according to it's happiness and health
 */
virtual_pet.Pet.prototype.updateLook = function() {
    //size of the pet according to the health
    var petSize = this.gameObj.maxPetSize * this.health/100;
    this.setSize(petSize, petSize);

    //color according to the happiness (between green and red)
    var redAmount = parseInt((100-this.happiness)/100*255); //255 if 0 health
    var greenAmount = parseInt((this.happiness)/100*255); //255 if 100 health
    this.setFill(redAmount,greenAmount, 0);
};

After adding a new file don’t forget to “require” this new object back in virtual_pet.js:

goog.require('virtual_pet.Pet');

Add this to the gameObj object definition in virtual_pet.js:

maxPetSize: 200,

And run the following command on the terminal to update the project dependencies:

bin/lime.py update

Ok lets look into the pet.js file now. We are defining a new object called virtual_pet.Pet, which inherits from a Circle. LimeJS allows you to use the Google Closure inheritance capabilities. This basically means that a virtual_pet.Pet object will have the same properties and methods of lime.Circle, plus the new stuff we add in.

In the constructor we are passing it the gameObj object with game-level stuff so that it can be accessed or modified. We are giving the pet a default value of 100 for both happiness and health. The initial location of Zenvita will be the center of the screen. Finally, we are calling a method called updateLook(), which is defined further down.

updateLook() does the following:

  • Calculate the pet’s current size based on the default maximum size and the pet’s current health.
  • Setting this size to the pet, using setSize(), which is available on lime.Circle objects.
  • Calculate the amount of green and red according to the pet’s happiness. RGB color definitions consist in three numbers that go from 0 to 255 and represent the amount of red, green and blue. Zenvita will have no blue, just red and green according to it’s happiness.
  • Definite the filling of the circle as per the amount of each color.

Let’s create the new pet in virtual_pet.js and see the result. Add the following after “gameScene.appendChild(gameLayer);”:

//create pet
var pet = new virtual_pet.Pet(gameObj, gameLayer);
gameLayer.appendChild(pet);

If you reload your browser you should see the pet with a black background. If you change the health and happiness of the pet and reload the page you should be seeing the increase in size and the color changes.

Game Over Conditions

Let’s make it so that if Zenvita reaches 0 health or 0 happiness, it dies. And let’s make it a very demanding pet that needs to be constantly entertained and fed. Zenvita will lose 1 unit of health and happiness per second, which means if you leave it still for 100 seconds it will die.

We’ll use the scheduler manager function to setup a timer, so that it’s executed every 0.1 seconds. Now why not every second? well, I’m planning on using this same timer later on for another feature which requires a shorter span, so 0.1 seconds will do for both.

In the virtual_pet.Pet constructor, add the following bellow “updateLook();”:

var dt = 100;
lime.scheduleManager.scheduleWithDelay(function() {
        this.happiness -= 0.1;
        this.health -= 0.1;

        //game over
        if(this.happiness <= 0 || this.health <= 0) {
            alert('Game over!');       
            location.reload(); 
        }

        this.updateLook();
    }, this, dt);

What does piece of code does, it runs every 100 milliseconds, and on each run it diminishes the pet’s health and happiness and updates the pet’s look. If any of the properties reaches a value of 0 or lower, the game is over and the page is reloaded (you can replace that with a proper ending/sad screen).

Background and Menu Area

Let’s add a background color to the game and a menu area. Add the following in virtual_pet.js after the gameLayer definition, which will give us basic rectangles to represent these areas:

var background = new lime.Sprite().setSize(gameObj.width,gameObj.height*4/5).
        setFill('#F3E2A9').setAnchorPoint(0,0).setPosition(0,0);

var menuArea = new lime.Sprite().setSize(gameObj.width,gameObj.height/5).
        setFill('#8B5A00').setPosition(gameObj.width/2,gameObj.height*9/10)

gameLayer.appendChild(background);    
gameLayer.appendChild(menuArea);

After reloading, the game should be looking like this:

Pet Items

Ok so far there isn’t much going on except making our pet hungry and upset. We need items like apples, ice creams and toys to get this more interesting.

We’ll create a new file called item.js, don’t forget to add a “require” statement for it in virtual_pet.js and to run the LimeJS project update command that we ran before. Use the following for the file’s contents:

goog.provide('virtual_pet.Item');
goog.require('lime.Sprite');

virtual_pet.Item = function(happiness, health) {
    goog.base(this);

    this.happiness = happiness;
    this.health = health;    
}

goog.inherits(virtual_pet.Item,lime.Sprite);

Things to keep in mind:

  • Our item object inherits from lime.Sprite (used to create rectangles or images).
  • When creating an item object, the happiness and health this item provides to the pet have to be given as parameters.

Now in our menu area we will be adding button to give the pet some items. In a more polished version there could be a screen to pick among hundreds of items with different features, you could have them loaded from the web and make the user buy them with real money 🙂 .. in this demo we will take a much simpler approach and hard-code three items for the user to pick.

Let’s add the following code to virtual_pet.js, after the menu area was appended to the Layer:

var appleButton = new lime.Sprite().setSize(gameObj.height/10,gameObj.height/10).
        setPosition(gameObj.width/4,gameObj.height*9/10).setFill('images/apple.png');

    goog.events.listen(appleButton, ['touchstart', 'mousedown'], function(e) {
        e.stopPropagation();
        gameObj.currentItem = {
            width: gameObj.height/10,
            height: gameObj.height/10,
            fill: 'images/apple.png',
            happiness: -5,
            health: 20
        };
    });

    var icecreamButton = new lime.Sprite().setSize(gameObj.height/20,gameObj.height/10).
        setPosition(gameObj.width/2,gameObj.height*9/10).setFill('images/icecream.png');

    goog.events.listen(icecreamButton, ['touchstart', 'mousedown'], function(e) {
        e.stopPropagation();
        gameObj.currentItem = {
            width: gameObj.height/20,
            height: gameObj.height/10,
            fill: 'images/icecream.png',
            happiness: 20,
            health: -10
        };
    });

    var toyButton = new lime.Sprite().setSize(gameObj.height/15,gameObj.height/10).
        setPosition(gameObj.width*3/4,gameObj.height*9/10).setFill('images/toy.png');

    goog.events.listen(toyButton, ['touchstart', 'mousedown'], function(e) {
        e.stopPropagation();
        gameObj.currentItem = {
            width: gameObj.height/15,
            height: gameObj.height/10,
            fill: 'images/toy.png',
            happiness: 10,
            health: 0
        };
    });

    gameLayer.appendChild(appleButton);    
    gameLayer.appendChild(icecreamButton);    
    gameLayer.appendChild(toyButton);

Note: if you want to make this something more abstract instead of repeating the code like this, you can look at my farming game tutorial on Binpress for a more polished implementation of this feature.

What we are doing with the buttons is:

  • Creating sprites with image backgrounds for each button (you can download all the code and images further down).
  • Binding mouse clicks and touch events to each button so that a “currently selected item” is setup on each case.

See how the apple will add health but take happiness away (apples are a bit boring, lets face it), icecreams will bring happiness but make it sick, and toys will just add a bit of fun to Zenvita’s life.

Nom nom nom

Having given the user the ability to pick an item, we need now to give them the ability to place these items on the game background, so that Zenvita can come by and nom nom nom…

Firstly, let’s add another property to the gameObj object definition, which should look like this:

var gameObj = {
        width: 320,
        height: 480,
        renderer: lime.Renderer.DOM,
        maxPetSize: 200,
        items: []
    };

The items array will contain all the items that are dropped on the game background. Let’s add a click/touch event binding to the background, in virtual_pet.js, right after the background definition, so that new items are created when the user clicks on it:

goog.events.listen(background, ['touchstart', 'mousedown'], function(e) {
        if(gameObj.currentItem) {
            var pos = e.position;
            var newItem = new virtual_pet.Item(gameObj.currentItem.happiness,gameObj.currentItem.health)
                .setPosition(pos)
                .setSize(gameObj.currentItem.width, gameObj.currentItem.height)
                .setFill(gameObj.currentItem.fill);
            gameLayer.appendChild(newItem);
            gameObj.items.push(newItem);    

            var movement = new lime.animation.MoveTo(e.position.x,e.position.y).setDuration(2);
            pet.runAction(movement);            

            gameObj.currentItem = null;
        }
    });

This will create the item object and place it where we click (or touch). We are also creating an animated movement so that the pet goes to where the item has been dropped. The current item selection is cleared by setting this property to null.

In pet.js, inside our scheduler function, we will add collision detection so that items are consumed by the pet if they are occupying the same space (otherwise, the pet will go towards the food but it will not be eaten). The scheduler function will look like this:

var dt = 100;
var i, arrayLen, toRemove;
lime.scheduleManager.scheduleWithDelay(function() {
        this.happiness -= 0.1;
        this.health -= 0.1;

        //game over
        if(this.happiness <= 0 || this.health <= 0) {
            alert('Game over!');       
            location.reload(); 
        }

        //check for collision with items   
        toRemove = new Array();
        for(i = 0, arrayLen = this.gameObj.items.length; i<arrayLen; i++) {

  if(goog.math.Box.intersects(this.gameObj.items[i].getBoundingBox(), this.getBoundingBox())) {
                this.happiness = Math.min(this.happiness+this.gameObj.items[i].happiness,100);
                 this.health = Math.min(this.health+this.gameObj.items[i].health,100);
                 toRemove.push(i);
            }
        }

    //remove picked up items        
    for(i = toRemove.length; i > 0; i--) {

            this.gameLayer.removeChild(this.gameObj.items[toRemove[i-1]]);
            this.gameObj.items.splice(toRemove[i-1],1);
        }
        this.updateLook();
    }, this, dt);

What’s going on here:

  • We iterate through the placed items (array gameObj.items), if any of them collides with the pet, it is added to a “toRemove” array.
  • Colliding elements add/subtract health and happiness to the pet.
  • We remove all colliding items.
  • The reason why I’m doing for(i = 0, arrayLen = this.gameObj.items.length; i<arrayLen; i++) instead of for(i = 0; i< this.gameObj.items.length; i++) is because getting an array’s length uses up resources, so it’s more efficient to carry out this operation just once instead of in each iteration.

Pets Like to be Petted

Let’s add one final thing to this game. Pets like to be petted, so how about we make it so that when the pet is dragged around it increases it’s happiness?

Add the following code to the constructor in pet.js, after the scheduler. Using “e.swallow” can be used in other events in LimeJS and it allows you to run code when the event is finished.

//drag it around to make it happier
    goog.events.listen(this,['mousedown','touchstart'],function(e){
        e.startDrag(true);

        var pet = this;
        e.swallow(['mouseup','touchend'],function(){
            this.happiness = Math.min(this.happiness+5,100);
        });
    });

Download the Files

You can download the code and images of this tutorial using this link.

Next Steps

There are many ways you could improve this game demo and turn it into a blockbuster hit:

  • Add the ability to save/load the data from a server
  • Instead of having a circle for a pet use a nice cute character, and animate it according to it’s health and happiness.
  • Add countless items to buy, trade, etc.
  • The pet could have random behaviors, like a rush of happiness or a panic attack.

I hope you enjoyed this tutorial and are eager to learn more on HTML5 app and game development. At Zenva, we have many courses on app and game development, feel free to check them out here.

And don’t forget that by using the following link, you get a nice discount on the course Mobile HTML5 Game Development for Beginners, which uses the LimeJS framework to create many cool game demos such as this one. The course will also guide you through the steps you need to go through in order to pack your HTML5 game into a native app for iOS and Android.

]]>
Create a Mobile HTML5 Farming Game https://gamedevacademy.org/create-a-mobile-html5-farming-game/ Fri, 31 May 2013 22:14:16 +0000 https://gamedevacademy.org/?p=295 Read more]]> Intro

Over the last few years, HTML5 has come out as a great alternative to develop cross-platform app using a single code base. A HTML5 app can run on iOS, Android, Windows Mobile, Blackberry.. and of course good old Desktop.

For amateurs and professional developers it’s quite easy to get started with HTML5 (which comprises HTML, CSS and Javascript) as all you need is a text editor and a web browser.

In this tutorial you’ll learn the basics on how to create a simple farming game that emulates those big hits you’ve played on Facebook. We’ll be using an open source HTML5 game dev framework called LimeJS.

Tutorial requirements

  • Basic HTML and Javascript knowledge
  • Basic notions of Object Oriented Programming
  • A text editor or IDE to create and edit code (I recommend Netbeans)
  • A terminal to run commands

Farming Games?

Farming games are a big phenomena that knows no limits when it comes to nationalities and generations. Fortunes have been made around them and people have created variations from the original concept. It’s not strange to find medieval, tropical, futuristic, even zombie themed farming games in the various app stores out there.

What is the reason behind this success? do we miss plowing the land with out bare hands in this post-modern urban civilisation? is this related to the urban farms people now grow on their balconies? Well who knows! ..

I’m not gonna tell you what the reasons are for their success (not that I know them anyway) but I am, on the other hand, gonna teach you how to make a simple farming game using HTML5 and an open source JS framework called LimeJS.

LimeJS

LimeJS is a Javascript game development framework that allows you to create cross-platform HTML5 games that work well on most platforms (specially iOS and newer Android devices).

You can dowload LimeJS from their home page. Installation instructions and a good intro can be found in the Getting Started Guide.

If you want step by step, video-based instructions on how to install this framework in Mac, Windows or Ubuntu and get a good hold of the basics feel free to check my online course, which teaches you all the basics of game development using LimeJS and other free tools.

If you want more info about my courses ask me on the comments section or on Twitter (@ZenvaTweets).

Game Elements

Our game will have the following elements:

  • Land
  • Plowing the land
  • A shop to get crops
  • Planting crops
  • Plants growing
  • Harvesting!

In this tutorial we won’t get into making it social or pervasive, but it might be on the horizon for future tutorials 🙂

Game World

Time to stop talking and dip our hands into the code. Oh yes. Assuming you have successfully downloaded and installed LimeJS (you should be able to run the examples that come with it) we’ll create a new project:

bin/lime.py create farming

This will create a folder called “farming” inside of the folder where LimeJS was installed. If you installed LimeJS correctly you should be able to find a file called “farming.html”. Open up the file and add the following below the script tag:

<style>
.lime-scene {display:block !important;}
body {background-color:black;}
</style>

All this is doing is setting the background to black and applying a little hack for a known bug on some devices. Now open farming.js and replace it’s contents with the following code:

//set main namespace 
goog.provide('farming');   
//get requirements 
goog.require('lime.Director'); 
goog.require('lime.Scene'); 
goog.require('lime.Layer');   

//entrypoint 
farming.start = function(){     

    //game object
    var gameObj = {
        width: 320,
        height: 480,
    }

    var director = new lime.Director(document.body,gameObj.width,gameObj.height);     
    director.makeMobileWebAppCapable();     
    director.setDisplayFPS(false);        

    var gameScene = new lime.Scene().setRenderer(lime.Renderer.CANVAS);
    var landLayer = new lime.Layer().setAnchorPoint(0, 0);
    var controlsLayer = new lime.Layer().setAnchorPoint(0, 0);

    gameScene.appendChild(landLayer);
    gameScene.appendChild(controlsLayer);

    director.replaceScene(gameScene); 
}

That is just a basic boilerplate (if you open farming.html you should see a black screen). Firstly, we are providing the namespace “farming” which is required to do when working in LimeJS. We are then including relevant framework modules. Our farming.start() is the first thing that is run when the game loads (see how this is being called in farming.html).

We can define an object called gameObj (or however you want) to store some game-level variables. We will be passing this object around to our game elements so that these properties can be accessed from everywhere.

In the next blocks we are defininig our “director” object which does a similar role as real life directiors: define which scenes are playing, etc. Our game will have two layers (which are areas where content will be placed). landLayer will host the land and the crops. controlsLayer will have the status area and the options for the user, which in this case is the button to enter the shop.

Controls area

Let’s include another file that provides a quick button:

goog.require('lime.GlossyButton');

We can add more properties to our gameObj that will contain some dimensions. It is recommended to do it this way instead of putting “magic numbers” in the code. Some of the properties I’m adding now will only make sense later in the tutorial so don’t worry if you don’t see them in the code right away:

//game object
var gameObj = {
    width: 320,
    height: 480,
    tile_size: 64,
    num_tiles_x: 5,
    num_tiles_y: 6,
    landLayer_w: 64*5, 
    landLayer_h: 64*6,
    controlsLayer_w: 64*5,
    controlsLayer_h: 64*1.5,
    costPlowing: 5,

    //shop
    shop_margin_x: 50,
    shop_margin_y: 20
}

Besides our game object, we also want to create an object for the player (just a design choice). The object will store the money and the currently selected crop (this will make sense later on). Add the following after the game object creation:

//player object
var playerObj = {
    money: 300,
    currentCrop: 0             
}

Now add the following code below “gameScene.appendChild(controlsLayer);”:

//controls area
var controlArea = new lime.Sprite().setAnchorPoint(0,0)
    .setPosition(0, gameObj.height-gameObj.controlsLayer_h)
    .setSize(gameObj.controlsLayer_w, gameObj.controlsLayer_h)
    .setFill('#0D0D0D')
controlsLayer.appendChild(controlArea);

//shop button
var shopButton = new lime.GlossyButton().setColor('#133242').setText('Shop')
    .setPosition(60, gameObj.height-gameObj.controlsLayer_h/2)
    .setSize(80, 40);
controlsLayer.appendChild(shopButton); 

//money
var moneyLabel = new lime.Label().setText('$'+playerObj.money).setFontColor('#E8FC08')
    .setPosition(gameObj.controlsLayer_w-50, gameObj.height-gameObj.controlsLayer_h/2);
controlsLayer.appendChild(moneyLabel);

What we just did was adding a grey container on the bottom, a button that says “Shop” and a text label showing the player’s current money. You should be seeing the following:

Game Tiles

The tiles used in this game have been adapted from Daneeklu’s artwork which has been released under the CC-BY-SA license, allowing us to use it for this purpose.

You can download all the game files from here.

Land

Back to work. To represent a unit of land we’ll create a new file called “land.js” and give it the following code:

goog.provide('farming.Land');
goog.require('lime.Sprite');

/**
 * Land elements
 * 
 * @param {} gameObj
 */
farming.Land = function(gameObj, playerObj) {
    goog.base(this);
    this.setAnchorPoint(0, 0);
    this.setSize(gameObj.tile_size,gameObj.tile_size);
    this.setFill('images/bare_land.png');
}

goog.inherits(farming.Land,lime.Sprite);

What we are doing here is creating a new type of object as per the LimeJS specs. This object “inherits” from the lime.Sprite object, so it behaves like a sprite in all ways. See how we are providing the namespace like we did before. We are passing the game and the player objects in the constructor, and we are setting up some basic properties so that we don’t have to enter them each time we create a farming.Land object.

Every time you add a new file to the project you have to run this command for the framework to keep it all registered:

bin/lime.py update

In farming.js add the following to the “require’s” section:

goog.require('farming.Land');

Now, we want to populate the land layer we created previously with our land lots. We’ll do that with an iteration and some of the game object properties that have been setup. Add the following under the money indicator definition:

//create land elements
    for(var i=0; i<gameObj.num_tiles_x; i++) {
        for(var j=0; j<gameObj.num_tiles_y; j++) {
            var landElement = new farming.Land(gameObj, playerObj).setPosition(i*gameObj.tile_size, j*gameObj.tile_size);
            landLayer.appendChild(landElement);
        }
    }

If you reload farming.html on your browser you should be getting this (provided you downloaded the images):

Land states

The first thing you do in a farming game is to plow the land so that it’s ready to receive the seeds. After you plant the seeds, they grow until ripe. We have then a total of 4 possible states for a lot of land (empty, plowed, growing and ripe). Let’s represent that by adding these states in our land.js file right after the “goog.inherits” part.

//states
farming.Land.prototype.EMPTY = 0;
farming.Land.prototype.PLOWED = 1;
farming.Land.prototype.GROWING = 2;
farming.Land.prototype.READY = 3;

And this line after “this.setFill” (inside farming.Land) to define the default state:

this.state = this.EMPTY;

Plowing

Every time the player clicks on a land element, we want it to be plowed (provided the land is “empty” and the user has enough money to pay for it). Let’s add an event listener inside the farming.Land function:

var land = this;
    goog.events.listen(this,['mousedown', 'touchstart'], function(e) {
        e.event.stopPropagation();        
        if(land.state == land.EMPTY && playerObj.money >= gameObj.costPlowing) {
            //plow land
            land.setFill('images/plowed.png')
            land.state = land.PLOWED;

            //update player money
            playerObj.money -= gameObj.costPlowing;
            gameObj.updateMoney();
        }
    });

What this does is attach the events “mousedown” and “touchstart” to the statements inside the listener. See how easily LimeJS allows us to create something that works in both touch and non-touch devices from day one.

We then check the player’s money. If the “show me the money” is all good, we’ll plow the land, change it’s state and image. The cash is taken out of the player’s pockets and we update the money status, for which we need to add the following in farming.js, right after the moneyLabel definition:

//updating money indicator
gameObj.updateMoney = function() {
    moneyLabel.setText('$'+playerObj.money);
};

You should now be able to plow land and spend money:

;

Shop

Ok plowing land can be fun, but to really make it as a farmer you need to buy seeds and grow your stuff. Lets start by putting all the crops in our game object. Add the following in farming.js after the player object definition. See how you can easily change the parameters and tweak it however you want.

gameObj.crops = [
    {
        name: 'tomato',
        cost: 10,
        revenue: 18,
        time_to_ripe: 10, //secods
        time_to_death: 30, //second from when it's ripe
        image: 'tomato.png'
    },
    {
        name: 'artichoke',
        cost: 20,
        revenue: 38,
        time_to_ripe: 60,
        time_to_death: 60,
        image: 'artichoke.png'
    },
    {
        name: 'lettuce',
        cost: 15,
        revenue: 26,
        time_to_ripe: 30,
        time_to_death: 60,
        image: 'lettuce.png'
    },
    {
        name: 'eggplant',
        cost: 30,
        revenue: 78,
        time_to_ripe: 120,
        time_to_death: 120,
        image: 'eggplant.png'
    },
    {
        name: 'peppers',
        cost: 40,
        revenue: 82,
        time_to_ripe: 180,
        time_to_death: 180,
        image: 'peppers.png'
    }
];

Each type of crop has then a name, a cost, a revenue that brings in when harvested, the time it takes it to be ready (in seconds), the time it takes it to die after it is ripe (in second), and an image file.

We’ll implement the shop as a new “scene” (think of the analogy of movie scenes). Add the following after the director.replace(…) part:

//shop
var shopScene = new lime.Scene().setRenderer(lime.Renderer.CANVAS);
var shopLayer = new lime.Layer().setAnchorPoint(0, 0);

var shopBackground = new lime.Sprite().setAnchorPoint(0,0).setPosition(0,0)
    .setSize(gameObj.width, gameObj.height).setFill('#0D0D0D');
shopLayer.appendChild(shopBackground);
shopScene.appendChild(shopLayer);

//close button
var closeButton = new lime.GlossyButton().setColor('#133242').setText('Back')
    .setPosition(gameObj.width/2, gameObj.height-25)
    .setSize(80, 40);
shopLayer.appendChild(closeButton);

//launch shop event
goog.events.listen(shopButton,['mousedown', 'touchstart'], function(e) {
    director.replaceScene(shopScene);
});

//close shop event
goog.events.listen(closeButton,['mousedown', 'touchstart'], function(e) {
    director.replaceScene(gameScene);
});

This creates a new scene for the shop, links our “Shop” button to the opening of this new scene. It also adds a “Close” button to the shop. You should now be able to open and close and empty shop.

The following code (which goes right after what we just added) will display the crops in our shop, and allow the player to pick one (that will be stored as a property of the player).

//shop items
for(var i=0; i<gameObj.crops.length; i++) {
    var item = new lime.Sprite().setAnchorPoint(0,0).setPosition(gameObj.shop_margin_x, gameObj.shop_margin_y + (gameObj.shop_margin_y + gameObj.tile_size)*i)
        .setFill('images/'+gameObj.crops[i].image).setSize(gameObj.tile_size, gameObj.tile_size);
    shopLayer.appendChild(item);

    var timeLabel = new lime.Label().setText(gameObj.crops[i].name+' ('+gameObj.crops[i].time_to_ripe+' days)').setFontColor('#E8FC08')
    .setPosition(gameObj.shop_margin_x+150, gameObj.shop_margin_y*1.5 + (gameObj.shop_margin_y + gameObj.tile_size)*i);
    shopLayer.appendChild(timeLabel);
    var costLabel = new lime.Label().setText('cost: $'+gameObj.crops[i].cost).setFontColor('#E8FC08')
    .setPosition(gameObj.shop_margin_x+150, gameObj.shop_margin_y*2.5 + (gameObj.shop_margin_y + gameObj.tile_size)*i);
    shopLayer.appendChild(costLabel);
    var label = new lime.Label().setText('revenue: $'+gameObj.crops[i].revenue).setFontColor('#E8FC08')
    .setPosition(gameObj.shop_margin_x+150, gameObj.shop_margin_y*3.4 + (gameObj.shop_margin_y + gameObj.tile_size)*i);
    shopLayer.appendChild(label);

    //pick crop
    (function(item, i) {
        goog.events.listen(item,['mousedown', 'touchstart'], function(e) {
            playerObj.currentCrop = i;
            director.replaceScene(gameScene);
        });
    })(item, i);
}

The only complicated part of the code above is the use of a closure (the function inside the brackets). This is a Javascript pattern that allows us to attach events inside a loop without the change of “i” affecting the event callback of the previous elements. You should now be able to open the shop and pick a crop by clicking on it’s image. See how we are calling “days” what in reality is just seconds.

Planting

Now that we’ve picked a crop, it’s time to plant it. Lets go back to land.js and add the following statement to the event listener that we use for plowing:

else if(land.state == land.PLOWED && playerObj.money >= gameObj.crops[playerObj.currentCrop].cost) {
        //plant
        land.setFill('images/growing.png');
        land.state = land.GROWING;

        //store crop and left time for it to be ready and to die
        land.crop = playerObj.currentCrop;
        land.ripeTime = gameObj.crops[playerObj.currentCrop].time_to_ripe * 1000;
        land.deathTime = gameObj.crops[playerObj.currentCrop].time_to_death * 1000;

        //update player money
        playerObj.money -= gameObj.crops[playerObj.currentCrop].cost;
        gameObj.updateMoney();
    }

We are checking that the land has been plowed and the player has enough cash. If so, we are planting our seeds, changing the state of the land element, storing the relevant times (in milliseconds) and updating the money. You can start plating now!

Plants growth and death

Each crop has their own time to maturity and time to death. We want to check that and replace the images and states of the land elements when these times are reached. When the crop is ready for harvest, we want it’s image to be that of the crop. When a crop dies, the land is set back to empty.

LimeJS comes with a scheduler helper that allows us to check for events every X number of milliseconds. The following code will take care of the growth and death of the plants, add it after the event listener in land.js.

//growing plants
dt = 1000;
lime.scheduleManager.scheduleWithDelay(function() {
    if(this.state == land.GROWING) {            
        if(this.ripeTime <= 0) {
            this.state = land.READY;
            this.setFill('images/'+gameObj.crops[this.crop].image);
        }
        else {
            this.ripeTime -= dt;
        }
    }
    else if(this.state == land.READY) {
        if(this.deathTime <= 0) {
            this.state = land.EMPTY;
            this.setFill('images/bare_land.png');
        }
        else {
            this.deathTime -= dt;
        }
    }
}, this, dt);

You are now able to plant.. but you can’t harvest yet.

Harvest

Adding the harvesting part is very easy 🙂 just add the following the our event listener in land.js:

else if(land.state == land.READY ) {
        //harvest
        land.setFill('images/bare_land.png');
        land.state = land.EMPTY;

        //update player money
        playerObj.money += gameObj.crops[land.crop].revenue;
        gameObj.updateMoney();
    }

The complete game

You can download the complete game from the here.

What’ next

I hope you’ve enjoyed making this simple farming game. Things that can be added to expand it further are progress saving, for which you can use something as simple as local storage, and of course social integration, so that you can share your farm on Facebook or Twitter.

I would like to encourage you to keep on learning HTML5 game development and to check out my game dev courses, which are designed for beginners and will save you hours of learning on your own.

HTML5 Mobile Game Development for Beginners

I’ve prepared a comprehensive online course which will guide you through the creation of HTML5 crossplatform games using LimeJS game development framework. The course is 100% video based so that you can see in real time how games are created from scratch. Each lesson comes with its own zip file with all the code so that you can have a play with the examples and used them as starters for your own games.

A lot of extra topics are covered in this course, such as adding animations, sound, 2D physics, using tile-based maps, and transforming your HTML5 game into a native app so you can make money with it.

]]>
Create a Mobile HTML5 RPG for Beginners https://gamedevacademy.org/create-a-mobile-html5-rpg-for-beginners/ Fri, 31 May 2013 22:08:40 +0000 https://gamedevacademy.org/?p=291 Read more]]> Intro

In this tutorial, I’ll show you how to create a (very) simple RPG demo that works in all HTML5 supporting platforms, using the Open Source Javascript framework LimeJS.

This framework allows you to quickly create simple games that work regardless of the screen resolution of your device (laptop, phone, tv). You can play these games through HTML5 supporting web browsers, or you can turn them into native mobile apps using Titanium or Phonegapp, and submit them to the various “app stores” out there.

RPG Games

What is the most important aspect of an RPG game? I’m sure each one will have their own opinion on this. Some might say the characters, their sometimes erratic evolution and deceptive plots. Some others might say exploring huge bizarre worlds. Or perhaps fighting weird creatures created by some tripping mind for our enjoyment. No matter the answer to this question, I think we can all agree that the following elements are no less than important:

  • World
  • Characters
  • Monsters
  • Story

We will thus cover these items, except for the “Story” one, as it’s really up to you to come up with something exciting.

Tutorial requirements

  • Basic HTML and Javascript knowledge
  • Basic notions of Object Oriented programming
  • A text editor or IDE to create and edit code
  • Some love for RPG games!

LimeJS

We’ll be using an awesome HTML5 game dev framework called LimeJS. This framework makes it easy to get started making your own games, as it comes with good support for aspects such as rendering images, user interaction for touch and non-touch screens, and many other game dev aspects (animations, 2D physics, etc). Moreover, LimeJS has a great and open community.

In this tutorial we will not go very deeply into installing the framework or using all of it’s power. You can get the installation instructions from the official guide here.

If you want a more detailed explanation of the installation process, I have created a full chapter on how to install the framework for Windows, Mac and Ubuntu in my video-based course [HTML5 Mobile Game Development for Beginners, where you can also learn a lot more about how to create games with this framework. I’ll talk more about this course at the end of this tutorial.

Installation Overview

  • Install Python
  • Install GIT
  • Install SVN
  • Download the ZIP file from www.limejs.com or clone their Github repo
  • Rename the folder we have downloaded as “limejs”, I will be refering to it with that name in this tutorial
  • Go into the limejs folder using your terminal. Type:bin/lime.py init

(this will download a bunch of dependencies) If you run into trouble installing LimeJS, the community is another excellent place to look for help and OS-specific guides.

Creating a new project

Once LimeJS has been installed, we can create a new project by going to our limejs folder using the terminal and typing:

bin/lime.py create rpg_tutorial

This will create a folder called “rpg_tutorial” in the limejs folder. That is where all of our files will reside.

Keep in mind that if you move this folder anywhere else, the game will not run. This is because while we are developing, our project will need the libraries in our limejs folder. Once we are finished with a project, you need to “compile” it, and the resulting JS files you can put anywhere you want.

Game World

We’ll start by creating our world, which is an image made with this tileset. The tileset has been created by Sharm and released with the licence CC By 3.0, which means we are free to use this for any purpose we want as long as we keep this notice and give attribution to Sharm (thank you Sharm, whoever you are!).

The game will have a resolution of 352×256. The game map has that same resolution (we won’t do scrolling in this tutorial). You can download the game map image from this link and copy it to your “rpg_tutorial” folder.

Let’s do some coding. Open the file rpg_tutorial.js, delete all of it’s contents (which is a sample game project, it’s worth checking out to get an intro to the framework) and copy the following:

//set main namespace 
goog.provide('rpg_tutorial');   
//get requirements 
goog.require('lime.Director'); 
goog.require('lime.Scene'); 
goog.require('lime.Layer');   

    //entrypoint 
    rpg_tutorial.start = function(){          
    var director = new lime.Director(document.body,352,256);     
    director.makeMobileWebAppCapable();     
    director.setDisplayFPS(false);          
    var mapScene = new lime.Scene();              
    director.replaceScene(mapScene); 
}

What I’ve entered there is pretty much a basic skeleton for a new project. For a good introduction to all these elements there is the official guide.

Mainly, what is happening here is:

  • We are telling the rest of the project that the namespace of the objects declared here is “rpg_tutorial”. A namespace is a unique identifier which helps you distinguish the objects in this file from objects that could have the same name in other files (imagine you create a “Circle”, there is already a “Circle” object in the framework, but they would not be confused as yours would be “your_namespace.Circle”, whereas the one that comes with the framework is called “limejs.Circle”).
  • Some objects are being imported so that they can be used here.
  • We declare the “director”, which is the object that does pretty much the same roles as a movie director: define main aspects, tell the game which scene we are playing now, etc
  • Create the current scene, which is where the action happens.

So far this doesn’t do anything, so let’s show our map after the scene has been declared:

var mapScene = new lime.Scene();
var mapLayer = new lime.Layer().setPosition(0,0).setRenderer(lime.Renderer.CANVAS).setAnchorPoint(0,0);

var gameMap = new lime.Sprite().setSize(352,256).setFill('map.png').setPosition(0,0).setAnchorPoint(0,0);

mapLayer.appendChild(gameMap);
mapScene.appendChild(mapLayer);

Now open the file rpg_tutorial.html in your web browser, you should be seeing the game map image. What we are doing here is creating a new Sprite object, which can be an image or just a rectangle with some filling (colours, gradients). An anchor point of (0,0) means that we’ll use the top left corner of the image to set it’s position (coordinates go from the top left corner of things in this framework, and with working with the Canvas in general). Position (0,0) means we are setting the image’s anchor point to the top left corner of the scene. Basically, the image will cover the entire screen.

Notice how if you resize the browser window, the image will resize as well. Cool stuff. What I usually do as well is giving the “body” tag in the HTML file the colour black using CSS, that’s just my preference here.

The “layer” that we created is an invisible container where we put the elements. A layer itself can be animated, moved, resized, etc. We are using the Canvas on this layer, as opposed to using the DOM.

Hero

What would it be of RPGs without a hero? Who will then endure the vicissitudes of a decadent world full of monsters? Well, let’s create it then. What we’ll do is create a hero and have him move to wherever we click or touch on the map, how does that sound?

We will use another Sprite object to represent the hero (I encourage you to create custom objects for each game entity). The image file we’ll use is labelled a public domain and can be downloaded here. Copy it to your rpg_tutorial folder.

The code of the rpg_tutorial.start object will now be:

rpg_tutorial.start = function(){          
    var director = new lime.Director(document.body,352,256);     
    director.makeMobileWebAppCapable();     
    director.setDisplayFPS(false);          
    var mapScene = new lime.Scene();
    var mapLayer = new lime.Layer().setPosition(0,0).setRenderer(lime.Renderer.CANVAS).setAnchorPoint(0,0);

    var gameMap = new lime.Sprite().setSize(352,256).setFill('map.png').setPosition(0,0).setAnchorPoint(0,0);
    var hero = new lime.Sprite().setSize(40,36).setFill('hero.png').setPosition(100,100);          
    mapLayer.appendChild(gameMap);     
    mapLayer.appendChild(hero);
    mapScene.appendChild(mapLayer);
    director.replaceScene(mapScene); 
}

We want the hero to move to where we click or touch, for which we need to bind the “click” and “touch” event in our map, so that the hero moves wherever the user clicked (or touched). This is done in LimeJS with the following code, which we’ll add after our hero definition:

goog.events.listen(gameMap, ['mousedown','touchstart'], function(e) {         
    var movement = new lime.animation.MoveTo(e.position.x,e.position.y).setDuration(1);        
    hero.runAction(movement);     
});

Some comments:

  • By using goog.events.listen we bind a game object (in this case the map) with events, in this case pressing the mouse or touching the screen.
  • We create a new “animation” which is a movement to the target coordinates, which will take 1 second to complete.
  • The animation is applied on the hero.

Ideally, one should create separate files for each game object. We will do that in a bit, but for the sake of simplicity and length I will leave it up to you to organise the code better. The next thing we’ll do to our character is giving it some characteristics:

hero.life = 20; 
hero.money = 100; 
hero.attack = 5;

Monsters

Time for evilness to appear. Let’s create a monster and put in on the map. The image file is a public domain one and you can get it here. After hour hero definition let’s add the monster sprite and give it some properties:

var monster = new lime.Sprite().setSize(40,36).setFill('monster.png').setPosition(200,200);
monster.life = 15;
monster.money = 10;
monster.attack = 1;
    mapScene.appendChild(monster);

Let’s make it so that if the user touches the monster, we’ll be taken to a “fight scene”. It’s not gonna be as elaborated as you expect, but it can be used as a ground for your own further enhancements. Let’s first create the fight scene. We need to include the LinearGradient file to fill out our sky with a linear colour transition:

goog.require('lime.fill.LinearGradient');

After the monster definition add the following code to show the fighting scene with our hero and monster (again, your homework here is to make this code modular, etc):

var fightScene = new lime.Scene().setRenderer();    
var fightLayer = new lime.Layer().setPosition(0,0).setRenderer(lime.Renderer.CANVAS).setAnchorPoint(0,0);
var sky_gradient = new lime.fill.LinearGradient().setDirection(0,0,1,1)
    .addColorStop(0,'#B2DFEE').addColorStop(1, '#0000CD');
var sky = new lime.Sprite().setSize(352,128).setPosition(0,0).setAnchorPoint(0,0).setFill(sky_gradient);
var grass = new lime.Sprite().setSize(352,128).setPosition(0,128).setAnchorPoint(0,0).setFill('rgb(0,125,0)');
fightLayer.appendChild(sky);
fightLayer.appendChild(grass);

//show the images of the monster and hero
var fighterOne = new lime.Sprite().setSize(hero.getSize()).setFill(hero.getFill()).setPosition(50,210);
var fighterTwo = new lime.Sprite().setSize(monster.getSize()).setFill(monster.getFill()).setPosition(280,210);

fightLayer.appendChild(fighterOne);
fightLayer.appendChild(fighterTwo);
fightScene.appendChild(fightLayer);

We can check how it’s looking by having the Director putting it in place using replaceScene as we did earlier with “mapScene”.

Ok! let’s add now collision detection so that if our brave hero touches the monster, the fighting scene comes into play. Include this file, which contains the Google Closure library math methods:

goog.require('goog.math');

Then add this code after the fight scene definition:

hero.inFightScene = false;

lime.scheduleManager.schedule(function(dt) {
    if(!this.inFightScene) {            
        if(goog.math.Box.intersects(this.getBoundingBox(),monster.getBoundingBox())) {
            director.replaceScene(fightScene);
            fightLayer.setDirty(255)
            hero.inFightScene = true;
        }
    }
}, hero);

There is a lot happening here guys!

  • We are using the scheduleManager, which will be executed periodically. The parameter dt contains the elapsed time between iterations.
  • If the player is not already in the fighting scene, we are using Closure Library’s “Box” object to check for collision between the boxes of both characters (see how the bounding box of each is extracted).
  • If the characters are indeed colliding, replace the scene.
  • The setDirty() method is just a workaround for a framework bug when replacing between Canvas scenes.

All ready! We have a pretty fancy fight scene in place, but what about the fighting itself? Well, you can create your own fighting algorithms involving all sorts of player choices, character attributes, items, etc. There is a lot of material online about RPG fights that you can use as inspiration. What I’ll do now is make up a really simple fighting algorithm, which will be basically tossing a random number and taking the “attack” attribute out of the enemy’s life attribute. But before that, let’s show the characters’ attributes in our fight scene, and add some fighting options.

Let’s include this file to create simple buttons:

goog.require('lime.GlossyButton');

The fight scene definition will look like this:

var fightScene = new lime.Scene().setRenderer();    
var fightLayer = new lime.Layer().setPosition(0,0).setRenderer(lime.Renderer.CANVAS).setAnchorPoint(0,0);

var sky_gradient = new lime.fill.LinearGradient().setDirection(0,0,1,1)
    .addColorStop(0,'#B2DFEE').addColorStop(1, '#0000CD');

var sky = new lime.Sprite().setSize(352,128).setPosition(0,0).setAnchorPoint(0,0).setFill(sky_gradient);

var grass = new lime.Sprite().setSize(352,128).setPosition(0,128).setAnchorPoint(0,0).setFill('rgb(0,125,0)');

fightLayer.appendChild(sky);
fightLayer.appendChild(grass);

//show the images of the monster and hero
var fighterOne = new lime.Sprite().setSize(hero.getSize()).setFill(hero.getFill()).setPosition(50,210);
var fighterTwo = new lime.Sprite().setSize(monster.getSize()).setFill(monster.getFill()).setPosition(280,210);

//labels with characters stats
var labelFighterOneLife = new lime.Label().setText('Life:'+hero.life).setPosition(50,150);
var labelFighterOneAttack = new lime.Label().setText('Attack:'+hero.attack).setPosition(50,170);

var labelFighterTwoLife = new lime.Label().setText('Life:'+monster.life).setPosition(280,150);
var labelFighterTwoAttack = new lime.Label().setText('Attack:'+monster.attack).setPosition(280,170);

//some options
var attackButton = new lime.GlossyButton().setSize(70,20).setPosition(40,10)
    .setText('Attack').setColor('#B0171F'); 

var runButton = new lime.GlossyButton().setSize(70,20).setPosition(120,10)
    .setText('Run').setColor('#00CD00'); 

fightLayer.appendChild(fighterOne);
fightLayer.appendChild(fighterTwo);

fightLayer.appendChild(labelFighterOneLife);
fightLayer.appendChild(labelFighterOneAttack);
fightLayer.appendChild(labelFighterTwoLife);
fightLayer.appendChild(labelFighterTwoAttack);

fightLayer.appendChild(attackButton);
fightLayer.appendChild(runButton);

fightScene.appendChild(fightLayer);

Let’s implement the “Run” behavior by binding the button “click” or “touch” with going back to the map scene. Add the following after the fight scene definition.

//run away, coward
goog.events.listen(runButton, ['mousedown','touchstart'], function(e) {
    //go back to the map
    director.replaceScene(mapScene);
    mapLayer.setDirty(255)

    //move the hero away from the monster, or the fight scene will be triggered again!
    //this is just a quick, non-elegant way of doing this
    currentPos = hero.getPosition();
    hero.setPosition(currentPos.x-60, currentPos.y-60);

    hero.inFightScene = false;

});

Righto. We have a brave hero who can get into fights and run away from them. Sweet.

Now let’s man up a bit and get into the fighting itself with this ugly, vicious creature/monster/evil king once and for all. The simple fighting algorithm will work as follows:

  1. Generate a random number, if it’s < 0.5, the player hits, otherwise the monster hits.
  2. When a character hits the other character, the attacker’s “attack” attribute will be subtracted from the opponent’s “life” attribute.
  3. If a character’s “life” attribute reaches zero.. he is then ready to be buried.

We’ll implement this by binding the attack button to the “click” and “touch” events, and by running this simple fighting algorithm when any of those events are triggered. As I’ve mentioned earlier, you are very welcome to transform this code into something modular and scalable, and if you do so and want to share it with the world just let me know and I’ll add it to the tutorial, or you can also do it through the Github repo.

//fighting algorithm
goog.events.listen(attackButton, ['mousedown','touchstart'], function(e) {

    //generate random number
    var randomStuff = Math.random();

    //the player hits!
    if(randomStuff < 0.5) {
        monster.life -= hero.attack;

        //is he dead yet?
        if(monster.life <= 0) {
            console.log('monster dead');
            //get the monster money
            hero.money += monster.money;

            //go back to the map
            director.replaceScene(mapScene);
            mapLayer.setDirty(255);
            hero.inFightScene = false;

            //delete the monster object
            monster.setHidden(true);
            delete monster;
        }
    }
    else {
        hero.life -= monster.attack;

        //have you been killed?
        if(hero.life <= 0) {
            var labelGameOver = new lime.Label().setText('GAME OVER!!!').setPosition(160,100);
            fightLayer.appendChild(labelGameOver);
        }
    }

    //update stats
    labelFighterOneLife.setText('Life:'+hero.life);
    labelFighterTwoLife.setText('Life:'+monster.life);
});

Key points here:

  • We are listening to “click” and “touch” events on the attack button using the same technique we’ve used earlier.
  • A random number decides who “hits”. Instead of being 50% each, you could make this dependent of the character’s agility or experience.
  • If the monster is dead, we are taking their money ($$$) and killing the object.
  • It a pretty unfair fight, as we are way stronger than the monster. If you happen to die I added a “game over” text to show up. Now that you know how to work with scenes, you could go to a game over scene.

To prevent the fight scene to be loaded again from the bounding box of the monster, change the line where we checked for collision detection, for this one, so that only alive monsters trigger this:

if(monster.life >0 && goog.math.Box.intersects(this.getBoundingBox(),monster.getBoundingBox())) {

Time to Play and Download

You can download the complete game files from this link. As I mentioned earlier, running these files outside the limejs folder is not gonna work. In order to deploy a LimeJS project you have to follow this guide.

What’s Next

After doing this tutorial you are all good to get started with this awesome framework. The first thing I reckon you should look into is on making this more modular, for instance putting each game object in a separate file, and add some methods so that you are not repeating the code. Also, the fighting scene display and fight algorithm should be made generic to “any” monster instead of having one monster hard coded. Getting you into Game Dev was my goal here, not teaching OOP design patterns (there are plenty of tutorials for that out there!).

Now where should you go next? I have an idea.

HTML5 Mobile Game Development for Beginners

I’ve prepared a comprehensive online course which will guide you through the creation of HTML5 crossplatform games using LimeJS game development framework. The course is 100% video based so that you can see in real time how games are created from scratch. Each lesson comes with its own zip file with all the code so that you can have a play with the examples and used them as starters for your own games.

]]>