最近花了两周的时间研究了如何用JS开发一个类似梦幻西游,英雄联盟这种操作模式的Web游戏,通过鼠标右键点击行走,并且地图可以跟随人物的移动而不断的移动。
看一下效果:
http://www.njhhsj.com/Game/Jianye/
操作:右键点击移动
http://www.njhhsj.com/Game/mxd/
操作,A键左移,D键右移,空格键攻击。
这个demo的开发花了我挺长时间的,也参考了许多论坛上游戏爱好者的思维方式。
下面我将总结一下我开发过程中是如何实现的,防止以后自己忘了,哈哈~,主要是几个我花了很长时间思考的部分。
主要展示三个部分:
在总结前先给出一张我的思考图,如图把一张地图划分成九个区域,分别标上字母,灰色地区为窗口区域。
A、B、C、D分别为窗口的左上、左下、右下、右上的四分之一区域,并且在A、B、C、D区域中可以自由移动,人物初始化时在A区中。
以X轴方向移动为例:
1.从A进入D1区域(两条竖着的红线之间的区域)并且继续往右移动时,先到达窗口的二分之一位置也就是红线所在位置,停止人物的移动,切换成地图往左移动,当地图往左一直移动到右边界时,人物进入D区域切换成自由移动,地图到达最右边停止移动。
2.当往左移动时,从D进入D1区域,方法一样,而当人物在D1区域左右移动时中,只需要往反方向移动地图即可,之后再判断是否进入左右边界即可。
人物在Y轴上移动原理是一样的。
var last_X = 500 // 当前人物图片X轴坐标
,last_Y = 300 // 当前人物图片Y轴坐标
,Des_x = 547 // 需要人物图片X轴坐标
,Des_y = 395 // 需要人物图片Y轴坐标
,Cur_x = 547 // 人物脚底需要移动到的X坐标
,Cur_y = 395 // 人物脚底需要移动到的坐标
,Orz_x = 547 // 当前人物脚底X坐标
,Orz_y = 395 // 当前人物脚底Y坐标
,n = 0
,img_url
,m_role_mx = 0 // X轴速度分量
,m_role_my = 0 // Y轴速度分量
,angle
,mapx_shift = 0 // 地图X轴移动量
,mapy_shift = 0 // 地图Y轴移动量
,PI = 3.141592653
,SPEED = 6
,dtn = null
,inlx = 0 // 人物X轴移动量
,inly = 0 // 人物Y轴移动量
,angle_D;
当点击地图时获取人物的X,Y轴的偏移量inlx,inly,然后分别进行人物X,Y轴的区域判断,分别进行加操作,偏移量为0结束移动,
// 角色移动
MoveRole : function(){
var _this = gameMonitor;
// 人物X轴状态
if(inlx > 0){
// A区域
if(Orz_x < w/2 && Orz_x > 0 && gameMonitor.mapX == 0 && gameMonitor.mapY == 0){
inlx -= Math.abs(m_role_mx);
last_X += m_role_mx;
Orz_x += m_role_mx;
if(Orz_x > w/2){
Orz_x = w/2;
}
// B区域
}else if(Orz_x < w/2 && Orz_x > 0 && gameMonitor.mapX == 0 && gameMonitor.mapY == -(_this.bgHeight-h)){
inlx -= Math.abs(m_role_mx);
last_X += m_role_mx;
Orz_x += m_role_mx;
// C区域
}else if(Orz_x > w/2 && Orz_x < w && gameMonitor.mapY == -(_this.bgHeight-h) && gameMonitor.mapX == -(_this.bgWidth-w)){
inlx -= Math.abs(m_role_mx);
last_X += m_role_mx;
Orz_x += m_role_mx;
// D区域
}else if(Orz_x > w/2 && Orz_x < w && gameMonitor.mapY == 0 && gameMonitor.mapX == -(_this.bgWidth-w)){
inlx -= Math.abs(m_role_mx);
last_X += m_role_mx;
Orz_x += m_role_mx;
// A1区域
}else if(Orz_x < w/2 && Orz_x > 0 && gameMonitor.mapX == 0 && gameMonitor.mapY < 0 && gameMonitor.mapY > -(_this.bgHeight-h)){
inlx -= Math.abs(m_role_mx);
last_X += m_role_mx;
Orz_x += m_role_mx;
if(Orz_x > w/2){
Orz_x = w/2;
}
// C1区域
}else if(Orz_x > w/2 && Orz_x < w && gameMonitor.mapX == -(_this.bgWidth-w) && gameMonitor.mapY < 0 && gameMonitor.mapY > -(_this.bgHeight-h)){
inlx -= Math.abs(m_role_mx);
last_X += m_role_mx;
Orz_x += m_role_mx;
// E区域地图移动
}else{ // 人物X轴超出窗口一半区域
Orz_x = w/2;
mapx_shift = inlx;
inlx = 0;
}
}else{
inlx = 0;
}
// 人物Y轴状态
if(inly > 0){
// A区域
if(0 < Orz_y && Orz_y < h/2 && gameMonitor.mapX == 0 && gameMonitor.mapY == 0){
inly -= Math.abs(m_role_my);
last_Y += m_role_my;
Orz_y += m_role_my;
if(Orz_y > h/2){
Orz_y = h/2;
}
// B区域
}else if(h/2 < Orz_y && Orz_y < h && gameMonitor.mapX == 0 && gameMonitor.mapY == -(_this.bgHeight-h)){
inly -= Math.abs(m_role_my);
last_Y += m_role_my;
Orz_y += m_role_my;
// C区域
}else if(Orz_y > h/2 && Orz_y < h && gameMonitor.mapY == -(_this.bgHeight-h) && gameMonitor.mapX == -(_this.bgWidth-w)){
inly -= Math.abs(m_role_my);
last_Y += m_role_my;
Orz_y += m_role_my;
// D区域
}else if(Orz_y > 0 && Orz_y < h/2 && gameMonitor.mapY == 0 && gameMonitor.mapX == -(_this.bgWidth-w)){
inly -= Math.abs(m_role_my);
last_Y += m_role_my;
Orz_y += m_role_my;
if(Orz_y > h/2){
Orz_y = h/2;
}
// D1区域
}else if(0 < Orz_y && Orz_y < h/2 && gameMonitor.mapY == 0 && gameMonitor.mapX < 0 && gameMonitor.mapX > -(_this.bgWidth-w)){
inly -= Math.abs(m_role_my);
last_Y += m_role_my;
Orz_y += m_role_my;
if(Orz_y > h/2){
Orz_y = h/2;
}
// B1区域
}else if(Orz_y > h/2 && Orz_y < h && gameMonitor.mapY == -(_this.bgHeight-h) && gameMonitor.mapX < 0 && gameMonitor.mapX > -(_this.bgWidth-w)){
// console.log("B1区域"+Orz_y)
inly -= Math.abs(m_role_my);
last_Y += m_role_my;
Orz_y += m_role_my;
// E区域地图移动
}else{
Orz_y = h/2;
mapy_shift = inly;
inly = 0;
}
}else{
inly = 0;
}
_this.MoveRoleImage(); // 人物八方位移动图切换
// 绘制角色
_this.hero.paint(img_url,last_X,last_Y);
},
地图的移动X,Y轴是从(0,0)到(-(地图宽度-窗口宽度),-(地图高度-地图高度))这个范围。
当地图接收到偏移量mapx_shift,mapy_shift之后,开始移动,知道偏移量为0结束移动。
// 地图移动
MoveImage : function(ctx){
var _this = gameMonitor;
//地图X轴需要移动
if(mapx_shift > 0){
mapx_shift -= Math.abs(m_role_mx);
gameMonitor.mapX -= m_role_mx;
if(gameMonitor.mapX > 0){
gameMonitor.mapX = 0;
}
if(gameMonitor.mapX < (-(_this.bgWidth-w))){
gameMonitor.mapX = (-(_this.bgWidth-w));
}
if(gameMonitor.mapX == 0){ // 到达左边界
_this.IsLeftBorder();
}
if(gameMonitor.mapX == (-(_this.bgWidth-w))){ // 到达右边界
_this.IsRightBorder();
}
}else{
mapx_shift = 0;
}
//地图Y轴需要移动
if(mapy_shift > 0){
mapy_shift -= Math.abs(m_role_my);
gameMonitor.mapY -= m_role_my;
if(gameMonitor.mapY > 0){
gameMonitor.mapY = 0;
}
if(gameMonitor.mapY < (-(_this.bgHeight-h))){
gameMonitor.mapY = (-(_this.bgHeight-h));
}
if(gameMonitor.mapY == 0){ // 到达上边界
_this.IsTopBorder();
}
if(gameMonitor.mapY == (-(_this.bgHeight-h))){ // 到达下边界
_this.IsBottomBorder();
}
}else{
mapy_shift = 0;
}
// 绘制背景
ctx.drawImage(img, gameMonitor.mapX, gameMonitor.mapY);
},
当进行跨区域操作时将人物偏移量inlx,inly赋值给地图的偏移量mapx_shift,mapy_shift让地图继续接替运动。
当人物进入到自由移动区域时,同样将地图偏移量mapx_shift,mapy_shift返给人物偏移量inlx,inly,接替运动。
// 是否在左边界
IsLeftBorder : function(){
var _this = gameMonitor;
console.log("=====进入左边界====")
Orz_x = w/2 - 1;
inlx = mapx_shift;
if(mapy_shift > 0){
inly = mapy_shift;
}
mapx_shift = 0;
mapy_shift = 0;
},
// 是否在右边界
IsRightBorder : function(){
var _this = gameMonitor;
console.log("====进入右边界====")
Orz_x = w/2 + 1;
inlx = mapx_shift;
if(mapy_shift > 0){
inly = mapy_shift;
}
mapx_shift = 0;
mapy_shift = 0;
},
// 是否在上边界
IsTopBorder : function(){
var _this = gameMonitor;
console.log("====进入上边界====")
Orz_y = h/2 - 1;
if(mapx_shift > 0){
inlx = mapx_shift;
}
inly = mapy_shift;
mapx_shift = 0;
mapy_shift = 0;
},
// 是否在下边界
IsBottomBorder : function(){
var _this = gameMonitor;
console.log("====进入下边界====")
Orz_y = h/2 + 1;
if(mapx_shift > 0){
inlx = mapx_shift;
}
inly = mapy_shift;
mapx_shift = 0;
mapy_shift = 0;
},
最后再分享一个参考链接,这篇文章我也看了三四遍,由于语言不同,理解起来也不同。
https://blog.csdn.net/crocodile__/article/details/18039107