我个人很喜欢开发的非常流行的2D、3D游戏库

# Phaserjs

h5游戏框架

安装

npm install phaser
1

加载资源

在preload(预加载)函数中调用phaser的加载器。Phaser启动时会自动找到这个函数,并加载里面定义好的所有资源。

function preload ()
{
    this.load.image('sky', 'assets/sky.png');
    this.load.image('ground', 'assets/platform.png');
    this.load.image('star', 'assets/star.png');
    this.load.image('bomb', 'assets/bomb.png');
    this.load.spritesheet('dude', 
        'assets/dude.png',
        { frameWidth: 32, frameHeight: 48 }
    );
}
1
2
3
4
5
6
7
8
9
10
11

上面的代码加载了四张图片和一张精灵表单,

把加载的图片显示出来用create方法

function create ()
{
    this.add.image(400, 300, 'sky');
    this.add.image(400, 300, 'star');
}
1
2
3
4
5

玩家

player = this.physics.add.sprite(100, 450, 'dude');

player.setBounce(0.2);
player.setCollideWorldBounds(true);
1
2
3
4

第一行生成一个新的精灵,叫player(玩家),位于100 x 450像素,在游戏的下部。

精灵生成后,被赋予0.2的一点点反弹(bounce)值。这意味着,它跳起后着地时始终会弹起那么一点点。

精灵设置了与世界边界(bound)的碰撞。——边界默认在游戏尺寸之外。我们(通过player.setCollideWorldBounds(true))把游戏(的世界边界)设置为800 x 600后,玩家就不能不跑出这个区域了。这样会让玩家停下来,不能跑出画面边界,或跳出顶边。

玩家动画

定义一个左转动画、转身动画、右转动画

this.anims.create({
    key: 'left',
    frames: this.anims.generateFrameNumbers('dude', { start: 0, end: 3 }),
    frameRate: 10,
    repeat: -1
});
this.anims.create({
    key: 'turn',
    frames: [ { key: 'dude', frame: 4 } ],
    frameRate: 20
});

