We chose a classical game development approach for making this game; we are going to have a game timer that ticks several times a second and all the magic happens during each tick.
In our implementation the GameTimer class has an array of MovingObjects. In each tick the timer calls move() method of each MovingObject. The move method updates the position of the object and draws it on the screen.
GameTimer
GameTimer is a singleton object.
The most important methods of GameTimer are:
- start()
- stop()
- pause()
- addMovingObject(movingObject)
- funcs: an array of callback functions. These functions will be called at each tick.
- frequency: in miliseconds
- tick(): private
Current implementations of JavaScript in browsers don't support threading and parallel programming. It means that all the time that it takes for exestuation of the callback functions that run at each tick must be less than the frequency of the timer; otherwise the user will experience freezing and delays.
ViewPort
A game may have many view ports. Each view port has its own set of MovingObjects. The game can have one active view port at a time. All visual objects must belong to the active ViewPort to be rendered on the screen. This game has only one view port.
The ViewPort object has these members:
- size: this width and height of the view port
- jq: a reference to the jQuery object of the parent HTML element of the view port (all visual objects in the ViewPort must be child elements of it)
- addMovingObject(movingObject)
- And some attributes related only to this game like sea level.
MovingObject
- position: the x, y position of the object, relative to its view port.
- size: the width and the height of the object.
- v: the instant velocity of the object relative to its view port.
- jq: a reference to the object's jQuery object (visual representation of the object).
- t: time (automatically assigned by GameTimer).
- getRect(): returns a Rect object describing the surrounding rectangle of the visual object.
- contains(x, y): finds whether point x, y is inside the object (x and y are relative to the object's view port. It will be used for a simple collision detection.)
- _updatePosition(): it is virtual method, by default it adds the instant velocity to the position of the object on each tick. We override this method in child classes to control the motion of the objects.
- move(): moves the object to its current position.
- _onMoved(): it will be called after the object is rendered in the screen at its current position.
Boat, Fish and Rod inherit from MovingObject.
In this game the player has to catch fishes using a fishing rod. The length of the thread of the rod increases as long as the left mouse click in down (so the player can catch fishes in deeper positions). It begins to retract as soon as the user releases the left button. Its length changes between a minimum and maximum value. You can think of many mathematical functions to control the length of the thread. The range of the function should be between min and max of the thread. We chose a simple trigonometry function, arc tangent. The change of the return value of arc tangent function slows down as its argument grows to bigger numbers.
Arctangent function
We attach a time property to rod. Rod time changes between 0 and 5 and its length changes between 0 and a coefficient of 7π/16. arctan(0) = 0 and arctan(5) = 7π/16.
User Input Handlers
GameControlsState class contains all the data about the current state of controls: the location of the mouse, the buttons that have been pressed but not yet released, etc. Event handlers change the state of this object. Later at each tick, each callback function checks if its controls have been triggered or not.
For example _updatePosition() method of Boat looks like this:
_updatePosition : function() {
if(GameControlsState.keyBoard.left) {
this.position.x -= 5;
}
if(GameControlsState.keyBoard.right) {
this.position.x += 5;
}
}
It means that at each tick of GameTimer, the boat moves 5 pixel to the left if left arrow key is down. Because tick is called 30 times a second, the small delays between each tick is unnoticeable for a player. Unfortunately JavaScript doesn’t support multithreading. You have to limit the amount of computation in each tick. User feels the delays if the computation takes more than 30 milliseconds.
Depending on your game you may want to choose a different event handling pattern.
Fish
The Fish object inherits from the MovingObject therefore all we need to make it behave like a fish is to define few more properties and a custom moving function by overriding "_updatePosition" function, Fish has the following attributes:
- isTrash: if true, it means that the object is a trash (trashes have no use for the player, we will talk about the difference between Fish and Trash and the need for trash objects in a later chapter)
- movingDirection: the direction in which the fish moves, it can be from right to left "rtl" or left to right "ltr".
- mouth: the mouth is a rectangle that defines the mouth area of the fish in which the fish can be caught.
- isHooking(x,y): this function takes the hook's coordinates and finds whether the hook is inside the fish's mouth.
- hook(): once the rod hooks the fish, it calls this function. This way the act of hooking will be controlled by the rod not the fish. After this call the fish can do any necessary action like performing a fishing animation.
- switchImageToVertical(): it is a private function. To make a better fishing animation, we rotate the fish image vertical direction as it is being dragged by the rod's hook. The function creates this animation using spriteAnimation jQuery plugin.
Two kinds of sprite animations we use for a fish: swimming and fishing. Note that the fish rotates around an axis that is located at its mouth.
Fishing Rod
Another important object in our fishing game is the rod that the player will use to catch the fishes. The hook is a part of the rod object and it is responsible for catching the fishes. The hook is a property of the rod which moves down and up. While the hook is moving we continuously check if the hook intersects with any fish by calling the fish's "isHooking()" function. This way the act of fishing will be controlled by the rod.
The rod goes through three main phases: moving down and up looking for fish, catching a fish and going back to the boat (retracting) with a fish.
By overriding the "_onMoved()" function of the movingObject class inside the rod, we can check for fishing events:
- When the rod is fully retracted and has a fish: it means that we should add the fish to the players bucket and do all the related events Like (increasing score, removing the fish from the ViewPort, …). This state is particularly important for Hyzonia advergames, this is where the player makes a progress in this game. All Hyzonia games must work with a type of Hyzonia Quest. From a very abstract point of view Hyzonia expects players continuously progress in the Quests and win them. We will discuss it in details in chapter 5.
- When the hook of the rod intersects with a fish: we fires the hooking events.
Config
If you look at the code you will notice that in several places we use Config object. Config represents the static configuration of the game and is a singleton name value collection in JSON format. The attributes of this object will be customizable. This is a common feature in all Hyzonia games. We talk about customization in details in a later chapter, for now we just describe the most important attribute of Config in this game:
- LIST_OF_FISHES: An array that defines the types of fishes the game has. Each element of the array is a fish data object that has the following properties:
- isTrash
- size: the size of the fish image.
- movmentImage: the URL of the sprite animation of the fish in swimming state.
- imageUrl: the URL of the sprite animation of the fish in fishing (hooking) state.
- dir: swimming direction, "rtl" or "ltr".
- swimDepth: an array of numbers that represent the y positions in which the fish can appear in.
We place the "LIST_OF_FISHES" array in the Config file. Later this file can be exposed to Publishers to enable customization of the game (for example using LIST_OF_FISHES they can customize the picture of the fishes).
Here is the prototype of this game. You can
download the source code. We kept the code simple and clear. Therefore it lacks lots of small FX and fixes, but it's easy to follow the logics.
"GameTimer" and the "MovingObject" classes are very handy and can be used in implementing many kinds of games. Such these generic classes makes development of JavaScript based games easy and neat.
Here we also used our
"sprite animation" jQuery plugin to create the animations (swimming and fishing); this way the animation is separated from the other logic of the game.
In the next chapter we introduce Hyzonia Game Client Services. These services can be consumed by game clients to communicate with Hyzonia.