JavaScript动漫作品(闭幕)

笔者:Steven Riche

发布时间:2014年2一个月18

原文链接:http://code.tutsplus.com/tutorials/javascript-animation-that-works-part-4-of-4--net-35263

翻译:子毅 --------- 将JavaScript进行究竟

碎碎两句

折腾了一个多月。杂七杂八的事情加在一起。简直糟透了。

博客停了大概有一个月了,从今天起一切都是新的,做好自己就OK了

----------------------------------------------------------------------------------------------

在本系列的

p=35205">第一篇文章中,我们介绍了用精灵在web上创建简单、跨浏览器的可交互动画。在第二篇文章中,我们让动画工作起来,而在第三篇文章中,我们整理好我们的代码,并为它在web上使用做好准备

介绍

如今,在我们的最后一部分中,我们将通过建立事件处理程序,而不是在点击button时机器人做出响应,我们的机器人将在屏幕上尾随着鼠标而移动。

在这个过程中。我们将讨论跨浏览器的代码,而且触摸屏也可用

假如你看一下我们上一次的代码。你能够看到,虽然我们的代码执行得非常好(而且同一时候有多个机器人),然而这里没有一个简单的方式来执行代码。

事件处理程序

事件处理程序是这种命令,当特定的事件触发时,它告诉某些代码运行。比如,不论什么时候,你能够让一个用户点击有“my_div‘ id的‘div’时,‘my_function()‘运行。

或者,当用户在‘my_other_div‘上移动鼠标时。‘my_other_function()‘运行

理论上,这个一个相当简单且直观的主意。不幸的是,当你卷入 不同的浏览器,这将会有一点迷惑。理想情况下,每一个浏览器都会以相同的方式在解释代码,而开发人员将仅仅写须要写一次代码就能够让每一个用户看到相同的结果。在真实世界中,不同的浏览器可能会有全然不同的命名来做同一件事(*咳**咳* IE),所以有时候想要一段代码在全部的浏览器中都执行得一样。会让人认为像是在放牧一群猫。近期。情况已经变得非常好了,Chrome,Firefox, Safgari,Opera对代码的响应已经非常相似了,IE9和IE10已经变得比早期的版本号更加符合标准。而且差点儿没有人在使用IE7和IE6了。因此,我们代码将使得事件处理程序在现代浏览器和IE8种可工作

作为一方面的说明。这是一种使用一个强大JavaScript库的原因,比方jQuery。

jQuery已经为你做好了全部的跨浏览器測试,因此,你仅仅须要输入一个命令,jQuery会在幕后翻译它使得它在每一个浏览器中都可用。此外,很多jQuery命令都比核心JavaScript更加直观、简单。

可是,因为我的固执,而且这是一次学习的机会,我们将继续在这条艰难的路上努力,仅仅用JavaScript来做这一切,不依赖不论什么库

页面交互

我们第一步要决定究竟将怎么和页面交互。

当我在舞台区域移动鼠标时。我想要全部的机器人朝着鼠标移动的方向跑。当它们抵达鼠标或者鼠标正好在它们上面,我想要它们停止移动。假如鼠标放在它们身上,我想要它们跳起来。

最后,当鼠标离开舞台,我想要它们停止跑动。我们将从绑定事件到RobotMaker函数内部開始。

stage.addEventListener(‘mousemove‘, stage_mousemove_listener, false);
robot.addEventListener(‘mouseover‘, robot_mouseover_listener, false);
stage.addEventListener(‘mouseout‘, stage_mouseout_listener, false);

因此。在上面的几行代码中,我们说过,不管什么时候用户在舞台(stage)元素上移动鼠标。将触发一个叫做stage_mousemove_listener()的函数(注意。在命令中。我们并没有包括參数)。相似地,当用户在robot元素上移动鼠标。将触发robot_mouseover_listener(),当用户从舞台上移开鼠标,触发stage_mouseout_listenr()

不幸的是,之前我们提到过,IE8及其低版本号使用不同(可是相似)的命令来做同样的事,因此,我们须要进行測试。以便知道用户的浏览器将会理解哪条命令,并运行对应的方法。