this.anims.create({
    key: 'right',
    frames: this.anims.generateFrameNumbers('dude', { start: 5, end: 8 }),
    frameRate: 10,
    repeat: -1
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

'left'动画使用0, 1, 2, 3帧,跑动时每秒10帧。'repeat -1'告诉动画要循环播放

右转动画

物理系统

Phaser支持多种物理系统,每一种都以插件形式运作,任何Phaser场景都能使用它们。

键盘控制

Phaser有内置的键盘管理器,

cursors = this.input.keyboard.createCursorKeys();
if (cursors.left.isDown)
{
    player.setVelocityX(-160);
    player.anims.play('left', true);
}
else if (cursors.right.isDown)
{
    player.setVelocityX(160);
    player.anims.play('right', true);
}
else
{
    player.setVelocityX(0);
    player.anims.play('turn');
}
if (cursors.up.isDown && player.body.touching.down)
{
    player.setVelocityY(-330);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

上面代码表示如果左键按下,我们应用一个负的水平速度,开动奔跑动画'left'。如果是方向右键正被按下,我们按字面意思做反向动作。方向up键是跳起键,我们检查它有没有被按下。不过我们同时也检测玩家是不是正与地面接触,否则在半空中还会往上跳。

如果所有这些条件都符合,我们应用一个垂直速度,330像素每秒。玩家会自动落回地面,因为有重力。

游戏目标

stars = this.physics.add.group({
    key: 'star',
    repeat: 11,
    setXY: { x: 12, y: 0, stepX: 70 }
});

stars.children.iterate(function (child) {
    child.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
});
1
2
3
4
5
6
7
8
9

定义一个收集星星的游戏目标。首先定义一个新的组,生成星星,

this.physics.add.collider(stars, platforms);

this.physics.add.overlap(player, stars, collectStar, null, this);

function collectStar (player, star)
{
    star.disableBody(true, true);
}
1
2
3
4
5
6
7
8

定义得分及显示

var score = 0;
var scoreText;

scoreText = this.add.text(16, 16, 'score: 0', { fontSize: '32px', fill: '#000' });

function collectStar (player, star)
{
    star.disableBody(true, true);
    score += 10;
    scoreText.setText('Score: ' + score);
}
1
2
3
4
5
6
7
8
9
10
11

定义两个对象。一个持有实际得分,一个文本对象

在create函数中创建文本,语句中16 x 16是显示文本的坐标位置。'score: 0'是要显示的默认字符串,接下来的对象包含字号、填充色等。没有指定字体的话将用Phaser默认的,即Courier。

每颗星星加10分,scoreText将更新,显示出新的总分。

添加坏蛋

游戏的另一规则是添加坏蛋,定义规则为:你第一次收集到所有星星后,将放出一个跳跳弹。这个炸弹只是随机地在平台上各处跳,如果收集它,你就死了。所有星星会重新产出,以便你可以再次收集,如果你完成了,又会放出另一个炸弹。这将给玩家一个挑战:别死掉,取得尽可能高的分数。

bombs = this.physics.add.group();
this.physics.add.collider(bombs, platforms);
this.physics.add.collider(player, bombs, hitBomb, null, this);

function hitBomb (player, bomb)
{
    this.physics.pause();
    player.setTint(0xff0000);
    player.anims.play('turn');
    gameOver = true;
}

function collectStar (player, star)
{
    star.disableBody(true, true);

    score += 10;
    scoreText.setText('Score: ' + score);

    if (stars.countActive(true) === 0)
    {
        stars.children.iterate(function (child) {
            child.enableBody(true, child.x, 0, true, true);
        });

        var x = (player.x < 400) ? Phaser.Math.Between(400, 800) : Phaser.Math.Between(0, 400);
        var bomb = bombs.create(x, 16, 'bomb');
        bomb.setBounce(1);
        bomb.setCollideWorldBounds(true);
        bomb.setVelocity(Phaser.Math.Between(-200, 200), 20);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

首先新定义一个组表示炸弹组,再定义两个碰撞器检测,使炸弹不出边界,以及玩家碰撞炸弹的情况。

当玩家碰到炸弹时调用hitbomb函数,函数定义玩家碰到炸弹时玩家变成红色,游戏停止。

还更新了原来的收集星星的函数,碰到星星的同时放出炸弹。如果星星没有了,那么玩家把它们收集完了,于是我们使用迭代函数重新激活所有星星,重置它们的y位置为0。这将使所有星星再次从画面顶部落下。

正常镜头、缓慢息屏镜头、屏闪镜头、抖动镜头

var config = {
    type: Phaser.WEBGL,
    parent: 'phaser-example',
    scene: {
        preload: preload,
        create: create,
        update: update
    },
    width: 800,
    height: 600
};

var game = new Phaser.Game(config);
var fadeCamera;
var flashCamera;
var shakeCamera;

function preload() {
    this.load.image('CherilPerils', 'assets/tests/camera/CherilPerils.png');
}

function create() {

    var image = this.add.image(0, 0, 'CherilPerils');

    this.cameras.main.setViewport(5, 5, 390, 290);
    fadeCamera = this.cameras.add(405, 5, 390, 290);
    flashCamera = this.cameras.add(5, 305, 390, 290);
    shakeCamera = this.cameras.add(405, 305, 390, 290);

    fadeCamera.fade(1000);
}

function update()
{
    flashCamera.flash(1000);
    shakeCamera.shake(1000);
    if (fadeCamera._fadeAlpha >= 1.0)
    {
        fadeCamera._fadeAlpha = 0.0;
        fadeCamera.fade(1000);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

时间

var config = {
    type: Phaser.CANVAS,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    backgroundColor: '#9adaea',
    useTicker: true,
    scene: {
        preload: preload,
        create: create,
        update: update
    }
};

var bullet1;
var bullet2;

var speed1;
var speed2;

var game = new Phaser.Game(config);

function preload ()
{
    this.load.image('bullet', 'assets/tests/timer/bullet-bill.png');
    this.load.image('cannon', 'assets/tests/timer/cannon.png');
    this.load.image('ground', 'assets/tests/timer/ground.png');
}

function create ()
{
    //   Bullet 1 (600px in 6 seconds)
    this.add.image(0, 200, 'ground').setOrigin(0);
    bullet1 = this.add.image(64, 76, 'bullet').setOrigin(0);
    speed1 = Phaser.Math.GetSpeed(600, 6);
    this.add.image(64, 72, 'cannon').setOrigin(0);
    this.add.text(64, 50, '600px / 6 secs', { fill: '#000' });

    //   Bullet 2 (600px in 3 seconds)
    this.add.image(0, 500, 'ground').setOrigin(0);
    bullet2 = this.add.image(64, 376, 'bullet').setOrigin(0);
    speed2 = Phaser.Math.GetSpeed(600, 3);
    this.add.image(64, 500, 'cannon').setOrigin(0, 1);
    this.add.text(64, 350, '600px / 3 secs', { fill: '#000' });
}
//  The update function is passed 2 values:
//  The current time (in ms)

function update (time, delta)
{
    bullet1.x += speed1 * delta;

    if (bullet1.x > 864)
    {
        bullet1.x = 64;
    }

    bullet2.x += speed2 * delta;

    if (bullet2.x > 864)
    {
        bullet2.x = 64;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

# Pixi

https://github.com/Zainking/learningPixi

Pixi是一个超快的2D渲染引擎,这意味着它会帮助你用JavaScript或者其他HTML5技术来显示媒体、创建动画或管理交互式图像,从而制作一个游戏或者应用。

它拥有简洁的API接口,并且加入了一些非常有用的特性,比如支持纹理贴图集和为精灵提供了一个简单的动画系统。它提供了一个完备的场景图,你可以在精灵图层里面创建另一个精灵,

Pixi API的优势在于,它是通用的:它不是一个游戏引擎,这是一个优势,因为它给了你所有的自由去做任何你想做的事,甚至于写成自己的游戏引擎

# Babylonjs

# Cocos 2D-x

基本的概念:

Director导演:

一个常见的 Director 任务是控制场景替换和转换。 Director是一个共享的单例对象,可以在代码中的任何地方调用。

auto myScene = Scene::create();
//用于创建第一个场景,只用于第一个场景
Director::getInstance()->runWithScene(myScene);
//用于替换场景,并释放当前场景
Director::getInstance()->replaceScene(myScene);
//将当前运行中的场景暂停并压入到场景栈中,再将传入的场景设置为当前运行场景。
Director::getInstance()->pushScene(myScene);
//释放当前场景,再从场景栈中弹出栈顶的场景,并将其设置为当前运行场景。如果栈为空,直接结束应用。
Director::getInstance()->popScene();
1
2
3
4
5
6
7
8
9

场景切换的效果

// Transition Fade
Director::getInstance()->replaceScene(TransitionFade::create(0.5, myScene, Color3B(0,255,255)));

// FlipX
Director::getInstance()->replaceScene(TransitionFlipX::create(2, myScene));

// Transition Slide In
Director::getInstance()->replaceScene(TransitionSlideInT::create(1, myScene) );
1
2
3
4
5
6
7
8

Scene场景:

这个场景是由很多小的对象拼接而成,所有的对象组合在一起,形成了最终的结果。场景是被 渲染器(renderer) 画出来的。渲染器负责渲染精灵和其它的对象进入屏幕。为了更好的理解这个过程,我们需要讨论一下 场景图

场景图(Scene Graph)是一种安排场景内对象的数据结构,它把场景内所有的 节点(Node) 都包含在一个 树(tree) 上。(场景图虽然叫做"图",但实际使用一个树结构来表示)。

//创建场景
auto myScene = Scene::create();

1
2
3

Spirite精灵:

精灵是您在屏幕上移动的对象,它能被控制。你喜欢玩的游戏中主角可能就是一个精灵,如果不能控制,就是节点(Node)。Sprite 很容易被创建,它有一些可以被配置的属性,比如:位置,旋转角度,缩放比例,透明度,颜色 等等。

// 创建精灵
auto mySprite = Sprite::create("mysprite.png");

// 改变精灵属性
mySprite->setPosition(Vec2(500, 0));
//设置旋转角度
mySprite->setRotation(40);

mySprite->setScale(2.0); // sets both the scale of the X and Y axis uniformly
//设置锚点
mySprite->setAnchorPoint(Vec2(0, 0));
//设置颜色
mySprite->setColor(Color3B(255, 255, 255)); 
//设置透明度
mySprite->setOpacity(30);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

锚点(anchor point) ,所有的节点(Node)对象都有锚点值,SpriteNode 的子类,自然也具有锚点。锚点是节点对象在计算坐标位置时的一个基准点。

Action动作:

动作(Action)可以让精灵在场景中移动,如从一个点移动到另外一个点。你还可以创建一个动作 序列(Sequence) ,让精灵按照这个序列做连续的动作,在动作过程中你可以改变精灵的位置,旋转角度,缩放比例等等。

实例

// Move a sprite 50 pixels to the right, and 10 pixels to the top over 2 seconds.
auto moveBy = MoveBy::create(2, Vec2(50,10));
mySprite->runAction(moveBy);

// Move a sprite to a specific location over 2 seconds.
auto moveTo = MoveTo::create(2, Vec2(50,10));
mySprite->runAction(moveTo);
1
2
3
4
5
6
7

Sequence序列:

顾名思义,序列就是多个动作按照特定顺序的一个排列,当然反向执行这个序列也是可以的,Cocos2d-x 能很方便的完成这项工作。

实例

auto mySprite = Node::create();

// move to point 50,10 over 2 seconds
auto moveTo1 = MoveTo::create(2, Vec2(50,10));

// move from current position by 100,10 over 2 seconds
auto moveBy1 = MoveBy::create(2, Vec2(100,10));

// move to point 150,10 over 2 seconds
auto moveTo2 = MoveTo::create(2, Vec2(150,10));

// create a delay
auto delay = DelayTime::create(1);

mySprite->runAction(Sequence::create(moveTo1, delay, moveBy1, delay.clone(),
moveTo2, nullptr));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 事件监听

  • EventListenerTouch - 响应触摸事件
  • EventListenerKeyboard - 响应键盘事件
  • EventListenerAcceleration - 响应加速度事件
  • EventListenMouse - 响应鼠标事件
  • EventListenerCustom - 响应自定义事件

# 音乐和音效

Cocos2d-x 提供了一个 SimpleAudioEngine 类支持游戏内的音乐和音效。它可以被用来增加背景音乐,控制游戏音效。

SimpleAudioEngine 是一个共享的单例对象,你可以在代码中的任何地方通过很简单的方式获取到。以下,我们会尽可能的为你展示它的各种使用方法。

支持的背景音乐格式

平台 支持的常见文件格式 备注
Android mp3, mid, ogg, wav 可以播放android.media.MediaPlayer所支持的所有格式
iOS aac, caf, mp3, m4a, wav 可以播放AVAudioPlayer所支持的所有格式
Windows mid, mp3, wav

支持的音效格式:

平台 支持的常见文件格式 备注
Android ogg, wav 对wav的支持不完美
iOS caf, m4a 可以播放Cocos2d-iPhone CocosDesion所支持的所有格式
Windows mid, wav

播放背景音乐

播放音效

暂停背景音乐和音效

// 暂停背景音乐
audio->pauseBackgroundMusic();

// 暂停音效
audio->pauseEffect();

// 暂停所有音效
audio->pauseAllEffects();
1
2
3
4
5
6
7
8

停止背景音乐和音效

//停止背景音乐
audio->stopBackgroundMusic();

// 停止音效
audio->stopEffect();

// 停止所有音效
audio->stopAllEffects();
1
2
3
4
5
6
7
8

恢复背景音乐和音效

// 恢复背景音乐
audio->resumeBackgroundMusic();

// 恢复音效
audio->resumeEffect();

// 恢复所有音效
audio->resumeAllEffects();
1
2
3
4
5
6
7
8

调节音量

// setting the volume specifying value as a float
// 设置默认音量
audio->setEffectsVolume(0.5);
audio->setBackgroundMusicVolume(0.5);
1
2
3
4

# 物理引擎

概念

刚体(Bodies) 描述了抽象物体的物理属性,包括:质量、位置、旋转角度、速度和阻尼。Cocos2d-x 中用 PhysicsBody 对象表示刚体。当刚体和形状关联后,刚体对象才具有几何形状,未关联形状, 刚体只是一个抽象物体的物理属性集。

材质(Material) 描述了抽象物体的材料属性:

  • density:密度,用于计算物体的质量
  • friction:摩擦,用于模拟物体间的接触滑动
  • restitution:恢复系数,模拟物体反弹的一个系数,系数一般设为 0 到 1 之间。0 代表不反弹,1 代表完全反弹。

形状(Shape) 描述了抽象物体的几何属性,将形状关联到刚体,刚体才具有几何形状。如果需要刚体具有复杂的形状,可以为它关联多个形状,每个形状对象都与一个 PhysicsMaterial 相关,并且拥有以下属性:

连接(Contacts)关节(joint) 对象描述了刚体相互关联的方式。

物理检测

基于点检测

点检测是检查一个点周围的一定距离内是否有物体。通过点检测你可以找到一个物体中距离某定点最近的点,或者找到距离一个定点最近的物体,这非常适合于判断鼠标点击拾取的对象,也可以利用它进行一些其它的简单感知。

射线检测

当你四处看的时候,在你视线内的某些物体肯定会引起你的注意,你可以将这种情景作为一个射线查询的例子。射线查询是检查从一个定点发出的射线是否相交于一个物体,如果相交可以获取到一个交叉点,这非常适合于判断子弹(忽略子弹的飞行时间)是否命中。

矩形检测

# Cocos Creator

Cocos Creator 的工作流程是以数据驱动和场景为核心的,初次打开一个项目时,默认不会打开任何场景,要看到 Hello World 模板中的内容,我们需要先打开场景资源文件。

项目结构

初次创建并打开一个 Cocos Creator 项目后,开发者的项目文件夹将会包括以下结构:

ProjectName(项目文件夹)
├──assets
├──library
├──local
├──packages
├──settings
├──temp
└──project.json
1
2
3
4
5
6
7
8

assets 将会用来放置游戏中所有的本地资源、脚本和第三方库文件。只有在 assets 目录下的内容才能显示在 资源管理器 中。assets 中的每个文件在导入项目后都会生成一个相同名字的 .meta 文件,用于存储对应的资源配置和索引信息。.meta 文件需要一并提交到版本控制系统,一些第三方工具生成的工程或设计原文件,如 TexturePacker 的 .tps 文件,或 Photoshop 的 .psd 文件,可以选择放在 assets 外面来管理。

library 是将 assets 中的资源导入后生成的,在这里文件的结构和资源的格式将被处理成最终游戏发布时需要的形式。

library 丢失或损坏的时候,只要删除整个 library 文件夹再打开项目,就会重新生成资源库。

local 文件夹中包含该项目的本机上的配置信息,包括编辑器面板布局,窗口大小,位置等信息。开发者不需要关心这里的内容。

packages 文件夹用于放置此项目的自定义扩展插件。如需手动安装扩展插件,可以手动创建此文件夹。如需卸载扩展插件,在 packages 中删除对应的文件夹即可。

settings 里保存项目相关的设置,如 构建发布 菜单里的包名、场景和平台选择等。

temp 是临时文件夹,用于缓存一些 Cocos Creator 在本地的临时文件。这个文件夹可以在关闭 Cocos Creator 后手动删除,开发者不需要关心这里面的内容。

project.json 文件和 assets 文件夹一起,作为验证 Cocos Creator 项目合法性的标志,只有包括了这两个内容的文件夹才能作为 Cocos Creator 项目打开。开发者不需要关心里面的内容。

发布文件夹build:在使用主菜单中的 项目 -> 构建发布... 使用默认发布路径发布项目后,编辑器会在项目路径下创建 build 目录,并存放所有目标平台的构建工程。

制作简单游戏

Cocos Creator 开发游戏的一个核心理念就是让内容生产和功能开发可以流畅的并行协作,我们在上个部分着重于处理美术内容,而接下来就是通过编写脚本来开发功能的流程,之后我们还会看到写好的程序脚本可以很容易地被内容生产者使用。

首先我们可以看到一个全局的 cc.Class() 方法,cc 是 Cocos 的简称,Cocos 引擎的主要命名空间,引擎代码中所有的类、函数、属性和常量都在这个命名空间中定义。而 Class() 就是 cc 模块下的一个方法,这个方法用于声明 Cocos Creator 中的类。为了方便区分,我们把使用 cc.Class 声明的类叫做 CCClassClass() 方法的参数是一个原型对象,在原型对象中以键值对的形式设定所需的类型参数,就能创建出所需要的类。

# egret

# layabox

# CreateJS

http://www.createjs.cc/about.html

CreateJS是一套可以构建丰富交互体验的 HTML5 游戏的开源工具包,旨在降低 HTML5 项目的开发难度和成本,让开发者以熟悉的方式打造更具现代感的网络交互体验。

CreateJS 中包含四款工具:

  • EaselJS:用于 Sprites、动画、向量和位图的绘制,创建 HTML5 Canvas 上的交互体验(包含多点触控),同时提供 Flash 中的“显示列表”功能。
  • TweenJS:一个简单的用于制作类似 Flash 中“补间动画”的引擎,可生成数字或非数字的连续变化效果。
  • SoundJS:一个音频播放引擎,能够根据浏览器性能选择音频播放方式。将音频文件作为模块,可随时加载和卸载。
  • PrloadJS:帮助你简化网站资源预加载工作,无论加载内容是图形、视频、声音、JS、数据……
Last Updated: 8/22/2021, 2:30:32 PM