flex 联机游戏开发 - 四国军棋游戏:(三) 核心类

通过前面的练习 flex 联机游戏开发 - 四国军棋游戏:(二)棋盘棋子 我们已经成功地用不到200行的代码绘制出了一个漂亮的棋盘,现在,我们开始进入游戏的核心类设计阶段。四国军棋的游戏逻辑还是比较复杂的,棋子在布局,游戏阶段有不同的可移动位置,棋子的位置也有自己的可移动位置,工并可以到处飞,还有铁道等,当然,设计者通过不同的渠道都可以达到相同的设计目标,主要看你设计的目标及对性能的要求。在开始设计之前,我先来说说flex的坏话

一)利用flex设计的利与弊

1.1)坏处

1)flex暂时还很难在没有fms支持的情况下实现双工通讯,这与silverlight成熟的双工通讯机制比还是有点不足,当然,也并不全是坏事,在下棋的时候加上聊天,双工通讯的开销也是挺吓人的。 在没有双工通讯的基础上,我们只能通过定时期不断的获得服务器端的数据进行更新

2) flex暂时还没有比较完善的集合类,它仅提供了一个arraycollection及xmlcollection类供开发者使用,我们不得不使用一些第三方或自己开发的集合类来完善功能,比如hashmap,这总是应该有的一个集合类吧。当然,作为一个plug in ,adobe也是挺痛苦的,类库太大方便了开发者,就苦了消费者。当年的java swing  直接将 java applet 送入了死亡通道,前车之鉴嘛,我估计最终仍旧是消费者战胜开发者。

3)图形绘制中没有drawsting的功能,而且就算将来有,对中文字体的支持估计也够呛,所以,你只能自己写一个类似于label的uid类或者直接用label类来显示中文文本。这无疑增大系统的开销。

1.2)好处

1)良好的ui设计,通过flex绘制出来的图形本身已经比较漂亮,当你加入一些简单的组件的效果,滤镜时就更漂亮了,而所有这些,开销并不算太大。在讲究用户体验的今天,这些还是相当诱人的。

这是设计的一个全局位置图。仅在棋盘中绑定一些label,label加上一些效果就行了,几行代码。sg3_1

2)flex简单易学,我从java,c#转头来做这个游戏似乎只看了一本书,书名叫“flex 4-一学就会”,所以,如果你是一位java,c#程序员,不要有太多的顾虑。另外,flex类似于silverlight的绑定机制,事件冒泡模式使设计开发变得更有想象力(当然,想象力太好也可能把事情越弄越复杂)s

3)所有好处好象最终只围绕这个好处,那就是 flash player拥有全世界无人能敌的98%的装机量,而且,直接延伸到android,iphone。还有什么比这更让一个游戏开发者羡慕。。。

好了,聊完了上面的这些内容,让我们来干些实事

二)全局设计考虑

1) 你可以从任何一个方向来开始这个程序,对老练的程序员来算,只要你有头脑,似乎并不需要太多的经验,但是你首先得确定方向,本程序里,我开发的首先是一个联机,然后才是游戏,对于联机游戏,有必引入adobe的一种设计模式 cairngoarm,似乎可以将事情变得简单一点。

2)作为联机游戏,你得时时考虑服务器的开销,在本程序里,服务器需要什么,他只需要一个数组标识三个内容(位置,玩家,棋子),算起来一共只要6个字节,加上129个位置,最多也不超过1k的传输内容,真是令人惊讶。没开发的时候,我以为要传输的内容很多呐。所以,我决定从自顶向下的开发这个游戏。就是先设计与服务器交互的内容 GameEngine,然后再回头来设计每个类。