if (stage.addEventListener){ // We will test to see if this command is available
  stage.addEventListener(‘mousemove‘, stage_mousemove_listener, false);
  robot.addEventListener(‘mouseover‘, robot_mouseover_listener, false);
  stage.addEventListener(‘mouseout‘, stage_mouseout_listener, false);
} else { // If not, we have to use IE commands
  stage.attachEvent(‘onmousemove‘, stage_mousemove_listener);
  robot.attachEvent(‘onmouseover‘, robot_mouseover_listener);
  stage.attachEvent(‘onmouseout‘, stage_mouseout_listener);
}

你可能会注意到那些命令的格式很相似。可是还是有一些基本的差别:一个叫做‘addEventListener‘,一个叫做‘attachEvent‘,一个叫做‘mousemove‘,然而还有一个叫做‘onmousemove‘。一个须要第三个參数。而另个仅仅用了两个。

混淆它们之间的不论什么一个都会导致命令不运行。这一系列的事会使你实用脑袋撞墙的冲动。不幸的是,为了是具有跨浏览器的能力,这并非我们须要额外编写的最后代码

监听函数

接下来,我们将编写监听函数。

从编写用户在舞台上移动而触发的函数開始。

正由于它是一个mousemove侦听器,当鼠标每次在舞台区域内移动时,都将触发它(这意味着在一秒钟内将会触发多次)这个函数须要将机器人的位置和鼠标的位置作比較。并使机器人见机行事。每次函数触发,它将检測机器人须要继续朝同样的方向跑动。还是变换为其它行为。

因此,它须要像以下这样编写。

// Inside of RobotMaker

// We will need to introduce a few extra variables to track
var mouseX; // For tracking horizontal mouse position
var running_dir = ‘‘; // For tracking if (and where) robot is currently running
var stageOffset; // For tracking the position of the stage

function stage_mousemove_listener(e){

  // Find the horizontal position of the mouse inside of the stage ...
  // That position will be saved in ‘mouseX‘

  // Then we compare ‘mouseX‘ to the robot, and decide if we need to run differently
  if (((robot.offsetLeft + (15 * run_speed)) < (mouseX - robot.offsetWidth)) && running_dir !== ‘r‘ && (!jump_timer || jump_timer === undefined)){
    // If the mouse is in the stage and to the right of the robot, make run right, if not already
    running_dir = ‘r‘;
    clearTimeout(run_timer);
    run_r(1, robot.offsetLeft);
  } else if ((mouseX < robot.offsetLeft - (15 * run_speed)) && running_dir !== ‘l‘ && (!jump_timer || jump_timer === undefined)) {
    // If the mouse is in the stage and to the left of the robot, make run left, if not already
    running_dir = ‘l‘;
    clearTimeout(run_timer);
    run_l(1, robot.offsetLeft);
  } else if ((robot.offsetLeft < mouseX) && ((robot.offsetLeft + robot.offsetWidth) > mouseX) && running_dir !== ‘‘ && (!jump_timer || jump_timer === undefined)) {
    // If the mouse is in the stage and over a robot, stop and clear running_dir
    running_dir = ‘‘;
    clearTimeout(run_timer);
    if (face_right){
      robot.style.backgroundPosition = "0px 0px";
    } else {
      robot.style.backgroundPosition = "0px -50px";
    }
  }
  // If none of the above is true, then we let our current behavior continue
}

在上面的函数中。一旦我们找到mouseX,我们就能够和机器人的位置作比較,假设须要的话,触发或停止不同的跑动函数。

不幸的是,找出mouseX有一些棘手,由于鼠标位置是还有一件不同浏览器表现不同的事。

为避免找出mouseX而进行复杂冗长的解释。正如灵感来自优秀的Quirksmode博客 (这是一个学习很多其它高级JavaScript技术的伟大源地):

function stage_mousemove_listener(e){
  var posX = 0;
  if (!e){
    var e = window.event;
  }

  if (e.pageX) {
    posX = e.pageX;
  } else if (e.clientX) {
    posX = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
  }
  mouseX = posX - stageOffset.xpos; // 我们找到了mouseX!
}

我们有个叫做e的參数在函数中,虽然我们没有传递不论什么东西给它。可是这是一个事件侦听器,我们将自己主动拥有一个叫做e的变量,这个变量存储有和事件相关的信息,比方鼠标数据。可是不同浏览器存储的方式不同,我们不得不添加额外的一个步骤。

