as3.0滑动拼接游戏

游戏玩法:

这是一个拼图游戏,游戏的开始会在一个完整的图案上留下一个空缺的格子,玩家通过移动这个空缺周围的拼图来最终完成图案。

游戏主要思路:

一、先是将一幅外部的图像导入,然后进行将其进行切分。所谓的切分就是将其代表不同块的区域的复制给一个一个的Sprite

二、将块打乱顺序

三、然后为每一个Sprite加侦听器响应玩家点击。

四、实时判断是否游戏结束

准备工作:

元件:

只需准备一张外部图像文件名为“slidingimage.jpg

舞台设置:

一共有三帧。

第一帧:有一个开始按钮,实例名为startButton,帧代码为

stop();

startButton.addEventListener(MouseEvent.CLICK,clickStart);

function clickStart(event:MouseEvent) {

       gotoAndStop("play");

}

很容易理解,点击跳到第二帧,即游戏开始帧。

第二帧:帧代码为startSlidingPuzzle();即调用游戏主函数开始游戏。

第三帧:有一个重玩按钮,实例名为playAgainButton,帧代码为

playAgainButton.addEventListener(MouseEvent.CLICK,clickPlayAgain);

function clickPlayAgain(event:MouseEvent) {

       gotoAndStop("play");

}

点击重新开始游戏

类文件的编写

此游戏只有一个主类为SlidingPuzzle继承自MovieClip

