浮動(dòng)區(qū)塊
首先來(lái)講一個(gè)小故事,關(guān)于浮動(dòng)的方塊的故事。或許你已經(jīng)聽(tīng)說(shuō)過(guò)了“移動(dòng)平臺(tái)”這個(gè)名字,不要迷惑,他們是一樣的東西,一樣有趣。
很久很久以前,在區(qū)塊游戲的世界里,住者一個(gè)年輕的方塊。他是一個(gè)快樂(lè)的方塊。有一天,他遇到了一個(gè)英雄。英雄問(wèn)他:“年輕人,為什么你不會(huì)浮動(dòng)呢?”
“我不知道怎么移動(dòng)……” 小方塊說(shuō)道。
“那真遺憾,”英雄說(shuō)道,“我想要站在你上面,去以前夠不到的地方。”
那一天之后,小方塊就不再像以前一樣開(kāi)心了。
其實(shí)我們可以幫助他浮動(dòng)的,看:
在我們開(kāi)工寫(xiě)代碼之前,我們還是先來(lái)考慮一下規(guī)則。
我們應(yīng)該做什么?如何做?
* 浮動(dòng)方塊應(yīng)該是云(cloud)類(lèi)型的方塊 (云) * 方塊可以橫向或縱向移動(dòng) * 英雄可以從上方落到上面 * 當(dāng)英雄站到上面以后,他會(huì)隨著方塊運(yùn)動(dòng) * 方塊上的英雄不能穿過(guò)障礙物
踏上浮動(dòng)的方塊
英雄怎么站到運(yùn)動(dòng)方塊上?第一個(gè)也是最簡(jiǎn)單的一個(gè)方法就是跳上去。
在上圖中,英雄正處于跌落的過(guò)程中,下一步他將會(huì)碰到運(yùn)動(dòng)方塊。我們將會(huì)把他放置到方塊上去。注意,英雄必須是在運(yùn)動(dòng)方塊的上方,而且必須是往下運(yùn)動(dòng),否則他就無(wú)法站到上面。
但是,這并不是英雄上去的唯一途徑。下圖中,英雄站在障礙物上,沒(méi)有移動(dòng)。
但是方塊是移動(dòng)的,而且接下來(lái)就會(huì)接觸到英雄,若不做任何處理,英雄就會(huì)“陷”到方塊里面。所以,我們要做的就是讓方塊帶者英雄一起往上移動(dòng)。
離開(kāi)運(yùn)動(dòng)的方塊
一旦我們的英雄可以站到方塊上,我們還要保證他能夠以某種方式離開(kāi)。首先,他可以跳開(kāi)。它可以走到方塊的邊緣。下圖畫(huà)出了許多可能的情形:
黨英雄站在豎直移動(dòng)的方塊上,而且上方有個(gè)障礙物時(shí),他應(yīng)該掉下來(lái),否則就會(huì)被壓扁。黨方塊水平移動(dòng),黨英雄碰到障礙物,他應(yīng)該被貼著障礙物放置;如果方塊移開(kāi)的話,英雄就會(huì)掉下去。
上圖中,英雄隨著方塊往下移動(dòng),黨他碰到障礙物的時(shí)候,他不再隨著方塊移動(dòng),而是停在障礙物上。而方塊則繼續(xù)往下移動(dòng)。
準(zhǔn)備工作
畫(huà)出移動(dòng)方塊的影片剪輯。你可以做很多種類(lèi)的移動(dòng)方塊,把他們放在 movingtiles 影片剪輯的不同幀,然后將剪輯連接為movingtiles
定義 movingtiles 對(duì)象:
game.MovingTilep1= function () {}; game.MovingTilep1.prototype.speed=2; game.MovingTilep1.prototype.dirx=0; game.MovingTilep1.prototype.diry=1; game.MovingTilep1.prototype.miny= 0; game.MovingTilep1.prototype.maxy=2; game.MovingTilep1.prototype.width=game.tileW/2; game.MovingTilep1.prototype.height=game.tileH/2; game.MovingTilep2= function () {}; game.MovingTilep2.prototype.speed=2; game.MovingTilep2.prototype.dirx=1; game.MovingTilep2.prototype.diry=0; game.MovingTilep2.prototype.minx= -2; game.MovingTilep2.prototype.maxx=2; game.MovingTilep2.prototype.width=game.tileW/2; game.MovingTilep2.prototype.height=game.tileH/2;
我們有兩種類(lèi)型的可移動(dòng)方塊: MovingTilep1可以豎直移動(dòng)(它的diry屬性為非0數(shù)值),MovingTilep2可以水平移動(dòng)(它的dirx值非0)。speed屬性,你一定猜到了,代表方塊一次移動(dòng)的像素距離。
miny/maxy/minx/maxx 屬性設(shè)置了方塊運(yùn)動(dòng)的邊界。我們當(dāng)然可以把邊界坐標(biāo)設(shè)置成絕對(duì)的數(shù)值范圍,但是如果需要把方塊放到別的地方的話,就要改動(dòng)邊界的范圍了。而在這里,我們用的是相對(duì)于方塊起始位置的數(shù)值。這樣我們可以把方塊放在任意的位置,而不用修改邊界范圍。需要注意的是,移動(dòng)的方塊不會(huì)檢測(cè)碰撞,所以你應(yīng)該確保他們運(yùn)動(dòng)時(shí)不撞到障礙物;蛘吣阋部梢栽试S他們穿過(guò)障礙物。你在做游戲,你就是上帝。
來(lái)看一個(gè)例子。方塊起始的位置是(x=2,y=5),豎直運(yùn)動(dòng),miny=-1,maxy=4。它會(huì)怎么運(yùn)動(dòng)呢?起始位置-miny=5+(-1)=4,所以最小可以到達(dá)的位置是(x=2,y=4),最大可以到達(dá)的位置是(x=2,y=9)。
方塊起始位置的數(shù)組和敵人起始位置的數(shù)組類(lèi)似:
//浮動(dòng)方塊數(shù)組 [方塊類(lèi)型, x位置, y位置] myMovingTiles = [ [0], [[1, 4, 2]], [[2, 4, 4]] ];
在地圖1中,我們定義了一個(gè)浮動(dòng)方塊,它的類(lèi)型編號(hào)是1(從MovingTile1模版創(chuàng)建),起始位置是(x=4,y=2)。地圖2中同樣有1個(gè)浮動(dòng)方塊。你也可以在一個(gè)地圖中放置多個(gè)浮動(dòng)方塊。
接下來(lái)是要在buildMap函數(shù)中添加浮動(dòng)方塊的生成代碼。在創(chuàng)建敵人部分后面加入:
game.movingtiles = myMovingTiles[game.currentMap]; for (var i = 0; i<game.movingtiles.length; ++i) { var name = "movingtile"+i; game[name]= new game["MovingTilep"+game.movingtiles[i][0]]; game.clip.attachMovie("movingtiles", name, 12001+i); game[name].clip=game.clip[name]; game[name].clip.gotoAndStop(game.movingtiles[i][0]); game[name].xtile = game.movingtiles[i][1]; game[name].ytile = game.movingtiles[i][2]; game[name].x = game[name].xtile *game.tileW+game.tileW/2; game[name].y = game[name].ytile *game.tileH+game.tileH/2; game[name].clip._x = game[name].x; game[name].clip._y = game[name].y; game[name].minx=game[name].minx+game[name].xtile; game[name].maxx=game[name].maxx+game[name].xtile; game[name].miny=game[name].miny+game[name].ytile; game[name].maxy=game[name].maxy+game[name].ytile; }
首先還是取得當(dāng)前地圖的浮動(dòng)方塊數(shù)組(第一句)。變量game.movingtiles保存了當(dāng)前地圖的浮動(dòng)方塊數(shù)據(jù),包括數(shù)目和方位。然后創(chuàng)建新的對(duì)象,放置mc到舞臺(tái)正確的位置,跳轉(zhuǎn)到相應(yīng)的幀。類(lèi)型1的方塊是第一幀,類(lèi)型2的方塊則是第二幀。代碼的最后一部分是計(jì)算浮動(dòng)方塊的運(yùn)動(dòng)范圍。雖然變量名稱還是miny/maxy/minx/maxx,但是這些屬性變成了確定的數(shù)字,和原先的含義(相對(duì)起始位置的坐標(biāo))已經(jīng)不同了(或者說(shuō)他們是絕對(duì)的坐標(biāo),使用的時(shí)候不需要再參考起始位置)。
在moveChar函數(shù)中,需要添加一行代碼,用來(lái)保存y坐標(biāo):
ob.lasty=ob.y;
在moveChar函數(shù)中還需要改寫(xiě)移動(dòng)功能的代碼:
if (diry == 1) { if (ob.downleft and ob.downright and !checkMovingTiles(speed*diry)) { ob.y += speed*diry; } else { ob.jump = false; if(ob.onMovingTile){ ob.y=ob.onMovingTile.y-ob.onMovingTile.height-ob.height; }else{ ob.y = (ob.ytile+1)*game.tileH-ob.height; } } }
我們使用了checkMovingTiles函數(shù),如果英雄將會(huì)降落在浮動(dòng)方塊上,這個(gè)函數(shù)會(huì)返回true。如果英雄馬上就要落在浮動(dòng)方塊上,我們?cè)O(shè)置他的y坐標(biāo)為剛好在方塊上面。
英雄在浮動(dòng)方塊上面嗎?
或許你已經(jīng)從moveChar函數(shù)中增加的部分看出來(lái)了,沒(méi)錯(cuò),我們需要?jiǎng)?chuàng)建一個(gè)新函數(shù),用來(lái)檢測(cè)角色是不是站在浮動(dòng)方塊上面。checkMovingTiles函數(shù)不僅僅返回答案(是或者不是),而且還把英雄所在浮動(dòng)方塊的名字保存到char對(duì)象中。
function checkMovingTiles (y) { if(char.diry<>-1){ var heroymax=char.y+char.height+y; var heroxmax=char.x+char.width; var heroxmin=char.x-char.width; foundit=false; for (var i = 0; i<game.movingtiles.length; i++) { var ob=game["movingtile"+i]; var tileymax=ob.y+ob.height; var tileymin=ob.y-ob.height; var tilexmax=ob.x+ob.width; var tilexmin=ob.x-ob.width; if(char.lasty+char.height<=tileymin){ if (heroymax<=tileymax and heroymax>=tileymin) { if (heroxmax>tilexmin and heroxmax<tilexmax) { char.onMovingTile=ob; foundit=true; break; } else if (heroxmin>tilexmin and heroxmin<tilexmax) { char.onMovingTile=ob; foundit=true; break; } } } } return(foundit); } }
讓我們看看發(fā)生了什么。如果角色不是往上運(yùn)動(dòng)(diry值不是-1),我們就計(jì)算出角色的邊界。然后遍歷浮動(dòng)方塊數(shù)組,看角色是否和當(dāng)前的浮動(dòng)方塊接觸:
帶有“l(fā)asty”屬性的if語(yǔ)句是用來(lái)確定角色的上一個(gè)位置是在浮動(dòng)方塊的上方,下面的兩個(gè)if語(yǔ)句則判斷角色是不是和方塊有接觸。如果有碰撞,那就意味著我們找到了正確的移動(dòng)方塊,于是onMovingTile屬性就會(huì)紀(jì)錄下找到的方塊對(duì)象。
讓他也動(dòng)起來(lái)
請(qǐng)準(zhǔn)備好看史上最丑陋最冗長(zhǎng)最小氣的函數(shù)!它很長(zhǎng),因?yàn)樗芏鄸|西。首先,它移動(dòng)所有的浮動(dòng)方塊,然后檢查這些方塊是不是需要反過(guò)來(lái)運(yùn)動(dòng)了,這些還不夠,它還要處理英雄在浮動(dòng)方塊上面的動(dòng)作,檢查是不是應(yīng)該掉下來(lái)。
function moveTiles () { for (var i = 0; i<game.movingtiles.length; i++) { var ob=game["movingtile"+i]; getMyCorners (ob.x + ob.speed*ob.dirx, ob.y + ob.speed*ob.diry, ob) if (ob.miny>ob.upY or ob.maxy<ob.downY) { ob.diry=-ob.diry; } if (ob.minx>ob.leftX or ob.maxx<ob.rightX) { ob.dirx=-ob.dirx; } ob.x = ob.x + ob.speed*ob.dirx; ob.y = ob.y + ob.speed*ob.diry; ob.xtile = Math.floor(ob.x/game.tileW); ob.ytile = Math.floor(ob.y/game.tileH); ob.clip._x = ob.x; ob.clip._y = ob.y; if(ob.diry==-1){ checkMovingTiles(0); } } //check if hero is on moving tile if(char.onMovingTile){ getMyCorners (char.x, char.y+char.onMovingTile.speed*char.onMovingTile.diry, char); if (char.onMovingTile.diry == -1) { if (char.upleft and char.upright) { char.y=char.onMovingTile.y-char.onMovingTile.height-char.height; } else { char.y = char.ytile*game.tileH+char.height; char.jumpspeed = 0; char.jump = true; char.onMovingTile=false; } } if (char.onMovingTile.diry == 1) { if (char.downleft and char.downright) { char.y=char.onMovingTile.y-char.onMovingTile.height-char.height; } else { char.onMovingTile=false; char.y = (char.ytile+1)*game.tileH-char.height; } } getMyCorners (char.x+char.onMovingTile.speed*char.onMovingTile.dirx, char.y, char); if (char.onMovingTile.dirx == -1) { if (char.downleft and char.upleft) { char.x += char.onMovingTile.speed*char.onMovingTile.dirx; } else { char.x = char.xtile*game.tileW+char.width; fall (char); } } if (char.onMovingTile.dirx == 1) { if (char.upright and char.downright) { char.x += char.onMovingTile.speed*char.onMovingTile.dirx; } else { fall (char); char.x = (char.xtile+1)*game.tileW-char.width; } } updateChar (char); } }
和上面說(shuō)的一樣,第一部分的代碼用來(lái)移動(dòng)浮動(dòng)方塊。遍歷所有的浮動(dòng)方塊,把它們下一步的坐標(biāo)和miny/maxy(minx/maxx)屬性對(duì)照,看是否需要反過(guò)來(lái)運(yùn)動(dòng)。
這幾行代碼:if(ob.diry==-1){ checkMovingTiles(0); } 用來(lái)檢查是否要載上英雄,注意滿足的條件是英雄站在障礙物的邊緣上不動(dòng),而且方塊是朝上運(yùn)動(dòng)(diry是-1)。
在這行以下的函數(shù)部分:if(char.onMovingTile){ 用來(lái)處理英雄在浮動(dòng)方塊上的動(dòng)作。當(dāng)onMovingTile值不是false,意味著英雄站在某個(gè)浮動(dòng)的方塊上面,而且onMovingTile屬性值就是所在的浮動(dòng)方塊對(duì)象。這里的代碼和moveChar函數(shù)比較相似。我們利用getMyCorners函數(shù)計(jì)算英雄下一步的位置,如果沒(méi)有碰到任何障礙物,就讓英雄和方塊一起運(yùn)動(dòng);反之則不能把英雄移動(dòng)過(guò)去。
使用函數(shù)
在detectKeys函數(shù)的開(kāi)頭加入這行語(yǔ)句,用來(lái)移動(dòng)所有的浮動(dòng)方塊(即使英雄沒(méi)有踩在它們上面):
moveTiles();
另外,當(dāng)英雄起跳的時(shí)候,我們還要讓他的onMovingTile屬性變回false:
ob.onMovingTile=false;
下載源文件
出處:藍(lán)色理想
責(zé)任編輯:qhwa
上一頁(yè) 拾取物品 下一頁(yè) 卷屏
◎進(jìn)入論壇Flash專(zhuān)欄 版塊參加討論