我们终于通过找到posX(鼠标在页面上的水平坐标)并用它减去stage左边距离页面的值(存储在stageOffset.xpos),进而找到mouseX,这给出了我们鼠标距离stage左边界的距离,而且我们能够用它直接和robot.offsetLeft作比較。依据布局,stage可能会位于不同的位置,我们相同须要找出stage精确的像素偏移,并将它存储在stageOffset中。幸运的是,我们能够使用一个巧妙的花招来找到元素的绝对偏移量,这个函数来自于Vishal
Astik的博客

// 在RobotMaker内
var x = 0;
var y = 0;
function find_stage_offset (el){
  x = el.offsetLeft;
  y = el.offsetTop;
  el = el.offsetParent;

  while(el !== null) {
    x = parseInt(x) + parseInt(el.offsetLeft);
    y = parseInt(y) + parseInt(el.offsetTop);
    el = el.offsetParent;
  }

  return {xpos: x, ypos: y};
}
var stageOffset = find_stage_offset(stage);

如今我们已经写好了mousemove侦听器,其它将会easy非常多。

对于机器人mouseover侦听器,我们仅仅须要检測机器人是否在跳跃,假设不是,停止跑动,使之跳跃。

function robot_mouseover_listener(){
  if (!jump_timer || jump_timer === undefined){
    clearTimeout(run_timer);
    jmp(true, robot.offsetTop);
  }
}

mouseout侦听器相同也非常easy。仅仅须要重置一些我们用来跟踪robot的变量,假如机器人没有跳跃,则将机器人置为站立的精灵

function stage_mouseout_listener(){
  mouseX = undefined;
  running_dir = ‘‘;
  if (!jump_timer || jump_timer === undefined){
    clearTimeout(run_timer);
    if (face_right){
      robot.style.backgroundPosition = "0px 0px";
    } else {
      robot.style.backgroundPosition = "0px -50px";
    }
  }
}

动画函数