package {

    //导入需要的包

       import flash.display.*;

       import flash.events.*;

       import flash.net.URLRequest;

       import flash.geom.*;//这个包有我们后面用到的Point

       import flash.utils.Timer;

       public class SlidingPuzzle extends MovieClip {

              static const pieceSpace:Number = 2;//定义了块之间的间距

              static const horizOffset:Number = 50;//定义了水平的偏移

              static const vertOffset:Number = 50;//定义了垂直的偏移

              // 定义了水平方向和垂直方向的块数量

              static const numPiecesHoriz:int = 4;

              static const numPiecesVert:int = 3;

              // 这个是游戏乱序过程模拟的步数

              static const numShuffle:int = 200;

              // 块滑动动画的步数和时间

              static const slideSteps:int = 10;

              static const slideTime:int = 250;

              // 块的尺寸,由于要根据图片的大小定,所以未赋值

              private var pieceWidth:Number;

              private var pieceHeight:Number;

              // 一个用来存块对象引用的数组

              private var puzzleObjects:Array;

              // 有关块移动的变量

              private var blankPoint:Point;//空白块的坐标

              private var slidingPiece:Object;//当前移动的块对象

              private var slideDirection:Point;//块移动的点

              private var slideAnimation:Timer;//移动动画的计时器

              //定义游戏开始函数

              public function startSlidingPuzzle() {

                     // 取整个图片最右下角的块为空白

                     blankPoint = new Point(numPiecesHoriz-1,numPiecesVert-1);

                     // 加载图片

                     loadBitmap("slidingimage.jpg");

              }

              // 定义加载函数

              public function loadBitmap(bitmapFile:String) {//参数为字符串类型用来接收图片文件名

                     var loader:Loader = new Loader();//定义Loader

                     loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadingDone);//Load类加侦听器,当加载完成时执行loadingDone函数。

                     var request:URLRequest = new URLRequest(bitmapFile);//定义URLRequest即图片资源的地址

                     loader.load(request);//Loader加载图片

              }

              // 定义当图片加载完成时执行的函数,作用主要是切分图像

              public function loadingDone(event:Event):void {

                     // 建立一个新对象来持有图像。此对象为Bitmap类,用他的目的是为了后面好对像素进行操作,来达到复制的目的。

                     var image:Bitmap = Bitmap(event.target.loader.content);

            //用图像高和宽分别除横纵的块数来获取块的大小

                     pieceWidth = image.width/numPiecesHoriz;

                     pieceHeight = image.height/numPiecesVert;

                     // 执行切图函数

                     makePuzzlePieces(image.bitmapData);

 

                    // 执行乱序

                     shufflePuzzlePieces();

              }

              // 定义切图的函数

              public function makePuzzlePieces(bitmapData:BitmapData) {//用一个参数来接收图像信息。这里要注意,我们并没有用Bitmap类的变量来作参数,而用BitmapData类型的。这是因为每一个Bitmap类实际上是由自己的BitmapData类来保存信息的,所以我们对其操作也是要用其BitmapData类。

                     puzzleObjects = new Array();//创建数组

            //下面还是经常用的方法:利用双重for循环来排列块

                     for(var x:uint=0;x<numPiecesHoriz;x++) {

                            for (var y:uint=0;y<numPiecesVert;y++) {

                                   // 当执行到空白块时,用continue命令跳过此次循环,那么这个位置就没有图案。

                                   if (blankPoint.equals(new Point(x,y))) continue;

                                   var newPuzzlePieceBitmap:Bitmap = new Bitmap(new BitmapData(pieceWidth,pieceHeight));//创建一个块的Bitmap位图

                                 newPuzzlePieceBitmap.bitmapData.copyPixels(bitmapData,new Rectangle(x*pieceWidth,y*pieceHeight,pieceWidth,pieceHeight),new Point(0,0));//将指定的像素拷贝到这个位图

                                   var newPuzzlePiece:Sprite = new Sprite();//创建一个Sprite

                                   newPuzzlePiece.addChild(newPuzzlePieceBitmap);//将刚才创建的位图加入到Sprite

                                   addChild(newPuzzlePiece);//Sprite放到舞台上

                                   // 设置块的坐标

                                   newPuzzlePiece.x = x*(pieceWidth+pieceSpace) + horizOffset;

                                   newPuzzlePiece.y = y*(pieceHeight+pieceSpace) + vertOffset;

                                   // 为每个块创建一个Object用来存储每个块的信息,包括当前坐标和目标位置坐标

                                   var newPuzzleObject:Object = new Object();

                                   newPuzzleObject.currentLoc = new Point(x,y);//当前位置坐标

                                   newPuzzleObject.homeLoc = new Point(x,y);//目标位置坐标

                                   newPuzzleObject.piece = newPuzzlePiece;//所持有的块对象的引用

                                   newPuzzlePiece.addEventListener(MouseEvent.CLICK,clickPuzzlePiece);为每个块加侦听

 

                                   puzzleObjects.push(newPuzzleObject);将此Object加入到数组中

                            }

                     }

              }

              // 定义乱序的函数

              public function shufflePuzzlePieces() {

                     for(var i:int=0;i<numShuffle;i++) {

                //执行乱序

                            shuffleRandom();

                     }

        }

              public function shuffleRandom() {

                     // 循环所有可移动的块,用validMove函数来判断是否可移动,然后用validPuzzleObjects数组来存储所有可移动的块

                     var validPuzzleObjects:Array = new Array();

                     for(var i:uint=0;i<puzzleObjects.length;i++) {

                            if (validMove(puzzleObjects[i]) != "none") {

                                   validPuzzleObjects.push(puzzleObjects[i]);

                            }

                     }

                     // validPuzzleObjects数组中所有可以动的块中随机选出一个进行移动

                     var pick:uint = Math.floor(Math.random()*validPuzzleObjects.length);

                     movePiece(validPuzzleObjects[pick],false);//调用movePiece移动函数,这个函数有两个参数第一个是要移动块的引用,第二个是一个布尔值,true为执行动画,false为不执行动画。因为我们现在是执行乱序不需要让玩家看到他的过程,所以我们选false

              }

//用来判断是否块可以动的函数,函数有返回值,且返回值为String类型

              public function validMove(puzzleObject:Object): String {

                     // 用来判断空白点是否在此块的上面,如果是返回”up

                     if ((puzzleObject.currentLoc.x == blankPoint.x) &&

                            (puzzleObject.currentLoc.y == blankPoint.y+1)) {

                            return "up";

                     }

                     //用来判断空白点是否在此块的下面,如果是返回”down

                     if ((puzzleObject.currentLoc.x == blankPoint.x) &&

                            (puzzleObject.currentLoc.y == blankPoint.y-1)) {

                            return "down";

                     }

                     //用来判断空白点是否在此块的左面,如果是返回”left

                     if ((puzzleObject.currentLoc.y == blankPoint.y) &&

                            (puzzleObject.currentLoc.x == blankPoint.x+1)) {

                            return "left";

                     }

 

                    //用来判断空白点是否在此块的右面,如果是返回”right

                     if ((puzzleObject.currentLoc.y == blankPoint.y) &&

                            (puzzleObject.currentLoc.x == blankPoint.x-1)) {

                            return "right";

                     }

                     // 如果此块上下左右都不可移动则返回”none

                     return "none";

              }

              // 响应玩家点击的函数

              public function clickPuzzlePiece(event:MouseEvent) {

                     // puzzleObjects数组里找到当前点击的对象然后执行movePiece函数(块动画函数),并跳出循环。这时我们注意movePiece函数第二个参数为true,说明我们需要让玩家看到块的动画。

                     for(var i:int=0;i<puzzleObjects.length;i++) {

                            if (puzzleObjects[i].piece == event.currentTarget) {

                                   movePiece(puzzleObjects[i],true);

                                   break;

                            }

                     }

              }

              // 定义移动函数movePiece

              public function movePiece(puzzleObject:Object, slideEffect:Boolean) {

                     // 通过validMove函数获取空白块与当前块的相对关系并执行movePieceInDirection函数来实现移动,movePieceInDirection函数第二个和第三个参数分别代表相对坐标。可以举个例子,当空白块在当前块的上方,空白y坐标为2,当前应为3,当移动之后块当前变为2,即减一,所以我们传入-1值。

                     switch (validMove(puzzleObject)) {

                            case "up":

                                   movePieceInDirection(puzzleObject,0,-1,slideEffect);

                                   break;

                            case "down":

                                   movePieceInDirection(puzzleObject,0,1,slideEffect);

                                   break;

                            case "left":

                                   movePieceInDirection(puzzleObject,-1,0,slideEffect);

                                   break;

                            case "right":

                                   movePieceInDirection(puzzleObject,1,0,slideEffect);

                                   break;

                     }

              }

              // 定义movePieceInDirection函数

              public function movePieceInDirection(puzzleObject:Object, dx,dy:int, slideEffect:Boolean) {

                     //将相对坐标加到当前坐标上

puzzleObject.currentLoc.x += dx;

                     puzzleObject.currentLoc.y += dy;

            //空白点则正好相反,减去相对坐标

                     blankPoint.x -= dx;

                     blankPoint.y -= dy;

                     // 用来判断是否开启移动效果

                     if (slideEffect) {

                            // 执行动画函数startSlide

                           startSlide(puzzleObject,dx*(pieceWidth+pieceSpace),dy*(pieceHeight+pieceSpace));

                     } else {

                            // 如果不是仅仅是将坐标改变

                            puzzleObject.piece.x = puzzleObject.currentLoc.x*(pieceWidth+pieceSpace) + horizOffset;

                            puzzleObject.piece.y = puzzleObject.currentLoc.y*(pieceHeight+pieceSpace) + vertOffset;

                     }

              }

              // 定义动画函数

              public function startSlide(puzzleObject:Object, dx, dy:Number) {

                     if (slideAnimation != null) slideDone(null);//这句话的意思是当动画还在进行,但是玩家又点击了另外的块,为避免错误,这里强制停止了动画,即执行slideDone函数。

                     slidingPiece = puzzleObject;

                     slideDirection = new Point(dx,dy);

                     slideAnimation = new Timer(slideTime/slideSteps,slideSteps);//定义计时器,执行次数就是动画步数,而每次的间隔时间则是用动画时间除以动画步数

                     slideAnimation.addEventListener(TimerEvent.TIMER,slidePiece);//为计时器加一个侦听响应每次计时

                     slideAnimation.addEventListener(TimerEvent.TIMER_COMPLETE,slideDone);//为计时器加一个侦听响应其完成动画时的情况

                     slideAnimation.start();//启动计时器

              }

              //每步动画的移动

              public function slidePiece(event:Event) {

                     slidingPiece.piece.x += slideDirection.x/slideSteps;

                     slidingPiece.piece.y += slideDirection.y/slideSteps;

              }

              // 执行动画完成函数

              public function slideDone(event:Event) {

            //这个语句主要应该有两个作用,一个是出现当前块正在移动,而玩家又点击其他块的情况时,我们进行强制停止动画,应该将块一次归位。另一个作用就是对完成移动动画的块位置进行修正,因为之前的动画会设计到浮点运算,会导致最后的位置偏移。

                     slidingPiece.piece.x = slidingPiece.currentLoc.x*(pieceWidth+pieceSpace) + horizOffset;

                     slidingPiece.piece.y = slidingPiece.currentLoc.y*(pieceHeight+pieceSpace) + vertOffset;

            //停止动画计时器,并将其引用指空。

                     slideAnimation.stop();

                     slideAnimation = null;

                     // 检测是否游戏结束,如果是跳到gameover帧,并清除所有块

                     if (puzzleComplete()) {

                            clearPuzzle();

                            gotoAndStop("gameover");

                     }

              }

              //定义检测函数。原理很简单,用for循环puzzleObjects数组的成员,如果出现当前位置不等于目标位置的情况则返回false,如果全都符合则最终返回true

              public function puzzleComplete():Boolean {

                     for(var i:int=0;i<puzzleObjects.length;i++) {

                            if (!puzzleObjects[i].currentLoc.equals(puzzleObjects[i].homeLoc)) {

                                   return false;

                            }

                     }

                     return true;

              }

              // 删除所有块的函数

              public function clearPuzzle() {

                     for (var i in puzzleObjects) {

                //删除对象和侦听

                            puzzleObjects[i].piece.removeEventListener(MouseEvent.CLICK,clickPuzzlePiece);

                            removeChild(puzzleObjects[i].piece);

                     }

                     puzzleObjects = null;//将数组置空

              }

       }

}

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值