(一)Cocos2d-html5制作一款横版动作游戏——项目组织

发表于2015-08-24
评论0 1.3k浏览

(一) 项目组织

u0u0 2014-07-14 17:25:347083 次阅读

图1

源码下载 地址

这是一个简单的游戏打斗场景,一个英雄,一个怪物,可以控制英雄来回走动并且攻击,怪物实现简单 AI 并且自动攻击,有着不同的血量槽,控制系统,可以使用触摸,但为了操作的体验,同样实现了 键盘映射 ,可以使用 W、A、S、D 来控制人物的走动,J、U、I 实现一个普通攻击和两个特效攻击。

项目组织

为了使项目的代码结构清晰,前期规划好功能是必须的,先从整体看一下,项目的组织结构,然后会对其中内部实现做些必要的解说: 图2

如上所示, Arthur为游戏项目的主目录,与它同级的目录,是 H5 的库目录,当然截图中,为了发布,删除了一些不必要的文件,在 Arthur 目录下,包含一般项目都包含的结构组织。

  • index.html : 这是游戏的展示界面,其中包含 “gameCanvas” ,作为游戏绘制的所在,它引用加载了 cocos2d.js。
  • cocos2d.js : 项目初始化在这里进行,并完成系统库和项目源码的 js 加载,最后将控制权交给 main.js 文件。
  • main.js : 当 H5 库加载完毕,执行内中代码,完成项目资源加载,并运行第一个场景。
  • src : 此目录包含了游戏中编写的 js 源代码文件。
  • res : 游戏所需的资源,如图片,字体等。

在这个游戏中相对复杂一点的就是控制系统了,其中在 HudLayer 中添加实现了 ActionButton 普通攻击按钮; Joypad中实现了可触摸360度摇杆功能和KeyMap游戏控制键盘映射方案;Characters 实现了人物和怪物的功能,包括各种动作控制;Loading 替换了 H5 的默认加载界面,使用了一个进度条显示加载进度;GameLayer 作为游戏的主场景,各种游戏的流程控制在这里进行。

360度可触摸摇杆实现