3)需要设计什么类,首先是位置需要有个类 PositionVO,然后棋子应该是最主要的类QizhiVO,位置应该是棋子的成员,为什么棋子不是位置的成员?(原因:(有没有没有位置的棋子?当然没有;有没有没有棋子的位置?当然有),还要设计一个玩家的类,玩家在一张桌子上有一个位置,我们就按顺时针方向设计为(0,1,2,3)吧。这也是棋子的成员。似乎就没什么要考虑了的吧。

好了,现在我们来做四国军棋游戏的逻辑部分,一些轻松的工作,设计自己的第一个类,常量助辅类 Enum,类里的元素相信你一看就明白;

 

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
package com.boyiju.game.siguo.util
{
    /**
     * 四国军模可能用到的常量值
     * @author Administrator
     *
     */
    public class Enum
    {
        //棋局状态
        public static const GAME_LAYOUT:int=0;//布局
        public static const GAME_WAIT:int=1;//完成布局,等待棋它玩家
        public static const GAME_PLAYING:int=2;//游戏中
        public static const GAME_END:int=3;//游戏结束
         
        //玩家颜色
        public static const COLOR_PLAYER_BOTTOM:int=0X34699d;//下
        public static const COLOR_PLAYER_RIGHT:int=0Xd86c00;//右
        public static const COLOR_PLAYER_TOP:int=0X8f449f;//上
        public static const COLOR_PLAYER_LEFT:int=0X709c00;//左
         
        //棋子
        public static const QIZHI_SINING:int=40;//司令
        public static const QIZHI_JUNZHANG:int=39;
        public static const QIZHI_SHIZHANG:int=38;
        public static const QIZHI_LVZHANG:int=37;
        public static const QIZHI_TUANZHANG:int=36;
        public static const QIZHI_YINGZHANG:int=35;
        public static const QIZHI_LIANGZHANG:int=34;
        public static const QIZHI_PAIZHANG:int=33;
        public static const QIZHI_GONGBING:int=32;
        public static const QIZHI_DILEI:int=31;
        public static const QIZHI_JUQI:int=30; //最小为军棋,谁都可以吃
        public static const QIZHI_ZHADAN:int=100;
         
         
        //可视
        public static const QIZHI_STATE_NONE:int=-1;//不可见
        public static const QIZHI_STATE_SELF:int=0; //自己可见
        public static const QIZHI_STATE_TEAM:int=1;//队友可见
        public static const QIZHI_STATE_ALL:int=2;//全部可见
         
        //位置类型     
        public static const POSITION_NORAML:int=0;
        public static const POSITION_YING:int=1; //行营
        public static const POSITION_DABENYING:int=2; //大本营
         
        //布局移动
        public static const LAYOUT_MOVE_ALL:int=0;
        public static const LAYOUT_MOVE_LAST_TWO:int=1;//地雷只能在后两排
        public static const LAYOUT_MOVE_NOT_FRONT:int=2;//炸弹不能在前排铁道上
        public static const LAYOUT_MOVE_JUNQI:int=3;//军棋只能在大本营内
         
         
         
    }
}

 

三,核心类设计

3.1 Position类

棋盘由4个layout与一个centerarea组成,每个layout有30个位置,包括25个棋子位置与5个行营位置,centerarea包括9个行棋位置,棋盘共129个位置。位置的标识如上图所示,当用户进入棋局时,他的布局的索引就是 (30*玩家位置+具体位置)。这个逻辑就相当清楚了。

下面看类的具体内容,我将解释直接写到了类内部。

 

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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package com.boyiju.game.siguo.vo
{
 
    import com.boyiju.game.siguo.util.Enum;
     
    import mx.collections.ArrayCollection;
    /**
     * 位置类,每个棋盘共129个位置,每个位置有不同的可移动目标,类型,编号等
     * 每个位置将对应一个棋子类
     */
    [Bindable]
    public class PositionVO
    {
        /**
         *常量:可以直接移动的位置的集合,共30个
         */    
        public static const MOVE_ONE_STEP:Array=[new Array(1,6,7),new Array(0,2,7),new Array(1,3,7,8,9),new Array(2,4,9),new Array(3,5,9,10),new Array(4,11),new Array(0,12,7),new Array(0,1,2,6,8,12,13,14),new Array(2,7,9,14),new Array(2,3,4,8,10,14,15,16),new Array(4,9,11,16),null,new Array(6,7,13,18,19),new Array(7,12,14,19),new Array(7,8,9,13,15,19,20,21),new Array(9,14,16,21),new Array(9,10,15,17,21,22),new Array(11,16,23),new Array(12,19,24),new Array(12,13,14,18,20,24,25,26),new Array(14,19,21,26),new Array(14,15,16,20,22,26,27,28),new Array(16,21,23,28),null,new Array(18,19,25),new Array(19,24,26),new Array(19,20,21,25,27),new Array(21,26,28),new Array(21,22,27,29),new Array(23,28)];
         
        /**
         *常量:铁道线上的位置集合,横7条,竖七条,外加拐弯的4条,共18条
         */    
        public static const MOVE_RAIL:Array=[new Array(118,112,106,100,94),new Array(114,108,102,96,90),new Array(4,3,2,1,0,122,121,120,84,85,86,87,88),new Array(12,125,124,123,72),new Array(28,27,26,25,24,128,127,126,60,61,62,63,64),new Array(30,36,42,48,54),new Array(34,40,46,52,58),new Array(28,22,16,10,4),new Array(24,18,12,6,0),new Array(34,33,32,31,30,128,125,122,114,115,116,117,118),new Array(42,127,124,121,102),new Array(2,7,9,14),new Array(58,57,56,55,54,126,123,120,90,91,92,93,94),new Array(4,9,11,16),new Array(60,66,72,78,84),new Array(64,70,76,82,88)];
 
         
        private var _index:int=-1;
        /**
         *棋子位置的类型 如营或大本营
         */    
        public var type:int;
         
        /**
         *棋子绘制的开始位置
         */    
        public var startX:int;
        public var startY:int;
         
         
        /**
         *可移动位置的索引
         */    
        public var moveAC:ArrayCollection=new ArrayCollection();
        public var moveRailAC:ArrayCollection=new ArrayCollection();
         
        public function get index():int
        {
            return _index;
        }
        /**
         *位置的索引,作为一个联机游戏,用户在桌子上的位置就是索引的,在进入游戏时,索引已经固定(0-129)。
         * 通过索引可以得到可以移动的全部目标子位,棋子的类型,布局的位置索引(0-30)
         * @param value
         *
         */
        public function set index(value:int):void
        {
            _index = value;
            var layoutindex:int = value%30;
            if (_index<120)
            {
                startX=Math.floor(layoutindex/6)*37.5+5;
                startY=Math.floor(layoutindex%6)*30+10;
            }
            else
            {
                startX=Math.floor(layoutindex/3)*75+7.5;
                startY=Math.floor(layoutindex%3)*75+7.5;   
            }
            type=getType(layoutindex);
            initMoveAC(layoutindex);
            initMoveRoad(index);
        }
        /**
         *可以直接移动的子位,不需要判断中间是否有间隔
         * @param layoutindex
         *
         */    
        private function initMoveAC(layoutindex:int):void
        {
            moveAC.removeAll();
            var tempAC:ArrayCollection=new ArrayCollection(MOVE_ONE_STEP[layoutindex]);
            moveAC.addAll(tempAC);
            var basecount:int=_index-layoutindex;
            if (moveAC.length>0)
            {
                for (var i2:int=0;i2<moveAC.length;i2++)
                {
                    moveAC[i2]=moveAC[i2]+basecount;
                }
            }
             
        }
        /**
         *铁道线上的位置索引,如果该子包括在线路中,则将铁路放到索引中。
         * @param index
         *
         */    
        private function initMoveRoad(index:int):void{
            moveRailAC.removeAll();
            for (var i:int=0;i<MOVE_RAIL.length;i++)
            {
                if (MOVE_RAIL[i].indexOf(index)>=0)
                {
                    var tempAC:ArrayCollection=new ArrayCollection(MOVE_RAIL[i]);
                    if (tempAC.contains(_index))
                    {
                        moveRailAC.addItem(tempAC);
                    }
                }
            }
        }
        /**
         *获得当前位置的类型,如棋,大本营,行营等。
         * @param layoutindex
         * @return
         *
         */
        private function getType(layoutindex:int):int{
            var type:int;
            if (layoutindex==7||layoutindex==9||layoutindex==14||layoutindex==19||layoutindex==21)
            {
                type=Enum.POSITION_YING;
            }
            else if (layoutindex==11||layoutindex==23)
            {
                type=Enum.POSITION_DABENYING;
            }
            else
            {
                type=Enum.POSITION_NORAML;
            }
            return type;
        }
 
    }
}

 

3.2 QizhiVO类

棋子是棋局的基本组成部分,在布局阶段,我们会为用户在除行营外的位置上放置一些默认的棋子作为初始值,一共25个,也就是说,一个棋局只可能有100个棋子,并且会慢慢减小。现在,我们就来描述具体的棋子类。棋子的核实属性,也就是与服务器进行交互的只有3个,位置,值,与玩家,扩展显示的有一些,如名称,背景,位置的起始值等。棋子的方法包括 与其它棋子比较大小,移动到目标位置,与目标位置的棋子碰撞等。现在,我们围绕这个设计棋子类。

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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
package com.boyiju.game.siguo.vo
{
    import asds.map.HashMap;
     
    import com.boyiju.game.siguo.components.Qizhi;
    import com.boyiju.game.siguo.util.Enum;
     
    import mx.collections.ArrayCollection;
     
    /**
     *棋子类,每个棋子核心数值仅包括棋子的值,棋子的位置,棋子是否显示与棋子的玩家,
     * 其它的辅助值主要用于交互与显示,将通过核心值获得并可进行绑定显示
     */
    [Bindable]
    public class QizhiVO
    {
        private var _value:int=-1;
        private var _deskpos:int=-1;           
        private var _display:int=-1;
     
        public var positionVO:PositionVO;
        public var name:String;
        public var bgColor:int;
        public var layoutMoveType:int;
         
         
        public function get display():int
        {
            return _display;
        }
         
        public function set display(value:int):void
        {
            _display = value;
        }
         
        public function get deskpos():int
        {
            return _deskpos;
        }
         
         
        public function set deskpos(value:int):void
        {
            _deskpos = value;
            this.bgColor=getColor(value);
        }
         
        public function get value():int
        {
            return _value;
        }
         
        public function set value(value:int):void
        {
            _value = value;
            this.name=getQizhiName(value);
            this.layoutMoveType=getLayoutMoveType(value);
        }
 
        private function isTeam(deskpos:int):Boolean
        {
            var teamdeskpos:int=(this.deskpos+2)%4;
            return deskpos==teamdeskpos;
        }
        /**
         *获得棋子的显示名称,与棋子的显示类进行绑定
         * @param value
         * @return
         *
         */    
        private function getQizhiName(value:int):String{
            if (value==40) return "司令";
            if (value==39) return "军长";
            if (value==38) return "师长";
            if (value==37) return "旅长";
            if (value==36) return "团长";
            if (value==35) return "营长";
            if (value==34) return "连长";
            if (value==33) return "排长";
            if (value==32) return "工兵";
            if (value==31) return "地雷";
            if (value==30) return "军棋";
            if (value==100) return "炸弹";
            return "";
        }
        /**
         *棋子的颜色,通过棋子的玩家获得
         * @param player
         * 玩家
         * @return
         * 颜色值
         *
         */    
        private function getColor(player:int):int{
            if (player==0) return Enum.COLOR_PLAYER_BOTTOM;
            else if(player==1) return Enum.COLOR_PLAYER_RIGHT;
            else if (player==2) return Enum.COLOR_PLAYER_TOP;
            else if (player==3) return Enum.COLOR_PLAYER_LEFT;
            return 0x000000;
        }
        /**
         * 棋子本身在布局阶段的移动限制
         * @param value 棋子的值
         * @return
         *
         */    
        private function getLayoutMoveType(value:int):int{
             
            if (value==Enum.QIZHI_GONGBING) return Enum.LAYOUT_MOVE_LAST_TWO;
            if (value==Enum.QIZHI_ZHADAN) return Enum.LAYOUT_MOVE_NOT_FRONT;
            if (value==Enum.QIZHI_DILEI) return Enum.LAYOUT_MOVE_JUNQI;
            return Enum.LAYOUT_MOVE_ALL;
        }
         
        /**
         * 与目标棋子比较大小
         * @param target
         * @return
         *
         */    
        public function Compare(target:QizhiVO):int
        {
            if (this.value==Enum.QIZHI_ZHADAN||target.value==Enum.QIZHI_ZHADAN||this.value==target.value)
            {
                trace("很壮烈,您的 "+this.name+" 与敌人的 "+target.name+" 同归于尽");
                return 0;
            }
            if (target.value==Enum.QIZHI_DILEI&&this.value!=Enum.QIZHI_GONGBING||this.value<target.value)
            {
                trace("很悲剧,您的 "+this.name+" 被敌人的 "+target.name+" 吃掉了");
                 
                return -1;
            }
            if (this.value>target.value)
            {
                trace("很爽,您的 "+this.name+" 吃掉了敌人的 "+target.name);
                return 1;
            }
            return 1;
        }
         
        /**
         *布局阶段与目标棋子交换
         * @param target
         *
         */    
        public function exchange(target:QizhiVO):void
        {
            if (target==null) return;
            if (target.value==-1) return;
            if (target.deskpos!=this.deskpos) return;
             
            //军棋只能放大本营
            if (this.layoutMoveType==Enum.LAYOUT_MOVE_JUNQI)
            {
                if (target.positionVO.index==11)
                {
                     
                }else if (target.positionVO.index==23)
                {
                     
                }
                else
                    return;
            }
            if (target.layoutMoveType==Enum.LAYOUT_MOVE_JUNQI)
            {
                if (this.positionVO.index==11)
                {
                     
                }else if (this.positionVO.index==23)
                {
                     
                }
                else
                    return;
            }
            //地雷只能放在后两排
            if (this.layoutMoveType==Enum.LAYOUT_MOVE_LAST_TWO)
            {
                if (target.positionVO.index%6<4) return;
            }
            if (target.layoutMoveType==Enum.LAYOUT_MOVE_LAST_TWO)
            {
                if (this.positionVO.index%6<4) return;
            }
            //炸弹不能放在第一排三个位置
            if (this.layoutMoveType==Enum.LAYOUT_MOVE_NOT_FRONT)
            {
                if (target.positionVO.index==0||target.positionVO.index==12||target.positionVO.index==24) return;
            }
            if (target.layoutMoveType==Enum.LAYOUT_MOVE_NOT_FRONT)
            {
                if (this.positionVO.index==0||this.positionVO.index==12||this.positionVO.index==24) return;
            }
            var temp:int=target.value;
            target.value=this.value;
            this.value=temp;
        }
         
        /**
         * 可否移动到目标位置,主要包括棋子的可移动性,棋子的移动目标值,目标位置的内容等。
         * @param targetPos
         * @param qizhiMap
         * @return
         *
         */    
        public function canMoveTo(targetPos:PositionVO,qizhiMap:HashMap):Boolean{
             
            //位置无法移动
            if (this.positionVO.moveAC.length==0||this.value==Enum.QIZHI_DILEI||this.value==Enum.QIZHI_JUQI)
            {
                trace("该位置无法移动:"+this.positionVO.index);
                return false;
            }
            //目标位置不在可移动区内
            if (!this.positionVO.moveAC.contains(targetPos.index))
            {
                if (this.positionVO.moveRailAC.length==0){
                    trace(targetPos.index+" 不在该位置的可移动路径内:"+this.positionVO.index);
                    return false;
                     
                }
                for each (var railAC:ArrayCollection in this.positionVO.moveRailAC)
                {
                         
                        var targetindex:int=railAC.getItemIndex(targetPos.index);
                        //目标棋子不在铁路中
                        if (targetindex==-1) continue;
                        //目标棋子在铁路中.再找原始棋子的位置
                        var sourceindex:int=railAC.getItemIndex(this.positionVO.index);
                        //从原始棋子到目标棋子的通路中没有其它子
                         
                        if (sourceindex>targetindex)
                        {
                            for(var i:int=targetindex+1;i<sourceindex;i++)
                            {
                                //到达目标区的通路有其它的棋子
                                var qizhiVO:QizhiVO=qizhiMap.get(railAC.getItemAt(i)) as QizhiVO;
                                if (qizhiVO.value!=-1)
                                {
                                    trace("路径不通:"+qizhiVO.positionVO.index+" 有子 "+qizhiVO.name);                    return false;
                                }
                                trace("经过:"+qizhiVO.positionVO.index);
                                 
                                 
                            }
                             
                        }
                        else
                        {
                            for(var j:int=sourceindex+1;j<targetindex;j++)
                            {
                                //到达目标区的通路有其它的棋子
                                var qizhiVO2:QizhiVO=qizhiMap.get(railAC.getItemAt(j)) as QizhiVO;
                                if (qizhiVO2.value!=-1)
                                {
                                    trace("路径不通:"+qizhiVO2.positionVO.index+" 有子 "+qizhiVO2.name);
                                    return false;
                                }
                                trace("经过:"+qizhiVO2.positionVO.index);
                                 
                            }
                             
                        }
                        trace(this.name+" 从 "+this.positionVO.index+ " 移动至:"+targetPos.index);
                        return true;
                         
                }
                     
            }
             
            trace(this.name+" 从 "+this.positionVO.index+ " 移动至:"+targetPos.index);
            return true;
             
        }
         
        /**
         * 与目标棋子碰撞
         * @param target
         * @return
         *
         */    
        public function eat(target:QizhiVO,qizhiMap:HashMap):int{
            //不能吃自己的子
            if (target==null)
            {
                return -6;
            }
            if (target.value==-1)
            {
                trace( "目标位置无棋子");
                return -5;
            }
            if (target.deskpos==this.deskpos)
            {
                trace( "不能吃自己的子");
                 
                return -4;
            }
            //不能吃队友的子
            if (isTeam(target.deskpos))
            {
                trace( "位于"+target.positionVO.index+" 的棋子是您的队友的 "+target.name);
                 
                return -3;
            }
            if (!canMoveTo(target.positionVO,qizhiMap))
            {
                return -2;
            }
            //比较大小
            return this.Compare(target);
             
        }
         
    }
}

 

 

 

3.3 GameEngine 游戏控制类

游戏控制类用于对游戏进行调试,设计为一个全局类,包括了游戏进行必需的一些内容,如桌主,等待时间,游戏状态,游戏棋子集合,当前玩家,当前布局,当前选中棋子等内容。充分利用flex的绑定机制,将显示部分与控制部分结合。

 
 
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package com.boyiju.game.siguo.model
{
 
    import asds.map.HashMap;
     
    import com.adobe.cairngorm.model.IModelLocator;
    import com.boyiju.game.siguo.components.LayoutSelect;
    import com.boyiju.game.siguo.components.Qizhi;
    import com.boyiju.game.siguo.util.Enum;
    import com.boyiju.game.siguo.vo.LayoutVO;
    import com.boyiju.game.siguo.vo.PositionVO;
    import com.boyiju.game.siguo.vo.QizhiVO;
    import com.boyiju.game.siguo.vo.UserVO;
     
    import mx.collections.ArrayCollection;
    import mx.core.FlexGlobals;
     
    /**
     *四国军棋游戏的全局控制类,使用了cairngoarm类设计
     */
     
    [Bindable]
    public class GameEngine implements IModelLocator
    {
        private static var _model:GameEngine;
             
         
         
        public var gameOwner:int;//游戏桌主
                 
        public var gameWaitTime:int=30;//等待时间 秒    
         
        public var gameStatus:int;//游戏状态
         
         
        public var currentPlayer:UserVO;//当前玩家
        public var currentTurn:int;//当前回合玩家
        public var currentSelectedQZ:Qizhi; //选中的棋子
         
         
        public var sourceQZ:Qizhi;   //源棋子,用于棋子之间产鲜红用
         
         
        public var layoutAC:ArrayCollection;//布局文件组合
        public var currentLayout:LayoutVO;//当前布局文件
         
        public var playerAC:HashMap; //玩家组合
         
         
        public var qizhiMap:HashMap; //所有棋子有组合,与服务器交互的主要类
         
         
         
        /**
         *初始化四国军棋棋局
         * @param enforcer
         *
         */    
        public function GameEngine(enforcer:SingletonEnforcer) {   
             
            gameStatus=Enum.GAME_LAYOUT;
             
            layoutAC=new ArrayCollection();
            layoutAC.addItem(new LayoutVO("守型",LayoutSelect.LAYOUT_COOL,"偏防守"));
            layoutAC.addItem(new LayoutVO("攻型",LayoutSelect.LAYOUT_HOT,"偏进攻"));
            layoutAC.addItem(new LayoutVO("基本",LayoutSelect.LAYOUT_NORMAL,"攻守平衡"));
            currentLayout=layoutAC.getItemAt(0) as LayoutVO;
             
            qizhiMap=new HashMap();
            playerAC =new HashMap();
             
            createAndInitUser();
            currentPlayer=playerAC.get(0) as UserVO;
        }
        /**
         *将布局文件添加到全局布局列表中
         * @param layout
         *
         */    
        public function addLayout(layout:LayoutVO,deskpos:int):void{
             
            for (var i:int=0;i<layout.lyAC.length;i++)
            {
                if (layout.lyAC[i]!=-1)
                {
                    var positionVO:PositionVO=new PositionVO();
                    positionVO.index=30*deskpos+i;
                    var qizhiVO:QizhiVO=new QizhiVO();
                    qizhiVO.value=(layout.lyAC[i]);
                    qizhiVO.deskpos=deskpos;
                    qizhiVO.positionVO=positionVO;
                    qizhiMap.put(qizhiVO.positionVO.index,qizhiVO);
                }
            }
        }
         
        public static function get intance():GameEngine
        {
            if (_model ==null) {
                _model=new GameEngine(new SingletonEnforcer());
            }
            return _model;
        }
        /**
         *测试用,加入一些用户
         *
         */    
        private function createAndInitUser():void {
            var user:UserVO=new UserVO();
            user.name="张柏枝";
            user.picture="assets/images/zbz.jpg";
            user.score=0;
            user.win=0;
            user.lost=0;
            user.points=2100;
            user.deskpos=0;
            playerAC.put(user.deskpos,user);
            user=new UserVO();
            user.name="王菲";
            user.picture="assets/images/wf.jpg";
            user.score=0;
            user.win=0;
            user.lost=0;
            user.points=500;
            user.deskpos=1;
            playerAC.put(user.deskpos,user);
            user=new UserVO();
            user.name="林志玲";
            user.picture="assets/images/lzl.jpg";
            user.score=0;
            user.win=0;
            user.lost=0;
            user.points=2250;
            user.deskpos=2;
            playerAC.put(user.deskpos,user);
            user=new UserVO();
            user.name="阿娇";
            user.picture="assets/images/aj.jpg";
            user.score=0;
            user.win=0;
            user.lost=0;
            user.points=350;
            user.deskpos=3;
            playerAC.put(user.deskpos,user);
        }
        /**
         *获得下一位玩家,
         * @param num
         * @return
         *
         */    
        public function getNextUser(num:int):UserVO{
            var nextid:int=(currentPlayer.deskpos+num)%4;
            return playerAC.get(nextid) as UserVO;
        }
         
    }
     
}
class SingletonEnforcer
{
     
}
3.4 LayoutVO 类 布局文件类
布局文件类是个更简单的类,他包括一个名称,目录,及30个棋子位置的子的集合,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    [Bindable]   
public class LayoutVO   
{       
 
public var name:String;       
public var lyAC:ArrayCollection;       
public var catalog:String;    
            
public function LayoutVO(name:String,lyAC:Array,catalog:String)       
{          
 this.name=name;           
this.lyAC=new ArrayCollection(lyAC);          
 this.catalog=catalog;       
 
}

一个典型的博命型的划攻布局可以描述如下。够简单了吧,看看我们下QQ游戏的布局文件,几个K,我汗。。

public static const LAYOUT_HOT:Array=[40,39,38,38,37,37,36,-1,100,-1,36,30,35,35,-1,34,34,34,33,-1,33,-1,33,32,32,32,31,31,31,100];

四)下一节可能做的工作

核心部分基本就包括在这四个类内,应该来讲够简单吧,最终完成的效果如图

sg3_2s

下一节我来设计显示的部分及游戏进行中的逻辑部分,显示的部分就是把控件拉来拉去,加上绑定机制。你会觉得更简单的:),同时,下节打算做出第一个测试版本swf文件供大家测试一下。

posted @   博弈居  阅读(1865)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)

我的微博

点击右上角即可分享
微信分享提示