JS模仿《无限梦魇》中的精灵控制和场景滚动

效果:

算法:

 

代码:

<div class="stage">
  <div class="sence">
    <div class="sprite"></div>
  </div>
</div>

<style>
.stage{width: 100%; overflow: hidden; position: relative; }
.sence{width: 1024px; height: 350px; background:url(../assets/images/background.jpg); position: relative;}
.sprite{width: 20px;height: 50px; background: #f4f74a; position: absolute;}
</style>

<script>
// 初始化精灵
var sprite    = document.querySelector(".sprite");
// 精灵初始位置
var from  = {x:200,  y:280};
sprite.style.left = from.x+'px';
sprite.style.top  = from.y+'px';
// 精灵速度
sprite.vX = 0;
sprite.vY = 0;


// 初始化场景
var sence    = document.querySelector(".sence");
sence.style.marginLeft  = "-100px";
sence.style.marginTop   = "0px";
sence.style.width       = "1024px";


// 处理用户点击
function s(event){
  var from = {};
  from.x = parseFloat(sprite.style.left);
  from.y = parseFloat(sprite.style.top);

  var to = getToCoordinate(event, sence);

  move(sprite, sence, from, to, event);
}
document.addEventListener("touchstart", s);



/**
 * @function 精灵移动函数
 */
function move(spriteSelector, senceSelector, from, to, event){
  //偏移量,两条直角边长
  var offset  = {x:0,y:0};
  offset.x    = to.x - from.x;
  offset.y    = to.y - from.y;
  
  //实际距离
  var distance  = Math.pow(offset.x,2) + Math.pow(offset.y,2);
  distance      = Math.sqrt(distance);

  //速度 p/s 速度比等于直角三角形边长比
  var v   = 1; //斜边速度
  sprite.vX  = (offset.x * v)/distance;  //x轴上速度
  sprite.vY  = (offset.y * v)/distance;  //Y轴上速度

  //设置移动循环
  clearInterval(spriteSelector.timer);
  spriteSelector.timer = setInterval(function(){
    var left = parseFloat(spriteSelector.style.left) + sprite.vX;
    var top  = parseFloat(spriteSelector.style.top)  + sprite.vY;

    // 大小5*5的范围内
    var edge = 2;
    if( Math.round(left) > to.x-edge && Math.round(left) < to.x+edge){
      if( Math.round(top) > to.y-edge && Math.round(top) < to.y+edge){
        from.x = to.x;
        from.y = to.y;
        clearInterval(spriteSelector.timer);
      }
    }

    spriteSelector.style.left = left.toString() + "px";
    spriteSelector.style.top  = top.toString() + "px";

    scrollScence(spriteSelector, senceSelector, from, to, event); 
  },1);
};



/**
 * @function 场景移动 场景根据sprite的位置移动
 */
function scrollScence(spriteSelector, senceSelector, from, to, event){
  var spriteLeft      = parseFloat( spriteSelector.style.left );
  var senceMarginLeft = parseFloat( senceSelector.style.marginLeft );
  
  var distance      = Math.abs(spriteLeft) - Math.abs(senceMarginLeft);   // 精灵离浏览器左边的距离
  var documentWidth = Math.ceil( parseFloat(document.body.clientWidth) ); // 浏览器宽度
  var senceWidth    = parseFloat(senceSelector.style.width);              // 场景宽度

  // 场景左移 精灵向右移动 精灵离左边的距离大于屏幕一半,并且场景偏移到右边边界前执行
  if( sprite.vX>0 && distance+100 > documentWidth/2 && Math.abs(senceMarginLeft) <= (senceWidth-documentWidth) ){
    var marginLeft = parseFloat(senceSelector.style.marginLeft) - sprite.vX;
    senceSelector.style.marginLeft = marginLeft.toString() + "px";
    console.log("场景左移");
  }

  // 场景右移 精灵向左移动 精灵离右边的距离大于屏幕一半,并且场景偏移到左边边界前执行
  if( sprite.vX<0 && documentWidth-distance+100 > documentWidth/2 && senceMarginLeft <= 0 ){
    var marginLeft = parseFloat(senceSelector.style.marginLeft) - sprite.vX;
    senceSelector.style.marginLeft = marginLeft.toString() + "px";
    console.log("场景右移");
  }
}



/** 
 * @function 获取精灵目标坐标 获取sprite相对sence的坐标,由场景sence的marginLeft和clientX计算
 */
function getToCoordinate(event, senceSelector){
  var offset = {};
  offset.x = parseFloat( senceSelector.style.marginLeft );
  offset.y = parseFloat( senceSelector.style.marginTop );

  var destiny = {};
  destiny.x = event.touches[0].clientX + Math.abs(offset.x);
  destiny.y = event.touches[0].clientY + Math.abs(offset.y);
  return destiny;
}

</script>

 

演示地址 需要手机端打开

 

修改时间 2018-05-06

声明:本站所有文章和图片,如无特殊说明,均为原创发布。商业转载请联系作者获得授权,非商业转载请注明出处。
随机推荐
JavaScript navigator对象
Rollup 教程
JavaScript EventSource 服务器发送事件 Server-Sent Events(SSE)
Node.js readline 模块
HTML input radio 单选按钮
Express 使用 XSS 模块进行安全过滤
使用 MySQL 线程池对压力测试的影响
Wordpress 主样式表(style.css)