这里的摇杆,默认是为了触摸实现,之后添加的键盘映射,只是为了让操作更为方便而已(在 PC 浏览器中),触摸不同于摇杆的所在,是这里的摇杆可以在 360 度以内的任意角度遥控角色移动,这是键盘所不具备的,上下左右四个键,再加上每两个方向的组合也就八个方向。

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
var Joypad = cc.Layer.extend({
    _winSize: null,
    _pCenter: null,
    _pControlSprite: null,
    _pDefaultPoint: null,
 
    _pDefaultRotation: null,
    _pRotation: null,
 
    _pDelegate: null,
    _pKeyDown: false,
    ctor:function(){
        this._super();
 
        _winSize = cc.Director.getInstance().getWinSize();
        _pCenter = cc.p(_winSize.width / 2, _winSize.height / 2);
 
    },
    init:function(){
        var bRet = false;
        if (this._super()){
            cc.log("Joypad init ..");
            // 控制杆所在位置
            this._pDefaultPoint = cc.p(110, 110);
            // 默认旋转角度,以使开口正对右侧
            this._pDefaultRotation = 26;
            // 实际旋转角度
            this._pRotation = 0;
 
            this.setPosition(this._pDefaultPoint);           
 
            this.addChild(cc.Sprite.create(s_Joypad1));
            this.addChild(cc.Sprite.create(s_Joypad2));
            this._pControlSprite = cc.Sprite.create(s_Joypad3);
            this.addChild(this._pControlSprite);
            this.addChild(cc.Sprite.create(s_Joypad4));
 
            this.updateRotation();
 
            bRet = true;
        }
        return bRet;
    },
    keyStart:function(degrees){
        if (this._pDelegate)           
            this._pDelegate.actionJoypadStart(this._pRotation);
    },
    keyUpdate:function(degrees){
        this._pRotation = degrees;
        this.updateRotation();
        if (this._pDelegate)
            this._pDelegate.actionJoypadUpdate(this._pRotation);               
    },
    keyEnded:function(degrees){
        if (this._pDelegate)           
            this._pDelegate.actionJoypadEnded(this._pRotation);       
    },
    onEnter:function(){
        this._super();
        // cc.Director.getInstance().getTouchDispatcher().addTargetedDelegate(this, 0, true);
        // 2.1.5 to 2.1.6
        cc.registerTargetedDelegate(0, true, this);
    },
    onExit:function(){
        cc.unregisterTouchDelegate(this);
    },
    onTouchBegan:function (touch, event){
        // 点击点的范围判断
        var curPoint = touch.getLocation();
        if (curPoint.x > _winSize.width / 2 || curPoint.y > _winSize.height / 2 ){
            return false;
        }
 
        // var sp = cc.pSub(this._pDefaultPoint, curPoint);
        // var angle = cc.pToAngle(sp);
 
        this.updateTouchRotation(touch, event);
        this.updateRotation();
        if(this._pDelegate)
            this._pDelegate.actionJoypadStart(this._pRotation);
        else
            cc.log('_pDelegate is null ... ');
 
        // cc.log("Joypad touch ...");
        return true;
    },
    onTouchMoved:function (touch, event){
        this.updateTouchRotation(touch, event);
        this.updateRotation();
 
        if (this._pDelegate)
            this._pDelegate.actionJoypadUpdate(this._pRotation);
        else
            cc.log('_pDelegate is null ... ');
 
        // var a = cc.pAngleSigned( curPoint, this._pDefaultPoint);
        // cc.log("Joypad touch mvove ..." + rotation) ;
    },
    onTouchEnded:function (touch, event){
        this.updateTouchRotation(touch, event);
        this.updateRotation();
        if (this._pDelegate)
            this._pDelegate.actionJoypadEnded(this._pRotation);
        else
            cc.log('_pDelegate is null ... ');
    },
    updateTouchRotation:function(touch, event){
        var curPoint = touch.getLocation();
        var sp = cc.pSub(curPoint, this._pDefaultPoint);
        var angle = cc.pToAngle(sp) ;// * -57.29577951;
        var rotation = angle * -57.29577951;
        rotation = rotation < 0 ? 360 + rotation: rotation;
        this._pRotation = rotation;       
    },
    updateRotation:function(){
        this._pControlSprite.setRotation(this._pDefaultRotation + this._pRotation);
    },
    setDelegate:function(dg){
        this._pDelegate = dg;
    }
});

图3

在初始化方法中,加载了摇杆资源文件,它分解成几个组成部分,以便于很好的控制,并且保存了可旋转元素精灵的引用this._pControlSprite,以便于随时控制它的旋转角度,如图中 Joypad3.png 图片。

以触摸的动作来控制动作的执行,Joypad 中包含了一个名为 _pDelegate 的属性,它作为控制摇杆的代理,以通知其它 (如 人物),摇杆现在变动了,分别在 onTouchBegan 中调用,this._pDelegate.actionJoypadStart(this._pRotation);onTouchMoved 中调用this._pDelegate.actionJoypadUpdate(this._pRotation); 和在 onTouchEnded 中调用this._pDelegate.actionJoypadEnded(this._pRotation);

只需要在传入的 _pDelegate 中实现此三种函数,就可以通过摇杆来控制其操作了,H5 使用 javascript 相比如 C++ 倒也省去了接口定义等繁杂的操作。可以看见,在三个函数调用中,所传入的参数为触摸的角度,在触摸是通知控制显示摇杆中 “罗盘” 的旋转。Joypad 对内通过触摸控制显示,对外通过触摸调用代理,以达到显示和控制相一致的目的。通过触摸的点相对摇杆原点的位置关系,很容计算出其角度。

由于这里的摇杆设计是 360 度任意角度,所以在 delegate 中传出一个参数,以标示角度关系,如果并不需要那么复杂的控制,如前文所言,只需固定八个方向的控制,那么这里传出的参数可以使用 枚举 类型,代表八个不同的方向,也会使得游戏逻辑变得稍微简单。

最后可以为 Joypad 层封装一个简单好用的调用方式:

1
2
3
4
5
6
7
Joypad.create = function(){
    var joypad = new Joypad();
    if (joypad && joypad.init()){
        return joypad;
    }
    return null;
};

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引