时间:2015-12-20 22:19:03 所属分类:软件开发 浏览量:
1、 引言 黑白棋, 又叫反棋 (Reversi)、 奥赛罗棋 (Othello)、 苹果棋、 翻转棋。 黑白棋在西方和日本很流行。 黑白棋的棋盘是一个有 8*8 方格的棋盘。 开始时在棋盘正中有两白两黑 4 个棋子交叉放置, 黑棋总是先下子。 游戏通过相互翻转对方的棋子(当自
1、 引言
黑白棋, 又叫反棋 (Reversi)、 奥赛罗棋 (Othello)、 苹果棋、 翻转棋。 黑白棋在西方和日本很流行。 黑白棋的棋盘是一个有 8*8 方格的棋盘。 开始时在棋盘正中有两白两黑 4 个棋子交叉放置, 黑棋总是先下子。 游戏通过相互翻转对方的棋子(当自己放下的棋子在横 、 竖 、 斜 8 个方向內有一个自己的棋子, 则被夹在中间的全部翻转会成为自己的棋子), 如果玩家在棋盘上没有地方可以下子, 则该玩家对手可以连下。 最后以棋盘上谁的棋子多来判断胜负。 本文使用 Flash AS3 开发黑白棋游戏程序。 该游戏具有显示执棋方可以落棋子的位置提示功能和判断胜负功能。 在游戏过程中, 点击 “帮助” 按钮则显示执棋方可落子位置 (图片 表示可落子位置)。 游戏运行界面如图 1 所示。
2、 黑白棋游戏设计思路
2.1 棋子和棋盘
游戏开发时, 需要事先准备黑白两色棋子 (如图 2 所示)和棋盘图片, 这里设计棋子影片剪辑使用图 2 中 4 张图, 黑白两色棋子各一帧, 图片 (表示可落子位置) 第 3 帧, 游戏背景方格是第 4 帧。 游戏最初显示时, 棋盘上布满所有 64个棋子影片剪辑 (播放到第 4 帧), 游戏过程中根据需要每个棋子影片剪辑播放不同帧。 棋盘在设计时直接放在 Fla 文件的舞台上。
这里为了便于处理, 采用一个 qizi 二维数组用来存储棋盘上棋子状态, 一个 qipan 一维数组用来存储棋子影片。
2.2 翻转对方的棋子
需要从自己落子 (x1, y1) 为中心的横、 竖、 斜 8 个方向上判断是否需要翻转对方的棋子, 程序中由棋子影片剪辑 qi的 MouseEvent.CLICK 事件实现的。 在 MouseEvent.CLICK 事件中参数 event 对象含有被单击对象信息。 event.target 可以获取被单击棋子影片剪辑对象 thisQi。
剪辑对象 thisQi 位置像素信息 (thisQi.x, thisQi.y) 转换成棋盘坐标 (x1, y1)。 从左, 左上、 上、 右上、 右、 右下、 下、左下 8 个方向上调用过程 DirectReverse (x1, y1, dx, dy) 翻转对方的棋子。 而具体棋子的翻转由 FanQi (x, y) 实现。 FanQi (x,y) 修改数组 qizi 的 (x, y) 处保存棋盘上的棋子信息, 同时播放到指定帧。
private function FanQi(x, y:int):void {if (qizi[x][y] == BLACK) {qizi[x][y] = WHITE;qipan[8 * x + y].gotoAndStop(WHITE);//显示 WHITE 棋子图形} else {qizi[x][y] = BLACK;qipan[8 * x + y].gotoAndStop(BLACK);//显示 BLACK 棋子图形}
2.3 显示执棋方可落子位置
Can_go ( x1, y1) 从左 、 左上 、 上 、 右上 、 右 、 右下 、下、 左下 8 个方向上调用函数 CheckDirect (x1, y1, dx, dy) 判断某方向上是否形成夹击之势, 如果形成且中间无空子则返回True, 表示 (x1, y1) 可以落子。 (x1, y1) 处可以落子则用图片显示。
2.4 判断胜负功能
qizi 二维数组保存棋盘上的棋子信息 , 其中元素保存 1,表示此处为黑子; 元素保存 2, 表示此处为白子; 元素保存 0,表示此处为无棋子。 通过对 qizi 数组中各方棋子数统计, 在棋盘无处可下时, 根据各方棋子数判断出输赢。
3、 设计步骤
3.1 创建 Flash 文件
打开 Flash CS6 软件后, 选择 “文件” → “新建” 选项,系统将弹出 “新建文档” 窗口, 在窗口中选择 “ActionScript3.0” 选项。
3.1.1 设置文档属性
选择菜单 “修改”, 再选择 “文档” 选项, 调出 “文档属性” 对话框。 设置场景的尺寸为 720*780 像素, 背景颜色为浅绿色, 然后单击 “确定” 按钮。 在属性面板设置文档类为Main。
3.1.2 设计棋子影片剪辑元件
选择菜单 “插入” → “新建元件”。 在新弹出的 “新建元件” 窗口中, 将元件名称设置为 “棋子”, 将元件类型设置为“影片剪辑 ”, 单击 “确定 ” 按钮后 , Flash 界面将转变为 “棋子” 元件的编辑区。 导入图 2 所示 4 幅图, 注意每幅图大小80*80。
3.2 设计游戏文档类 (Main.as)
选择 “文件” → “新建” 选项, 系统将弹出 “新建文档”窗口。 在窗口中选择 “ActionScript 文件” 选项。 这样在 Flash中新建一个 ActionScript 类文件, 将其命名为 Main.as。 导入包及相关类:
package {import flash.display.*;import flash.events.*;import flash.text.*;import flash.utils.Timer;类成员变量定义:public class Main extends MovieClip {//常量private static const BLACK:int = 1;private static const WHITE:int = 2;private static const KONG:int = 0;private var qizi:Array =new Array();//构造一个二维//数组用来存储棋子状态private var qipan:Array =new Array();//构造一个一//维数组用来存储棋子影片private var curQizi :int = BLACK;// 当前走棋方var hitTimer:Timer=new Timer(1000);//计时器,定时//清除提示图形
构造函数对保存棋盘上的棋子信息的 qizi 数组初始化, 实例化所有棋子影片对象。 同时在棋盘上显示初始的 4 个棋子。
public function Main():void {//构造函数var i,j:int;for (i=0; i<8; i++) {qizi[i]=new Array();for (j=0; j<8; j++) {qizi[i][j]=KONG;var qi:Qi=new Qi();//棋子实例qi.y=80*j+42;//确定位置qi.x=80*i+42;qi.gotoAndStop(4);//显示棋子图形qipan.push(qi);qi.addEventListener(MouseEvent.CLICK,clickQi);addChild(qi);//加到显示列表}}// 棋盘上初始 4 个棋子qizi[3][3] = WHITE;qipan[8 * 3 + 3].gotoAndStop(2);//显示白色棋子图形qizi[4][4] = WHITE;qipan[8 * 4 + 4].gotoAndStop(2);//显示白色棋子图形qizi[3][4] = BLACK;qipan[8 * 3 + 4].gotoAndStop(1);//显示黑色棋子图形qizi[4][3] = BLACK;qipan[8 * 4 + 3].gotoAndStop(1);//显示黑色棋子图形help_btn.addEventListener (MouseEvent.CLICK,clickHelp);message_txt.text="该黑棋走子";}
构造函数同时对所有的棋子影片对象和 “帮助” 按钮添加鼠标单击事件的侦听。 如果是 help_btn 按钮被单击, 则执行clickHelp 函数显示可以落子的位置提示。
public function clickHelp(event:MouseEvent) {showCanPosition();//显示可以落子的位置}
Show_Can_Position () 用图片 显示可以落子的位置 。 同时启动定时器控制图片 仅显示 1 秒钟。
private function showCanPosition():void {//显示可以落子的位置var i,j:int;var n:int = 0;//可以落子的位置统计for (i = 0; i <= 7; i++) {for (j = 0; j <= 7; j++) {if (qizi[i][j] == 0 && Can_go(i, j)) {n = n + 1;qipan[8 * i + j].gotoAndStop(3);//显示提示图形}}}hitTimer.start();hitTimer.addEventListener (TimerEvent.TIMER, clsCanPosition);}private function clsCanPosition(event:Event) {var i,j:int;for (i = 0; i <= 7; i++) {for (j = 0; j <= 7; j++) {if (qizi[i][j] == 0 && Can_go(i, j)) {qipan[8 * i + j].gotoAndStop(4);//显示背景图形}}}hitTimer.removeEventListener (TimerEvent.TIMER, clsCanPosition);}
如果是棋子影片对象 (此时显示是背景第 4 帧) 被单击,则此剪辑对象 thisQi 位置像素信息 (thisQi.x, thisQi.y) 可以转换成棋盘坐标 (x1, y1), 然后判断当前位置 (x1, y1) 是否可以放棋子 (符合夹角之势), 如果可以则此棋子影片对象调用gotoAndStop (curQizi) 显示自己棋子图形, 调用 FanALLQi (i, j)从左、 左上、 上、 右上等 8 个方向翻转对方的棋。 最后判断对方是否有棋可走, 如果对方可以走棋则交换走棋方。 如果对方不可以走棋, 则自己可以继续走棋, 直到双方都不能走棋, 显示输赢信息。
public function clickQi(event:MouseEvent) {var x1:int, y1:int;var thisQi:Qi = (event.target as Qi);// what Qi?x1=(thisQi.x-42)/80;y1=(thisQi.y-42)/80;if (Can_go(x1, y1)) {// 判断当前位置是否可以放棋子trace("can");qizi[x1][y1] = curQizi;FanALLQi(x1, y1);// 从 8 个方向翻转对方的棋qipan[8 * x1 + y1].gotoAndStop(curQizi);//显示棋子图形//统计棋盘已下棋子数量 nfor (x = 0; x <= 7; x++) {for (y = 0; y <= 7; y++) {if (qizi[x][y]! =0)n = n + 1;}}if(n==64){//棋盘已下满,显示输赢信息isLoseWin();return;}//判断对方是否有棋可走,如有交换走棋方if (curQizi==WHITE &&checkNext(BLACK)||curQizi==BLACK &&checkNext(WHITE)) {if (curQizi==WHITE) {curQizi=BLACK;message_txt.text="该黑棋走子";} else {curQizi=WHITE;message_txt.text="该白棋走子";}} else if (checkNext(curQizi)) {//判断自己是否有棋可走,如有,给出提示message_txt.text="对方无棋可走,请继续";} else {//双方都无棋可走,游戏结束,显示输赢信息isLoseWin();}//统计双方的棋子数量,显示输赢信息。} else {message_txt.text="不能落子! ";}}
Can_go (x1, y1) 从左, 左上、 上、 右上、 右、 右下 、 下 、左下 8 个方向判断 (x1, y1) 处可否落子。
private function Can_go(x1, y1:int):Boolean {//从左、左上、上、右上、右、右下、下、左下 8 个方//向判断if (CheckDirect(x1, y1, -1, 0) == true) return true;if (CheckDirect(x1, y1, -1, -1) == true) return true;if (CheckDirect(x1, y1, 0, -1) == true) return true;if (CheckDirect(x1, y1, 1, -1) == true) return true;if (CheckDirect(x1, y1, 1, 0) == true) return true;if (CheckDirect(x1, y1, 1, 1) == true) return true;if (CheckDirect(x1, y1, 0, 1) == true) return true;if (CheckDirect(x1, y1, -1, 1) == true) return true;}
checkNext (i:int) 验证参数代表的走棋方是否还有棋可走。
/中华人民共和国著作权法 @param i 代表走棋方,1 为黑方,2 为白方* @return true/false*/private function checkNext(i:int):Boolean {if ( Can_Num()>0) {return true;} else {return false;}}
Can_Num () 统计可以落子的位置数。
private function Can_Num():int {//统计可以落子的//位置数var i, j, n = 0;for (i = 0; i <= 7; i++) {for (j = 0; j <= 7; j++) {if (Can_go(i, j)) {n = n + 1;}}}return n;//可以落子的位置个数}
isLoseWin () 统计双方的棋子数量, 显示输赢信息。
// 显示输赢信息private function isLoseWin() {var whitenum:int = 0;var blacknum:int = 0;var n = 0,x,y:int;for (x = 0; x <= 7; x++) {for (y = 0; y <=7; y++) {if (qizi[x][y] ! = 0) {n = n + 1;if (qizi[x][y] == 2) {whitenum += 1;}if (qizi[x][y] == 1) {blacknum += 1;}}}}if (blacknum > whitenum) {message_txt.text=" 游戏结束黑方胜利,黑方:" +String (blacknum)+ " 白方 :" + String(whitenum);} else {message_txt.text=" 游戏结束白方胜利,黑方:" +String (blacknum)+ " 白方 :" + String(whitenum);}}
FanALLQi (int x1, int y1) 从左 、 左上 、 上 、 右上 、 右 、右下、 下、 左下 8 个方向翻转对方的棋子。
private function FanALLQi(x1, y1:int):void {//从左、左上、上、右上、右、右下、下、左下 8 个方//向翻转if (CheckDirect(x1, y1, -1, 0) == true) {DirectReverse(x1, y1, -1, 0);}if (CheckDirect(x1, y1, -1, -1) == true) {DirectReverse(x1, y1, -1, -1);}if (CheckDirect(x1, y1, 0, -1) == true) {DirectReverse(x1, y1, 0, -1);}if (CheckDirect(x1, y1, 1, -1) == true) {DirectReverse(x1, y1, 1, -1);}if (CheckDirect(x1, y1, 1, 0) == true) {DirectReverse(x1, y1, 1, 0);}if (CheckDirect(x1, y1, 1, 1) == true) {DirectReverse(x1, y1, 1, 1);}if (CheckDirect(x1, y1, 0, 1) == true) {DirectReverse(x1, y1, 0, 1);}if (CheckDirect(x1, y1, -1, 1) == true) {DirectReverse(x1, y1, -1, 1);}}
CheckDirect () 判断某方向上是否形成夹击之势 , 如果形成且中间无空子则返回 True。
private function CheckDirect (x1, y1, dx, dy:int):Boolean {var x, y:int;var flag:Boolean;x = x1 + dx;y = y1 + dy;flag = false;while (InBoard(x, y) && ! Ismychess(x, y) &&qizi[x][y] ! = 0) {x += dx;y += dy;flag = true;//构成夹击之势}if (InBoard(x, y) && Ismychess(x, y) && flag == true) {return true;//该方向落子有效}return false;}
DirectReverse () 针对已形成夹击之势某方向上的对方棋子进行翻转。
private function DirectReverse (x1, y1, dx, dy:int):void {var x, y:int;var flag:Boolean;x = x1 + dx;y = y1 + dy;flag = false;while (InBoard(x, y) && ! Ismychess(x, y) &&qizi[x][y] ! = 0) {x += dx;y += dy;flag = true;//构成夹击之势}if (InBoard(x, y) && Ismychess(x, y) && flag== true) {do {x -= dx;y -= dy;if ((x ! = x1 || y ! = y1)) {FanQi(x, y);}} while ((x ! = x1 || y ! = y1));}}
FanQi (int x, int y) 将存储 (x, y) 处棋子信息 qizi [x] [y]
的反色处理。
private function FanQi(x, y:int):void {if (qizi[x][y] == BLACK) {qizi[x][y] = WHITE;qipan[8 * x + y].gotoAndStop(WHITE);//显示棋子图形} else {qizi[x][y] = BLACK;qipan[8 * x + y].gotoAndStop(BLACK);//显示棋子图形}}
InBoard () 判断 (x,y) 是否在棋盘界内 , 如果在界内则返回真, 否则返回假。
private function InBoard(x,y :int):Boolean {if (x >= 0 && x <= 7 && y >= 0 && y <= 7) {return true;} else {return false;}}
至此就完成黑白棋游戏设计了, 运行程序效果如图 1 所示。
4、 结语
用 Flash ActionScript3.0 实现经典的黑白棋游戏基本功能,并且能够判断输赢, 如果用户可以进一步改进翻转效果和增加双方棋子数量提示, 则使得游戏更具吸引力。
转载请注明来自:http://www.zazhifabiao.com/lunwen/dzxx/rjkf/28236.html
上一篇:软件工程的合理设计开发及具体运用