ผลต่างระหว่างรุ่นของ "Prg2/arcade4 flappy dot"

จาก Theory Wiki
ไปยังการนำทาง ไปยังการค้นหา
(Prg2/arcade3 flappy dot ถูกเปลี่ยนชื่อเป็น Prg2/arcade4 flappy dot)
แถว 25: แถว 25:
  
 
== The player and its movement ==
 
== The player and its movement ==
 +
 +
=== Create a new project, clean up, and set up a Git repository ===
 +
You should start by downloading the template and cleaning up the original Hello World app.  Follow the instruction from the [[01219245/cocos2d-js/Sprites#Getting_started|previous tutorial]].
 +
 +
{{กล่องสี|#eeeeff|
 +
'''If you use the full version of Cocos2d-JS or Cocos2d-x''', you should start by creating a new Cocos-JS project.
 +
 +
cocos new -l js --no-native ชื่อโปรเจ็ค
 +
 +
This will create an example HelloWorld project.  You should clean up the example by following instructions outlined in [[01219245/cocos2d-js/Sprites#Let.27s_clean_up_HelloWorld_and_start_with_our_empty_game|Tutorial 100]].
 +
}}
 +
 +
Then, create a git repository at the project directory.
 +
 +
{{gitcomment|Create your git repository.}}
 +
 +
=== Creating the sprite ===
 +
In this step, we shall create a sprite for the player, and show it in the middle of the screen.
 +
 +
Use a graphic editor to create an image for our player.  The image should be of size 40 pixels x 40 pixels.  Save the image as <tt>res/images/dot.png</tt> and try to make it look cute.
 +
 +
We shall create class <tt>Player</tt> as <tt>src/Player.js</tt>.
 +
 +
{{synfile|src/Player.js}}
 +
<syntaxhighlight lang="javascript">
 +
var Player = cc.Sprite.extend({
 +
    ctor: function() {
 +
        this._super();
 +
        this.initWithFile( 'res/images/dot.png' );
 +
    }
 +
});
 +
</syntaxhighlight>
 +
 +
We shall create the player in <tt>GameLayer.init</tt>.  To do so add these lines:
 +
 +
{{synfile|src/GameLayer.js}}
 +
<syntaxhighlight lang="javascript">
 +
        this.player = new Player();
 +
        this.player.setPosition( new cc.Point( screenWidth / 2, screenHeight / 2 ) );
 +
        this.addChild( this.player );
 +
        this.player.scheduleUpdate();
 +
</syntaxhighlight>
 +
 +
Note that we use constants <tt>screenWidth</tt> and <tt>screenHight</tt> (which are 800 and 600, respectively).  Don't forget to add this constant in <tt>main.js</tt>.
 +
 +
{{synfile|main.js}}
 +
<syntaxhighlight lang="javascript">
 +
 +
var screenWidth = 800;      // add these two constants
 +
var screenHeight = 600;      //
 +
 +
cc.game.onStart = function(){
 +
    cc.view.adjustViewPort(true);
 +
    cc.view.setDesignResolutionSize(screenWidth, screenHeight, cc.ResolutionPolicy.SHOW_ALL);    // use them here
 +
    // ...
 +
};
 +
cc.game.run();
 +
</syntaxhighlight>
 +
 +
Last step is to update configuration and resource files.
 +
 +
1. We need to add <tt>src/Player.js</tt> to the jsList in <tt>project.json</tt>.
 +
 +
{{synfile|project.json}}
 +
<syntaxhighlight lang="javascript">
 +
    // ...
 +
    "jsList" : [
 +
        "src/resource.js",
 +
        "src/GameLayer.js",
 +
        "src/Player.js"
 +
    ]
 +
    // ...
 +
</syntaxhighlight>
 +
 +
2. Since we are using resource <tt>res/images/dot.png</tt>, we should preload it (so that we do not have to see empty screen when we start our program).  Put the file name in <tt>src/resource.js</tt>  (See more in section '''Technicalities: preloading of resources''', later in this page.)
 +
 +
{{synfile|src/resource.js}}
 +
<syntaxhighlight lang="javascript">
 +
var res = {
 +
    dot_png: 'res/images/dot.png'
 +
};
 +
// ...
 +
</syntaxhighlight>
 +
 +
Try to refresh the game.  You should see your sprite in the middle of the screen.
 +
 +
{{gitcomment|Commit your work.}}
 +
 +
=== Review of physics ===
 +
You might forget all these, but if you want objects in your game to look and act a bit like real objects, you might have to recall stuffs you learned from mechanics.
 +
 +
Let's look at the basics.  An object has a position, its position changes if it has non-zero velocity.
 +
 +
How can you change the player's position?  Put something like this in <tt>Player.update</tt>:
 +
 +
this.setPosition( x, y );
 +
 +
If you want to apply the velocity, you can change the player position based on the velocity.
 +
 +
If there is an acceleration, the object's velocity also changes.  The Sprite do not have <tt>velocity</tt> as its property, so we will add it.  You can update the velocity based on the acceleration.
 +
 +
These properties (the position, the velocity, and the acceleration) all have directions.  Sometimes, you see negative velocity; this means the object is moving in an opposite direction as the positive direction.  We shall follow the standard co-ordinate system for Cocos2d, i.e., for the y-axis, we think of the direction as going upwards.
 +
 +
In Physics, everything is continuous.  When writing games, we don't really need exact physics, so we can move objects in discrete steps.  (In fact, method <tt>update</tt> is also called with parameter <tt>dt</tt>, the time period between this call and the last call, and you can use this to make your simulation more smooth.)
 +
 +
So the usual pseudo code for physics is as follows.
 +
 +
pos = pos + velocity;
 +
velocity = velocity + acceleration
 +
 +
=== Falling dot ===
 +
To simulate the player falls, we should maintain the player's current velocity, so that we can make it falls as close as the real object. 
 +
 +
Let's add this line that initialize property <tt>vy</tt> in <tt>Player.ctor</tt>:
 +
 +
{{synfile|src/Player.js}}
 +
<syntaxhighlight lang="javascript">
 +
        this.vy = 15;
 +
</syntaxhighlight>
 +
 +
You may wonder why we put 15 here.  It is just pure guess at this point.  However, when you write games, you might want to try various possible values and pick the best one (i.e., the one that make the game fun).
 +
 +
The <tt>update</tt> method changes the player's position
 +
 +
{{synfile|src/Player.js}}
 +
<syntaxhighlight lang="javascript">
 +
    update: function( dt ) {
 +
        var pos = this.getPosition();
 +
        this.setPosition( new cc.Point( pos.x, pos.y + this.vy ) );
 +
        this.vy += -1;
 +
    }
 +
</syntaxhighlight>
 +
 +
Note that we update <tt>this.vy</tt> at the end of update.  The constant <tt>-1</tt> is the acceleration.  The parameter <tt>dt</tt> represents delta time; we do not use it for now.
 +
 +
Try to run the program.  You should see the player falling.
 +
 +
While our program works, don't just rush to commit right away.  Let's try to get rid of the magic numbers first, by defining them explicitly.
 +
 +
Add these line at the end of <tt>Player.js</tt>
 +
 +
{{synfile|src/Player.js}}
 +
<syntaxhighlight lang="javascript">
 +
Player.G = -1;
 +
Player.STARTING_VELOCITY = 15;
 +
</syntaxhighlight>
 +
 +
Then replace <tt>15</tt> and <tt>-1</tt> in the code with the appropriate constants.
 +
 +
{{gitcomment|When your program looks good, commit it}}
 +
 +
=== Jumping dot ===
 +
 +
Now, let's make the dot jumps.  Let's add method <tt>Player.jump</tt> that set the velocity to some positive amount.
 +
 +
{{synfile|src/Player.js}}
 +
<syntaxhighlight lang="javascript">
 +
    jump: function() {
 +
        this.vy = Player.JUMPING_VELOCITY;
 +
    }
 +
</syntaxhighlight>
 +
 +
Also, add this constant after the class is defined in the <tt>.extend</tt> block.
 +
 +
{{synfile|src/Player.js}}
 +
<syntaxhighlight lang="javascript">
 +
Player.JUMPING_VELOCITY = 15;
 +
</syntaxhighlight>
 +
 +
To jump, we have to call <tt>player.jump()</tt> in an appropriate time.  We will response to keyboard inputs.  We shall follow the style we did in the last tutorial.
 +
 +
First, add these functions.  Function addKeyboardHandler registers the event handlers: onKeyDown and onKeyUp.
 +
 +
{{synfile|src/GameLayer.js}}
 +
<syntaxhighlight lang="javascript">
 +
    addKeyboardHandlers: function() {
 +
        var self = this;
 +
        cc.eventManager.addListener({
 +
            event: cc.EventListener.KEYBOARD,
 +
            onKeyPressed : function( keyCode, event ) {
 +
                self.onKeyDown( keyCode, event );
 +
            },
 +
            onKeyReleased: function( keyCode, event ) {
 +
                self.onKeyUp( keyCode, event );
 +
            }
 +
        }, this);
 +
    },
 +
 +
    onKeyDown: function( keyCode, event ) {
 +
    },
 +
 +
    onKeyUp: function( keyCode, event ) {
 +
    }
 +
</syntaxhighlight>
 +
 +
Then, call addKeyboardHandlers in GameLayer.init
 +
 +
{{synfile|src/GameLayer.js}}
 +
<syntaxhighlight lang="javascript">
 +
    init: function() {
 +
        // ...
 +
this.addKeyboardHandlers();
 +
        // ...
 +
    },
 +
</syntaxhighlight>
 +
 +
We will jump in any key input, so we shall modify <tt>onKeyDown</tt> as follows.
 +
 +
{{synfile|src/GameLayer.js}}
 +
<syntaxhighlight lang="javascript">
 +
    onKeyDown: function( keyCode, event ) {
 +
        this.player.jump();
 +
    }
 +
</syntaxhighlight>
 +
 +
To test this increment, you will have to click on the game canvas, and then quickly hit on any key to get the dot jumping.  Try a few times to see how the dot moves.  You can adjust the jumping velocity to make the movement nice.
 +
 +
{{gitcomment|After a few trials to make sure your code works, please commit.}}

รุ่นแก้ไขเมื่อ 19:38, 12 กุมภาพันธ์ 2562

This is part of the course Programming 2, the material is originally from 01219245/cocos2d-js/Sprites2 from 01219245, 2nd semester 2557.

In this tutorial, we will recreate a clone of a wonderful Flappy Bird. Let's call it Flappy Dot (as our player would look like a dot). We will develop basic game mechanics in this tutorial. We will try to add special effects to the game in the next tutorial.

Task breakdown

Before we start, make sure you know how this game works. You may want to try it for a bit. I guess many of your friends have it on their phones. This is how our game would look like:

219245-dotscr.png

As usual, let's start by thinking about the possible list of increments we would add to an empty project to get this game.

When you get your list, please see the steps that we plan to take here.

  • Show the player on the screen.
  • The player can jump and fall. (Implement player physics)
  • Show a single pillar pair.
  • Move the pillar pair across the screen.
  • Let the pillar pair reappear.
  • Check for player-pillar collision.
  • Make the game with one pillar pair.
  • Show more than one pillar pairs.

The player and its movement

Create a new project, clean up, and set up a Git repository

You should start by downloading the template and cleaning up the original Hello World app. Follow the instruction from the previous tutorial.

If you use the full version of Cocos2d-JS or Cocos2d-x, you should start by creating a new Cocos-JS project.

cocos new -l js --no-native ชื่อโปรเจ็ค

This will create an example HelloWorld project. You should clean up the example by following instructions outlined in Tutorial 100.

Then, create a git repository at the project directory.

Gitmark.png Create your git repository.

Creating the sprite

In this step, we shall create a sprite for the player, and show it in the middle of the screen.

Use a graphic editor to create an image for our player. The image should be of size 40 pixels x 40 pixels. Save the image as res/images/dot.png and try to make it look cute.

We shall create class Player as src/Player.js.

File: src/Player.js
var Player = cc.Sprite.extend({
    ctor: function() {
        this._super();
        this.initWithFile( 'res/images/dot.png' );
    }
});

We shall create the player in GameLayer.init. To do so add these lines:

File: src/GameLayer.js
        this.player = new Player();
        this.player.setPosition( new cc.Point( screenWidth / 2, screenHeight / 2 ) );
        this.addChild( this.player );
        this.player.scheduleUpdate();

Note that we use constants screenWidth and screenHight (which are 800 and 600, respectively). Don't forget to add this constant in main.js.

File: main.js
var screenWidth = 800;       // add these two constants
var screenHeight = 600;      //

cc.game.onStart = function(){
    cc.view.adjustViewPort(true);
    cc.view.setDesignResolutionSize(screenWidth, screenHeight, cc.ResolutionPolicy.SHOW_ALL);    // use them here
    // ...
};
cc.game.run();

Last step is to update configuration and resource files.

1. We need to add src/Player.js to the jsList in project.json.

File: project.json
    // ...
    "jsList" : [
        "src/resource.js",
        "src/GameLayer.js",
        "src/Player.js"
    ]
    // ...

2. Since we are using resource res/images/dot.png, we should preload it (so that we do not have to see empty screen when we start our program). Put the file name in src/resource.js (See more in section Technicalities: preloading of resources, later in this page.)

File: src/resource.js
var res = {
    dot_png: 'res/images/dot.png'
};
// ...

Try to refresh the game. You should see your sprite in the middle of the screen.

Gitmark.png Commit your work.

Review of physics

You might forget all these, but if you want objects in your game to look and act a bit like real objects, you might have to recall stuffs you learned from mechanics.

Let's look at the basics. An object has a position, its position changes if it has non-zero velocity.

How can you change the player's position? Put something like this in Player.update:

this.setPosition( x, y );

If you want to apply the velocity, you can change the player position based on the velocity.

If there is an acceleration, the object's velocity also changes. The Sprite do not have velocity as its property, so we will add it. You can update the velocity based on the acceleration.

These properties (the position, the velocity, and the acceleration) all have directions. Sometimes, you see negative velocity; this means the object is moving in an opposite direction as the positive direction. We shall follow the standard co-ordinate system for Cocos2d, i.e., for the y-axis, we think of the direction as going upwards.

In Physics, everything is continuous. When writing games, we don't really need exact physics, so we can move objects in discrete steps. (In fact, method update is also called with parameter dt, the time period between this call and the last call, and you can use this to make your simulation more smooth.)

So the usual pseudo code for physics is as follows.

pos = pos + velocity;
velocity = velocity + acceleration

Falling dot

To simulate the player falls, we should maintain the player's current velocity, so that we can make it falls as close as the real object.

Let's add this line that initialize property vy in Player.ctor:

File: src/Player.js
        this.vy = 15;

You may wonder why we put 15 here. It is just pure guess at this point. However, when you write games, you might want to try various possible values and pick the best one (i.e., the one that make the game fun).

The update method changes the player's position

File: src/Player.js
    update: function( dt ) {
        var pos = this.getPosition();
        this.setPosition( new cc.Point( pos.x, pos.y + this.vy ) );
        this.vy += -1;
    }

Note that we update this.vy at the end of update. The constant -1 is the acceleration. The parameter dt represents delta time; we do not use it for now.

Try to run the program. You should see the player falling.

While our program works, don't just rush to commit right away. Let's try to get rid of the magic numbers first, by defining them explicitly.

Add these line at the end of Player.js

File: src/Player.js
Player.G = -1;
Player.STARTING_VELOCITY = 15;

Then replace 15 and -1 in the code with the appropriate constants.

Gitmark.png When your program looks good, commit it

Jumping dot

Now, let's make the dot jumps. Let's add method Player.jump that set the velocity to some positive amount.

File: src/Player.js
    jump: function() {
        this.vy = Player.JUMPING_VELOCITY;
    }

Also, add this constant after the class is defined in the .extend block.

File: src/Player.js
Player.JUMPING_VELOCITY = 15;

To jump, we have to call player.jump() in an appropriate time. We will response to keyboard inputs. We shall follow the style we did in the last tutorial.

First, add these functions. Function addKeyboardHandler registers the event handlers: onKeyDown and onKeyUp.

File: src/GameLayer.js
    addKeyboardHandlers: function() {
        var self = this;
        cc.eventManager.addListener({
            event: cc.EventListener.KEYBOARD,
            onKeyPressed : function( keyCode, event ) {
                self.onKeyDown( keyCode, event );
            },
            onKeyReleased: function( keyCode, event ) {
                self.onKeyUp( keyCode, event );
            }
        }, this);
    },

    onKeyDown: function( keyCode, event ) {
    },

    onKeyUp: function( keyCode, event ) {
    }

Then, call addKeyboardHandlers in GameLayer.init

File: src/GameLayer.js
    init: function() {
        // ...
	this.addKeyboardHandlers();
        // ...
    },

We will jump in any key input, so we shall modify onKeyDown as follows.

File: src/GameLayer.js
    onKeyDown: function( keyCode, event ) {
        this.player.jump();
    }

To test this increment, you will have to click on the game canvas, and then quickly hit on any key to get the dot jumping. Try a few times to see how the dot moves. You can adjust the jumping velocity to make the movement nice.

Gitmark.png After a few trials to make sure your code works, please commit.