Part 1 »
Part 2 »
Part 3 »
Part 4 »
Part 5 »
Part 6 »
Part 7 // End)

Today we will deal with the coordinate system that is used in Cocos2d-JS and talk about how to move game objects on the screen.

Coordinate system
In Cocos2d-JS, the position of objects in the game space is determined by the coordinate system. Each node in the engine has x and y coordinates that determine its position. It uses the right
rectangular coordinate system , exactly the same that is learned in the classroom in mathematics.
')
Coordinate systemThe size of the visible area
The maximum coordinates along the x and y axes are determined by the size of the visible area. Cocos2d-JS provides an object called “view”, or “view”, which supports various resolutions and screen sizes.
Here is a line of code from main.js that sets the size of the visible area.
cc.view.setDesignResolutionSize(480, 800, cc.ResolutionPolicy.SHOW_ALL);
The first argument of the called method is the width, the second is the height. In our case, the native resolution of the visible area is 480x800. The third argument sets the rules for changing the size of the game space when the program runs on a device whose screen has a resolution and aspect ratio that differ from the specified parameters.
The engine provides five ways to solve the problem of inconsistency of the screen characteristics with the parameters specified in the program. Their descriptions can be found in the main.js file, above the line of code that we just looked at. We will use the default, SHOW_ALL. With this approach, the aspect ratio of the visible area will remain on any display, while the unoccupied image of the screen will be painted over in black - black stripes will appear on the sides of the playing field.
Coordinate space
Each node has its own internal space of coordinates. Both the window and each of the nodes have a coordinate system, the origin of which is located in the lower left corner of the rectangle bounding the object.
The origin of the window and game objectSpecifying the position of the node, we set its place in the coordinate space of the parent object. For example, specifying the position for the red point (treats for the snake) shown in the figure above, you force it to move within the coordinate system of the layer (axes drawn with black lines), and not within its own coordinate space (yellow axis).
We take out the snake from the corner
Now that we’ve dealt with the coordinate system, we can pull the snake’s head out of a corner and place it in a more decent place. Namely, in our version of the game Snake, everything will start in the center of the screen.
Update the SnakeLayer layer code as shown below. A new code should be added below the comment “Add code below”.
var SnakeLayer = cc.Layer.extend({ snakeHead: null ctor: function () { // var winSize = cc.view.getDesignResolutionSize(); this._super(); this.snakeHead = new SnakePart(asset.SnakeHead_png); // this.snakeHead.x = winSize.width / 2; this.snakeHead.y = winSize.height / 2; this.addChild(this.snakeHead); }, });
The variable winSize is an object that contains the size of the window — its width and height. Using this data, we assign a position to the snake head, the x coordinate of which is equal to half the width of the window, and the y coordinate to half the height.
Now let's run what happened in the emulator.
The head of the snake moved to the center of the screen.Teach the snake to move.
Moving objects
After we figured out the coordinate system, it’s obvious that to move a node on the screen, you need to change its x and y coordinates. Let's do it.
In order for the snake to move, add the following method to the SnakeLayer layer code.
moveSnake: function(dir) { /* , */ var up = 1, down = -1, left = -2, right = 2, step = 20; /* snakeHead */ var snakeHead = this.snakeHead; /* */ var dirMap = {}; dirMap[up] = function() {snakeHead.move(snakeHead.x, snakeHead.y + step);}; dirMap[down] = function() {snakeHead.move(snakeHead.x, snakeHead.y - step);}; dirMap[left] = function() {snakeHead.move(snakeHead.x - step, snakeHead.y);}; dirMap[right] = function() {snakeHead.move(snakeHead.x + step, snakeHead.y);}; /* */ if (dirMap[dir] !== undefined) { dirMap[dir](); } },
This method deals with the fact that it moves a snake's head with a constant, hard-coded, step (step variable) whenever it is called. As a step, we chose 20, since this value completely divides both the width and height of the game screen. To indicate the direction of movement, we use numbers that specify the necessary changes in the coordinates of objects. Now this method must somehow be called.
Game cycle
In the game engine there is an infinite loop that solves the following tasks: processing input events without blocking the program, executing game logic, displaying graphics. Each pass of a cycle is called a “tick” or “tick”. It can be compared with a regularly triggered timer.
If you describe the structure of the game cycle in pseudocode, you get the following:
while (true) { processInput(); runGameLogic(); renderGame(); }
When the engine is engaged in the execution of the game logic, it passes through the list of game objects, executes the code and updates their state. For example, if the game has a character that falls from the sky, the game will need to update its position every time, based on a given algorithm. Add a SnakeLayer layer to the Cocos2d-JS update list.
Add the update method to the SnakeLayer code and call the scheduleUpdate method in the ctor method. The rest of the code in the listing is provided to help navigate.
var SnakeLayer = cc.Layer.extend({ snakeHead: null, ctor: function () { ... this.scheduleUpdate(); }, moveSnake: function(dir) { ... }, update: function() { var up = 1; this.moveSnake(up); }, });
Now, every time after creating an object, the update method will be called at each clock cycle of the game. If you run the project now in the emulator, the snake's head, like a rocket, will fly over the upper edge of the screen.
Movement speed limit
The snake now flies away from the screen instantly, although each call to the moveSnake method moves it only one step. This is because the game loop executes very quickly. Unlike the primitive scheme of such a cycle, which we cited above, a real game cycle tracks the time between measures. We can use this fact to ensure that the method of updating the position of an object works at the desired speed. Here's how to do it.
- Add two new class members — interval and counter.
var SnakeLayer = cc.Layer.extend({ snakeHead: null, // interval: 0.25, /* 1/4 */ counter: this.interval, ctor: function () {...}, moveSnake: function(dir) {...}, update: function(dt) {...}, });
- Replace the update method code with the one below.
update: function(dt) { var up = 1; if (this.counter < this.interval) { this.counter += dt; } else { this.counter = 0; this.moveSnake(up); } },
The update method now has the argument “dt” (delta time, time change). This is the time in seconds after the last frame. This argument passes the game loop to this method. We have created two new class members: interval and counter. Interval sets the number of seconds that must elapse between update () calls. Counter (counter) is needed to calculate the number of seconds elapsed since the object was previously moved. In this case, the counter accumulates data from the game cycle, available in the argument of the dt method.
Now, if you start the game in the emulator, the snake will move much slower.
findings
Let's sum up the today's occupation:
- Cocos2d-JS uses the right coordinate system.
- There is such a thing as the own size of the visible area.
- Nodes are positioned in the coordinate space of parent objects.
- The game engine has an infinite loop that updates the logic of the game.
- One pass of the game cycle is called " tact" or "tick" (tick) .
Now you can do the following:
- Position game objects in the desired position of the screen.
- Move objects around the screen.
Next time we will increase the length of the snake and make its movements more meaningful.
Part 1 »
Part 2 »
Part 3 »
Part 4 »
Part 5 »
Part 6 »
Part 7 // End)
