Javascript游戏中的“透视”

物体与观察者的距离远近在静态时通过物体的大小来体现。当物体运动时,通过远近物体不同的运动速度来体现,从而形成层次感。近处的物体运动快,远处的物体运动慢。

手机演示地址://javascript.net.cn/test/446/#/

代码:

<template>
  <div class="viewport">
    <div class="sence">
      <div class="sprite sprite-free-right"></div>
    </div>
    <div class="front-background"></div>
    <div class="distance-background"></div>
  </div>
</template>

<style>
html,body{height: 100%;}
.viewport{width: 100%; height: 100%; overflow: hidden; position: relative; }
.sence{
  width: 2500px; 
  height: 100%;
  background:url(../assets/images/background.png) no-repeat; 
  background-position-y: 100%; 
  position: relative;
}
.front-background{
  width: 2500px; 
  height: 100%;
  background:url(../assets/images/FrontBackground.png) no-repeat; 
  background-position-y: 100%; 
  position: absolute;
  bottom: 0px;
  z-index: 9;
}
.distance-background{
  width: 2500px; 
  height: 100%;
  background:url(../assets/images/DistantBackground.png) no-repeat; 
  background-position-y: 0%; 
  position: absolute;
  top: 0px;
  z-index: -9;
}
.sprite{width: 160px;height: 205px; background: #f4f74a; position: absolute;}

/*精灵向右停止动画*/
.sprite-free-right{
  background:url(../assets/images/SpriteFreeRight.png);
  animation: stop 2.5s infinite steps(4);
  width: 160px;
}
/*精灵向左停止动画*/
.sprite-free-left{
  background:url(../assets/images/SpriteFreeRight.png);
  animation: stop 2.5s infinite steps(4);
  transform:scaleX(-1);  
  width: 160px;
}
@keyframes stop { to {background-position: -640px 0;} }



/*精灵向右动画*/
.sprite-right{
  background:url(../assets/images/SpriteRight.png);
  animation: spriteMove 2s infinite steps(4);
}
/*精灵向左动画*/
.sprite-left{
  background:url(../assets/images/SpriteRight.png);
  transform:scaleX(-1);
  animation: spriteMove 2s infinite steps(4);
}
@keyframes spriteMove { to {background-position: -695px 0;} }

</style>

<script>
import querystring from "querystring";

export default {
  data() {
    return {};
  },

  created: function(){

  },

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

    // 初始化场景
    var sence = document.querySelector(".sence");
    sence.style.marginLeft    = "-100px";
    sence.style.marginBottom  = "0px";
    sence.style.width         = "2500px";
    // 初始化前景
    var frontBackground = document.querySelector(".front-background");
    frontBackground.style.left = String(parseInt(sence.style.marginLeft)*1.5) + "px";
    // 初始化远景
    var distanceBackground = document.querySelector(".distance-background");
    distanceBackground.style.left = String(parseInt(sence.style.marginLeft)*0.3) + "px";

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

      var to = getToCoordinate(event, sence);
      console.log("to:",to);
      move(sprite, sence, from, to, event);
    }
    document.addEventListener("touchstart", s);
    


    /**
     * @function 精灵移动动画
     */
    function spriteMoveAnimate(spriteSelector){
      //停止左右空闲动画
      spriteSelector.classList.remove("sprite-free-left");
      spriteSelector.classList.remove("sprite-free-right");

      //停止左右移动动画
      spriteSelector.classList.remove("sprite-left");
      spriteSelector.classList.remove("sprite-right");

      //添加移动动画
      if(spriteSelector.vX > 0){
        spriteSelector.classList.add("sprite-right");
      }else if(spriteSelector.vX < 0){
        spriteSelector.classList.add("sprite-left");
      }
    }
    /**
     * @function 精灵空闲动画
     */
    function spriteStopAnimate(spriteSelector){
      console.log(spriteSelector.classList.contains("sprite-right"));
      //精灵停止后,添加空闲的动画
      if(spriteSelector.classList.contains("sprite-right") ){
        spriteSelector.classList.remove("sprite-right");
        spriteSelector.classList.add("sprite-free-right");
      }else{
        spriteSelector.classList.remove("sprite-left");
        spriteSelector.classList.add("sprite-free-left");
      }
    }


    /**
     * @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轴上速度

      // 设置移动动画
      spriteMoveAnimate(spriteSelector);

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

        // 大小5*5的范围内 判断结束
        var edge = 2;
        if( Math.round(left) > to.x-edge && Math.round(left) < to.x+edge){
          if( Math.round(bottom) > to.y-edge && Math.round(bottom) < to.y+edge){
            from.x = to.x;
            from.y = to.y;
            spriteSelector.vX = 0;
            spriteSelector.vY = 0;
            clearInterval(spriteSelector.timer);
            // 设置停止动画
            spriteStopAnimate(spriteSelector);
          }
        }

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

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

    

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

    /**
     * @function 背景移动
     */
    function scrollBackground(senceSelector, backgroundSelector, background){
      // console.log("mL:", senceSelector.style.marginLeft);
      if(background){
        backgroundSelector.style.left = String(parseInt(senceSelector.style.marginLeft)*0.3) + "px";
      }else{
        backgroundSelector.style.left = String(parseInt(senceSelector.style.marginLeft)*1.5) + "px";        
      }
    }



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

      console.log(offset);

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

  },

  computed: {},

  methods: {}
};
</script>


 

 

声明:本站所有文章和图片,如无特殊说明,均为原创发布。商业转载请联系作者获得授权,非商业转载请注明出处。
随机推荐
Nine 主题
URLSearchParams 对象
使用 MySQL 线程池对压力测试的影响
WordPress 自定义文章类型
JavaScript 表单事件
Node.js 安装
WP_Query 函数参数
MySQL 的 sql_mode 模式介绍:为什么 MySQL 中 int,float,double 类型字段插入空字符时自动转为0