一般2D的RPG人物移動有三種:
(一)背景固定,角色移動
(二)角色固定,背景移動
(三)角色移動,背景動态移動
第一種在移動端的遊戲比較少見,但在PC端的模拟類遊戲比較常見,因為螢幕較大,背景固定即可,角色在背景上移動;第二種在移動端比較多見,就是角色固定在螢幕中間,需要移動時隻需要移動背景同時播放角色跑步的動畫即可達到角色移動的效果;第三種是第一和第二種的結合,是如今最常見的方式,先是背景固定,角色自由移動,當移動到螢幕邊緣時,背景移動來擴大角色的視野,或者,先是角色居中背景移動,當背景将要離開螢幕邊緣時,角色再移動。
在這篇文章,我隻說說第二種方式的實作思路,因為第一種十分簡單沒什麼難度,而第三種又是第一第二種的結合,是以先掌握第二種,自然會了第一種,再兩種結合即可寫出。
假設有一個Bg類,這個類繼承顯示容器精靈egret.Sprite,這個類有一個公有成員stone石頭,這個石頭是阻礙物阻礙角色移動的。将這個Bg類執行個體化成一個bg變量。
假設有一個role顯示對象,這個對象固定顯示在螢幕中間。
因為我們是實作第二種移動方式,Bg這個背景需要移來移去,但是不是随便移的,需要點選背景某目标坐标時才移動,是以我們偵聽一下點選事件,當點選背景某個坐标時,調用bgHandle函數。
<span style="font-size:18px;"> this.bg.addEventListener(egret.TouchEvent.TOUCH_TAP, this.bgHandle, this);</span>
bgHandle函數用來确定基于bg錨點的位置移動點坐标,定義bg_move_x為移動點橫坐标,bg_move_y為移動點縱坐标,speed為背景速度速度,timeOnEnterFrame為移動過程的結束時間。
那麼bg_move_x和bg_move_y怎麼擷取呢?首先擷取點選背景的坐标evt.stageX和evt.stageY,然後計算橫坐标evt.stageX、this.player.x和縱坐标evt.stageY、this.player.y的偏移值,通過這兩個偏移值與目前背景位置this.bg.x和this.bg.y按相應移動方向計算出bg_move_x和bg_move_y即可。
獲得bg移動點後,偵聽幀事件,當背景未移動到移動點,不斷調用bgMove函數。
private bg_move_x:number = 0; //背景移動位置
private bg_move_y:number = 0; //背景移動位置
private speed:number = 0.3; //角色移動速度
private timeOnEnterFrame = 0; //最後角色移動動畫結束時間
public bgHandle(evt:egret.TouchEvent):void{
if(this.bg.hasEventListener(egret.Event.ENTER_FRAME) ){
this.bg.removeEventListener(egret.Event.ENTER_FRAME,this.bgMove,this);
}
this.timeOnEnterFrame = egret.getTimer(); //初始化最後角色移動動畫結束時間
if(evt.stageX > this.player.x){
this.bg_move_x = this.bg.x - (evt.stageX - this.player.x);
}
else if(evt.stageX < this.player.x){
this.bg_move_x = this.bg.x + (this.player.x - evt.stageX);
}
if(evt.stageY > this.player.y){
this.bg_move_y = this.bg.y - (evt.stageY - this.player.y);
}
else if(evt.stageY < this.player.y){
this.bg_move_y = this.bg.y + (this.player.y - evt.stageY);
}
this.bg.addEventListener(egret.Event.ENTER_FRAME,this.bgMove,this);
}
bgMove函數根據bg_move_x和bg_move_y的值作背景移動,每次背景隻移動【speed * (每次幀事件的開始時間 - 結束時間)】像素,直到到達目的地才取消移動幀事件。當玩家突然點選背景另一個坐标時,bgHandle函數會取消幀事件,重新計算bg_move_x和bg_move_y然後再重新偵聽移動幀事件來調用bgMove函數。
private bgMove(evt:egret.Event):void{
var now = egret.getTimer();
var pass = this.timeOnEnterFrame;
var time = now - pass;
if(this.bg.x > this.bg_move_x){
if((this.bg.x - this.speed * time) < this.bg_move_x ){
this.bg.x = this.bg_move_x;
}
else{
this.bg.x -= this.speed * time;
if(this.isStopMove()){
this.bg.x += this.speed * time;
}
}
}
else if(this.bg.x < this.bg_move_x){
if((this.bg.x + this.speed * time) > this.bg_move_x ){
this.bg.x = this.bg_move_x;
}
else{
this.bg.x += this.speed * time;
if(this.isStopMove()){
this.bg.x -= this.speed * time;
}
}
}
if(this.bg.y > this.bg_move_y){
if((this.bg.y - this.speed * time) < this.bg_move_y ){
this.bg.y = this.bg_move_y;
}
else{
this.bg.y -= this.speed * time;
if(this.isStopMove()){
this.bg.y += this.speed * time;
}
}
}
else if(this.bg.y < this.bg_move_y){
if((this.bg.y + this.speed * time) >this.bg_move_y ){
this.bg.y = this.bg_move_y;
}
else{
this.bg.y += this.speed * time;
if(this.isStopMove()){
this.bg.y -= this.speed * time;
}
}
}
this.timeOnEnterFrame = egret.getTimer();
if(this.bg.x == this.bg_move_x && this.bg.y == this.bg_move_y){
this.bg.removeEventListener(egret.Event.ENTER_FRAME,this.bgMove,this);
}
}
在bgMove函數中,有一個函數isStopMove(),這個函數用來判斷角色是否碰撞到背景裡的石頭障礙物,如果碰到傳回true,bgMove()根據傳回值來判斷背景是否移動。
private isStopMove():boolean{
if( this.bg.stone.hitTestPoint( this.player.x, this.player.y, true ) ){
return true;
}
else{
return false;
}
}
這幾段代碼就是基于egret遊戲引擎的RPG背景移動模拟角色移動的思路,其實代碼還能做優化得更加精簡,但是精簡也會變得難以看懂,是以這長長的代碼耐心看還是沒什麼難度的(前提是學過egret引擎)。