一般2D的RPG人物移动有三种:
(一)背景固定,角色移动
(二)角色固定,背景移动
(三)角色移动,背景动态移动
第一种在移动端的游戏比较少见,但在PC端的模拟类游戏比较常见,因为屏幕较大,背景固定即可,角色在背景上移动;第二种在移动端比较多见,就是角色固定在屏幕中间,需要移动时只需要移动背景同时播放角色跑步的动画即可达到角色移动的效果;第三种是第一和第二种的结合,是如今最常见的方式,先是背景固定,角色自由移动,当移动到屏幕边缘时,背景移动来扩大角色的视野,或者,先是角色居中背景移动,当背景将要离开屏幕边缘时,角色再移动。
在这篇文章,我只说说第二种方式的实现思路,因为第一种十分简单没什么难度,而第三种又是第一第二种的结合,所以先掌握第二种,自然会了第一种,再两种结合即可写出。
假设有一个Bg类,这个类继承显示容器精灵egret.Sprite,这个类有一个公有成员stone石头,这个石头是阻碍物阻碍角色移动的。将这个Bg类实例化成一个bg变量。
假设有一个role显示对象,这个对象固定显示在屏幕中间。
因为我们是实现第二种移动方式,Bg这个背景需要移来移去,但是不是随便移的,需要点击背景某目标坐标时才移动,所以我们侦听一下点击事件,当点击背景某个坐标时,调用bgHandle函数。
this.bg.addEventListener(egret.TouchEvent.TOUCH_TAP, this.bgHandle, this);
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引擎)。