这一次。跑跳运动函数并没有改变非常多。我们仅仅是增添了一些跟踪变量running_dir,取出机器人将要撞击到强的声明(由于这是mouseout函数的冗余。并添加一些代码到跳跃函数,它用于再次检測,假如鼠标仍在stage内,当机器人在跳跃后落下。它是否须要開始跑动。以下是终于的代码(相当大):

function run_r(phase, left){
  face_right = true;
  running_dir = ‘r‘;
  if ((left + (15 * run_speed)) < (mouseX - robot.offsetWidth)){ // if mouse is to the right, run

    left = left + (15 * run_speed);
    robot.style.left = left+"px";
    switch (phase){
      case 1:
        robot.style.backgroundPosition = "-40px 0px";
        run_timer = setTimeout(function(){run_r(2, left);}, 200);
        break;
      case 2:
        robot.style.backgroundPosition = "-80px 0px";
        run_timer = setTimeout(function(){run_r(3, left);}, 200);
        break;
      case 3:
        robot.style.backgroundPosition = "-120px 0px";
        run_timer = setTimeout(function(){run_r(4, left);}, 200);
        break;
      case 4:
        robot.style.backgroundPosition = "-80px 0px";
        run_timer = setTimeout(function(){run_r(1, left);}, 200);
        break;
    }
} else if ((left + (15 * run_speed)) < mouseX) { // if mouse if above, stop
    robot.style.backgroundPosition = "0px 0px";
    running_dir = ‘‘;
} else { // if mouse is to the left, run left
    running_dir = ‘l‘;
    run_l(1, robot.offsetLeft);
  }
}

function run_l(phase, left){
  face_right = false;
  running_dir = ‘l‘;
  if (mouseX < robot.offsetLeft - (15 * run_speed)){ // if mouse is to the left, run

    left = left - (15 * run_speed);
    robot.style.left = left+"px";
    switch (phase){
      case 1:
        robot.style.backgroundPosition = "-40px -50px";
        run_timer = setTimeout(function(){run_l(2, left);}, 200);
        break;
      case 2:
        robot.style.backgroundPosition = "-80px -50px";
        run_timer = setTimeout(function(){run_l(3, left);}, 200);
        break;
      case 3:
        robot.style.backgroundPosition = "-120px -50px";
        run_timer = setTimeout(function(){run_l(4, left);}, 200);
        break;
      case 4:
        robot.style.backgroundPosition = "-80px -50px";
        run_timer = setTimeout(function(){run_l(1, left);}, 200);
        break;
    }
} else if (mouseX < (robot.offsetLeft + robot.offsetWidth - (15 * run_speed))){ // if mouse overhead, stop
    robot.style.backgroundPosition = "0px -50px";
    running_dir = ‘‘;
} else { // if mouse is to the right, run right
    running_dir = ‘r‘;
    run_r(1, robot.offsetLeft);
  }
}

function jmp(up, top){
  running_dir = ‘‘;
  if (face_right){
    robot.style.backgroundPosition = "-160px 0px";
  } else {
    robot.style.backgroundPosition = "-160px -50px";
  }

  if (up && (robot.offsetTop > (20 * (1 / jump_height)))){
    top = top - (top * 0.1);
    robot.style.top = top+"px";
    jump_timer = setTimeout(function(){jmp(up, top);}, 60);
  } else if (up) {
    up = false;
    jump_timer = setTimeout(function(){jmp(up, top);}, 60);
  } else if (!up && (robot.offsetTop < 115)){
    top = top + (top * 0.1);
    robot.style.top = top+"px";
    jump_timer = setTimeout(function(){jmp(up, top);}, 60);
  } else {
    robot.style.top = "120px";
    if (face_right){
      robot.style.backgroundPosition = "0px 0px";
    } else {
      robot.style.backgroundPosition = "0px -50px";
    }

    jump_timer = false;
    if (mouseX !== undefined){
      if (((robot.offsetLeft + (15 * run_speed)) < (mouseX - robot.offsetWidth)) && running_dir !== ‘r‘){
        // make run right, if not already
        running_dir = ‘r‘;
        clearTimeout(run_timer);
        run_r(1, robot.offsetLeft);
      } else if ((mouseX < robot.offsetLeft - (15 * run_speed)) && running_dir !== ‘l‘) {
        // make run left, if not already
        running_dir = ‘l‘;
        clearTimeout(run_timer);
        run_l(1, robot.offsetLeft);
      }
    }
  }
}

如今我们全然重写了函数而且跨浏览器工作得非常好……除非浏览器有触屏输入。我们仍须要向前进一步,使得我们的机器人能够在不论什么设备上跑动。由于触摸屏表现得有些不同,我们须要在事件侦听器上做一些额外的编码。

支持触摸屏

我们须要为触摸屏制定一些新规则:在stage上。屏幕被触摸到不论什么地方,机器人都会向那个点跑去,直到指尖离开。

假如用户触摸机器人。机器人则跳起来。总之,我们须要为之前的函数加入一些额外的事件处理器。而且我们将以这种方式来写代码:不管什么时候RobotMaster函数被调用,它都会自己主动执行。

(function (){
  if (stage.addEventListener){
    stage.addEventListener(‘touchstart‘, stage_mousemove_listener, false);
    stage.addEventListener(‘touchmove‘, stage_mousemove_listener, false);
    stage.addEventListener(‘touchend‘, stage_mouseout_listener, false);

    stage.addEventListener(‘mousemove‘, stage_mousemove_listener, false);
    robot.addEventListener(‘mouseover‘, robot_mouseover_listener, false);
    stage.addEventListener(‘mouseout‘, stage_mouseout_listener, false);
  } else {
    stage.attachEvent(‘onmousemove‘, stage_mousemove_listener);
    robot.attachEvent(‘onmouseover‘, robot_mouseover_listener);
    stage.attachEvent(‘onmouseout‘, stage_mouseout_listener);
  }
})();

我们不须要操心触摸事件在IE8中的格式,假如有不论什么设备不支持触摸触摸。它将忽略这些侦听器。如今,假如浏览器具有触摸功能,我们须要更新stage_mousemove_listener()函数使具有不同的表现。。

function stage_mousemove_listener(e){
/*
 * First we check if this is a touch screen device (if it has e.touches)
 */
  if (e.touches){
    e.preventDefault(); // we want to cancel what the browser would usually do if touched there
    // If the touch was within the boundaries of the stage...
    if ((e.touches[0].pageX > stageOffset.xpos)
    && (e.touches[0].pageX < (stageOffset.xpos + stage.offsetWidth))
    && (e.touches[0].pageY > stageOffset.ypos)
    && (e.touches[0].pageY < (stageOffset.ypos + stage.offsetHeight))){
      // we set the mouseX to equal the px location inside the stage
      mouseX = e.touches[0].pageX - stageOffset.xpos;
    } else { // if the touch was outside the stage, we call the mouseout listener
      stage_mouseout_listener();
    }

    /*
     * If the touch is directly on the robot, then we stop the run timer and make the robot jump
     */
    if ((e.touches[0].pageX > robot.offsetLeft) && (e.touches[0].pageX < (robot.offsetLeft + robot.offsetWidth))
    && (e.touches[0].pageY > (stageOffset.ypos + stage.offsetHeight - robot.offsetHeight))
    && (e.touches[0].pageY < (stageOffset.ypos + stage.offsetHeight))
    && (!jump_timer || jump_timer === undefined)){
      clearTimeout(run_timer);
      jmp(true, robot.offsetTop);
    }

  } else { // Finding the mouseX for non-touch devices...
    // All of our non-touch device code here
  }
}

你可能注意到,在RobotMaker函数里,这里不再具有不论什么”门“,可是,由于我们调用的全部具有事件处理程序的代码都在RobotMaker里。所以我们不再须要它们。对于我们的stage和characters,须要为 触摸设备加入一点特别的CSS,使得在用户手指按住它们时,它们不会尝试剪切和粘贴不论什么图片。

#stage, .character {
  -webkit-user-select: none;
}

