背景:梦幻西游;人物:逍遥生;场景:北俱芦洲。
游览行为:点击鼠标,人物行走。右键也能使人物转向。由于我只找到了人物四个方向的素材,所以如果刚好正对人物位置的水平或垂直方向,走起来会有些别扭,如果用八方图,code上只要再加正东南西北四个方向即可。一共使用了2张图片,一张是人物的四方图,一张是场景图,场景图用于设为body背景。
贴上一部分效果图,你可以在本文结尾下载整个demo。
先贴上Common类,主要就是通用的操作,如取元素位置,取鼠标位置,我的很多文章里都用到的。
Common<script type="text/javascript">
var Common = {
getElementPos: function(el) {
el = this.getItself(el);
var _x = 0, _y = 0;
do {
_x += el.offsetLeft;
_y += el.offsetTop;
} while (el = el.offsetParent);
return { x: _x, y: _y };
},
getItself: function(id) {
return "string" == typeof id ? document.getElementById(id) : id;
},
getMousePos: function(ev) {
ev = ev || window.event;
if (ev.pageX || ev.pageY) {
return {
x: ev.pageX,
y: ev.pageY
};
}
if (document.documentElement && document.documentElement.scrollTop) {
return {
x: ev.clientX + document.documentElement.scrollLeft - document.documentElement.clientLeft,
y: ev.clientY + document.documentElement.scrollTop - document.documentElement.clientTop
};
}
else if (document.body) {
return {
x: ev.clientX + document.body.scrollLeft - document.body.clientLeft,
y: ev.clientY + document.body.scrollTop - document.body.clientTop
};
}
}
}
</script>
贴上Walker类,
代码<script type="text/javascript">
var Class = {
create: function() {
return function() { this.init.apply(this, arguments); }
}
}
var Walker = Class.create();
Walker.prototype = {
init: function(_src, _walkerSize, initPos) {
//人物朝向,值与人物图片的行数要对应。譬如说图片第1行是朝向SouthWest的,则this.direction.SouthWest值为1
this.direction = { SouthEast: 0, SouthWest: 1, NorthEast: 2, NorthWest: 3 };
this.currentDirection = this.direction.SouthEast; //当前人物朝向
this.speed = 0.5; //默认速度:每次移动0.5px 通过此和起点终点距离算出移动总次数(总帧数)
this.walkFlag = this.moveFlag = null;
this.walkerSize = _walkerSize;
this.walker = document.createElement("div");
this.walker.style.cssText = "position:absolute;width:" + this.walkerSize.w + ";height:" + this.walkerSize.h + ";clip:rect(0px " + this.walkerSize.w + "px " + this.walkerSize.h + "px 0px)";
document.body.appendChild(this.walker);
this.img = document.createElement("img");
this.img.src = _src;
this.img.style.position = "absolute";
this.walker.appendChild(this.img);
this.walker.style.left = initPos.x + "px";
this.walker.style.top = initPos.y + "px";
},
setWalkStatus: function(row, col) {//col=0设置为该方向的初始状态。row值与方向direction一致
this.img.style.left = -col * this.walkerSize.w + "px";
this.img.style.top = -row * this.walkerSize.h + "px";
},
getDirection: function(mousePos) {
var dir = 0;
var initPos = Common.getElementPos(this.walker);
initPos.x = initPos.x + this.walkerSize.w / 2, initPos.y = initPos.y + this.walkerSize.h / 2;
if (mousePos.y < initPos.y) {//上方
if (mousePos.x > initPos.x) { //东北
dir = this.direction.NorthEast;
}
else { //西北
dir = this.direction.NorthWest;
}
}
else { //下方
if (mousePos.x > initPos.x) { //东南
dir = this.direction.SouthEast;
}
else { //西南
dir = this.direction.SouthWest;
}
}
this.currentDirection = dir;
},
beginWalk: function(mousePos) {
this.getDirection(mousePos);
var row = this.currentDirection;
this.setWalkStatus(row, 1);
var walkerObj = this;
var tmp = 1;
this.walkFlag = setInterval(function() {
tmp = tmp > 3 ? 0 : tmp;
//walkerObj.img.style.left = -walkerObj.walkerSize.w * tmp + "px";
walkerObj.setWalkStatus(row, tmp);
tmp++;
},
200);
},
stopWalk: function() {
clearInterval(this.walkFlag);
clearInterval(this.moveFlag);
this.setWalkStatus(this.currentDirection, 0);
},
walk: function(e) {
//停止当前动作
this.stopWalk();
var mousePos = Common.getMousePos(e);
this.beginWalk(mousePos);
this.move(this.walker, { x: mousePos.x - this.walkerSize.w / 2, y: mousePos.y - this.walkerSize.h / 2 });
},
setDirection: function(e) {
this.getDirection(Common.getMousePos(e));
this.setWalkStatus(this.currentDirection, 0);
},
timer: 10,
move: function(obj, targetPos) {
var currentCount = 0;
var elPos = Common.getElementPos(obj);
var initPos = { x: elPos.x, y: elPos.y }
var distance = Math.sqrt(Math.abs(targetPos.x - initPos.x) * Math.abs(targetPos.x - initPos.x) + Math.abs(targetPos.y - initPos.y) * Math.abs(targetPos.y - initPos.y));
var count = Math.ceil(distance / this.speed);
var tmpWalkObj = this;
var Func = Tween.Linear;
this.moveFlag = setInterval(function() {
if (currentCount > count) {
tmpWalkObj.stopWalk();
}
else {
currentCount++;
var tmpX = Func(initPos.x, targetPos.x, currentCount, count);
var tmpY = Func(initPos.y, targetPos.y, currentCount, count);
obj.style.left = tmpX + "px";
obj.style.top = tmpY + "px";
//清除小数点的误差
if (Math.abs(tmpX - targetPos.x) < 1) {
obj.style.left = targetPos.x + "px";
}
if (Math.abs(tmpY - targetPos.y) < 1) {
obj.style.top = targetPos.y + "px";
}
//边界控制
if (parseInt(obj.style.left) < 0) {
obj.style.left = 0 + "px";
}
if (parseInt(obj.style.top) < 0) {
obj.style.top = 0 + "px";
}
if (parseInt(obj.style.left) + tmpWalkObj.walkerSize.w > 1024) {//场景图片尺寸:1024*764
tmpWalkObj.stopWalk();
}
if (parseInt(obj.style.top) + tmpWalkObj.walkerSize.h > 764) {
tmpWalkObj.stopWalk();
}
}
}
, this.timer);
}
}
var Tween = {
Linear: function(initPos, targetPos, currentCount, count) {
var b = initPos, c = targetPos - initPos, t = currentCount, d = count;
return c * t / d + b;
}
}
</script>
人物行走如何实现呢?3步。
在这3步之前,当然会用init方法初始化1个div做为容器,来存放这个人物图片,所谓的人物行走就是这个div在移动。(细节见code的注释)
1. 显示人物四方图的某一块小图。
本例的四方图是4*4=16个人物形态构成,就是要显示具体的1个人物形态。实现方法:setWalkStatus。由于外部容器div的尺寸只是1个人物形态的尺寸,通过设置人物图片的left和top值,就能显示图片中第row行第col列的人物。
2.让人物动起来。
实现方法:beginWalk。通过setInterval循环执行setWalkStatus方法就能实现同一行的四个动作连贯显示。人物就动起来了。
3.让动起来的人物移动。
鼠标点击后移动,要首先算出朝哪个方向移动,从而显示那个方向的人物图片,方法:getDirection。
移动的主要code在move方法里。如何move和Js动画(一)基础所说的move原理一样,但是又不能照搬,因为那里的move是自己设置总帧数从而控制时间,达到设置移动快慢的目的。而这里,人物的移动肯定永远是匀速的,行走的距离长自然执行的总次数多,时间也就越长。所以原先自定义的count数要算出来,移动总次数=人物行走的总距离(像素)/速度(每1次移动speed像素),其他照旧。然后添加一些人物移动的边界限制。
文档加载后初始化逍遥生及注册逍遥生行为事件。
代码<script type="text/javascript">
window.onload = function() {
var 逍遥生 = new Walker("walker2.png", { w: 70, h: 92 }, { x: 100, y: 50 });
document.documentElement.onclick = function(e) {
逍遥生.walk(e);
}
document.documentElement.oncontextmenu = function(e) {
if (document.all) {
window.event.returnValue = false;
}
else {
if (e.preventDefault) {
e.preventDefault();
e.stopPropagation();
}
}
逍遥生.setDirection(e);
}
}
</script>
其中,var 逍遥生 = new Walker("walker2.png", { w: 70, h: 92 }, { x: 100, y: 50 }); 第一个参数是人物图片,第二个参数是单个人物形态尺寸,70=图片宽度280/4,第三个参数是,人物的出生地。
毕了。
点击下载