最后。我们声明全部的机器人在页面的底部。使用相同的格式。当页面载入时。事件处理器使得代码自己主动执行- 这种方法相同阻止了那些机器人对象成为全局变量。因此,在整个脚本中,我们唯一有的全局变量就是RobotMaker()函数

(function(){
  var j = RobotMaker(document.getElementById(‘j‘), 1, 1);
  var j2 = RobotMaker(document.getElementById(‘j2‘), .8, 5);
  var j3 = RobotMaker(document.getElementById(‘j3‘), 1.1, .5);
  var j4 = RobotMaker(document.getElementById(‘j4‘), .5, .75);
})();

请在glory中查看终于的结果

总结

我强烈建议你学习所有的代码(和所有的凝视)。同一时候你能够在这里下载 四个 机器人
全国联保

Happy animating!

时间: 2024-12-18 13:55:06

JavaScript动漫作品(闭幕)的相关文章

Snabbt.js – 极简的 JavaScript 动画库

Snabbt.js 是一个简约的 JavaScript 动画库.它会平移,旋转,缩放,倾斜和调整你的元素.通过矩阵乘法运算,变换等可以任何你想要的方式进行组合.最终的结果通过 CSS3 变换矩阵设置. 在线演示      源码下载 您可能感兴趣的相关文章 网站开发中很有用的 jQuery 效果[附源码] 分享35个让人惊讶的 CSS3 动画效果演示 十分惊艳的8个 HTML5 & JavaScript 特效 Web 开发中很实用的10个效果[源码下载] 12款经典的白富美型 jQuery 图片轮

javascript的时间描述图怎么写

在gis系统中往往需要在一个时间间隔内把图形动态播放出来,比如2000年到现在地震变化啊,海啸的变化,在flex中这种展现方式需要后台rest服务相结合,要建立有时间点的图层,arcgis发布要选timeinfo属性,如果我们不用后台,数据格式是json或者xml形式应该怎么做呢,在flex中还有帧动画这个东东,在javascript应该怎么写呢,因为这个表现形式要以数据做支持,而且要在一个地图底图上叠加不断展现,现有javascript动画库是用不上了,很多都是css动画和canvas(htm

25 个超棒的 HTML5 &amp; JavaScript 游戏引擎开发库

25 个超棒的 HTML5 & JavaScript 游戏引擎开发库 就像在汽车中,引擎完成主要的工作,使汽车看起来不可思议.游戏引擎同理,游戏开发者完成细节的工作,使游戏看起来真实.吸引人眼球.游戏引擎负责其余的事情.早期,游戏开发者通常从草图做起,花费高昂,且不容易获利.为了让游戏开发更加简单容易,主要的开发者开始授权他们的基本游戏引擎,如 Unreal.而且,随着手机和平板游戏的出现,所需预算比以前更少,对 JAVASCRIPT 和HTML5 游戏引擎的需求大增. 如果你是一个游戏开发者,

国产动漫想活,做点比盗版还好的玩具先

在很多人眼里,动漫的图书.影视方面的侵权危害较大,但实际上,几乎被盗版动漫周边产品包围的市场,才直接影响到了整个动漫产业的健康发展,也使得国内动漫产业自身缺乏有效的造血机制,无法通过"粉丝经济"获得效益. 文/张书乐 盗版动漫衍生品的现象在国内并不少见,例如市场上随处可见的喜羊羊.灰太狼.虹猫蓝兔等国产动漫形象的毛绒玩具.童鞋等,这些大多是没有经过任何授权的盗版产品.而国产动漫在经过十多年的市场化运作后,似乎依然没有多少起色.为此,笔者和<法制日报>记者廉颖婷有了一番交谈,

动漫网站基于jquery的横向手风琴特效

今天给大家分享一款动漫网站基于jquery的横向手风琴特效.这款手风琴特效适用浏览器:IE8.360.FireFox.Chrome.Safari.Opera.傲游.搜狗.世界之窗.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div class="box2"> <div class="banner_tit"> 动漫人物</div> <div class="hot_role">

2016年31款轻量高效的开源JavaScript插件和库

目前有很多网站设计师和开发者喜欢使用由JavaScript开发的插件和库,但同时面临一个苦恼的问题:它们中的大多数实在是太累赘而且常常降低网站的性能.其实,其中也有不少轻量级的插件和库,它们不仅轻巧有用,而且不会影响网站的性能.本文就为大家整理了2016年以来30多款轻量级Javascript插件和库的列表,这些工具服务于特定的目标,并且它们能够非常有效和高效地实现目标. 不管你想创建一个图片库.一个滑动效果,个性化菜单还是其他接口元素,你都可以用这些插件和库轻易的实现.同时,你还可以使用这些插

JavaScript 性能优化技巧分享

JavaScript 作为当前最为常见的直译式脚本语言,已经广泛应用于 Web 应用开发中.为了提高Web应用的性能,从 JavaScript 的性能优化方向入手,会是一个很好的选择. 本文从加载.上下文.解析.编译.执行和捆绑等多个方面来讲解 JavaScript 的性能优化技巧,以便让更多的前端开发人员掌握这方面知识. 什么是高性能的 JavaScript 代码? 尽管目前没有高性能代码的绝对定义,但却存在一个以用户为中心的性能模型,可以用作参考:RAIL模型. 响应 如果你的应用程序能在1

中国需要讲好自己的“动漫故事”

随着互联网时代的不断发展,网络动漫产业作为一种与时俱进的文化产业,在丰富人们精神生活的同时,一定程度上转变了人们的思维方式,助推着文化产业的发展.许多国家网络动漫产业发展迅速,而对我国来讲,我国的动漫产业存在着巨大的发展潜力. 这几年优秀的国产动漫不断涌现,虽然离复兴还有很长一段路要走,但是让我们看到了希望.从人人熟知的中国国产动漫记录<喜羊羊与灰太狼之牛气冲天>,这部投资仅600万元的二维动画电影,在一个月内拿下9000万元的票房,到现在的<秦时明月>,<画江湖>,&

转 设计师工具篇

2015年1月给设计师的新鲜货 在本期的新鲜货中,我们给设计团队送来了新鲜应用,给初创公司送来了框架和样板.新设计资源,另外还有很多新的播客.色彩资源等等等等供大家赏析借鉴 在本期的“给设计师和开发人员的新鲜货”中,我们给设计团队送来了新鲜应用,给初创公司送来了框架和样板.新设计资源.JavaScript资源,另外还有很多新的播客.色彩资源等等等等.和以前一样,我们还带来了一些华丽的新字体! 这个月的几乎都是免费干货,也有个别价值比较高的付费应用及工具.这些资源想来一定会给设计师和开发人员带来极