变换......无休止地添加 [英] Transforms are added...endlessly

查看:183
本文介绍了变换......无休止地添加的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用DOM over canvas在CSS和JS中创建一个类似于小行星的简单游戏,用于实验目的。

I'm creating a simple asteroids-like game in CSS and JS using the DOM over canvas for...experimentation purposes.

在这个例子中,我的代码非常小,可以很容易地看到下面发生了什么。最终目标:让箭头键平滑地旋转并在窗口周围转换太空船,而不会产生无限量的变换。 我想我90%

My code is pretty small in this example to make it easy to see what's going on below. The ultimate goal: Let arrow keys smoothly rotate and translate the spaceship around the window without creating an infinite amount of transforms. I think I'm 90% there:

使用箭头键控制下面的代码段。

'use strict';

function defineDistances() {
  var distance = {};

  distance.up = -1;
  distance.right = 1;
  distance.down = 1;
  distance.left = -1;
      
  return distance;
}

function defineKeys() {
  var keys = {};

  keys.up = 38;
  keys.right = 39;
  keys.down = 40;
  keys.left = 37;
      
  return keys;
}

function checkKeys( e ) {
  var triBx = document.getElementById( 'v-wrp' ),
      keys = defineKeys(),
      distance = defineDistances();

  switch( e.keyCode ) {
    case keys.up:
      triBx.style.transform += 'translateY(' + distance.up + 'px)';
      break;
    case keys.right:
      triBx.style.transform += 'rotate(' + distance.right + 'deg)';
      break;
    case keys.down:
      triBx.style.transform += 'translateY(' + distance.down + 'px)';
      break;
    case keys.left:
      triBx.style.transform += 'rotate(' + distance.left + 'deg)';
      break;
  }
}

function detectMovement( e ) {
  setInterval ( 
    function() {
      checkKeys( e );
    },
    1000/24
  );  
}

function start() {
  window.addEventListener( 'keydown', detectMovement );
  preventBrowserWindowScroll()
}

start();

@import url( "https://fonts.googleapis.com/css?family=Nunito" );

html {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  font-family: "Nunito", sans-serif;
  font-size: 2rem;
}

.v {
  display: block;
  transform: rotate( 180deg );
}

<div id="v-wrp" class="v-wrp">
  <b class="v">V</b>
</div>

<script>
function preventBrowserWindowScroll() {
  window.addEventListener( 'keydown', function( e ) {
    // space and arrow keys
    if([32, 37, 38, 39, 40].indexOf( e.keyCode ) > -1 ) {
      e.preventDefault();
    }
  }, false )
}
</script>

如果您检查 v-wrp 元素您可以看到浏览器无休止地添加转换。

If you inspect the v-wrp element in the browser you can see the transforms get added endlessly.

我使用的原因 + = 添加变换是为了避免这个问题:翻译/旋转后重置CSS变换原点

The reason I use += to add transforms is to avoid this problem: Reset CSS transform origin after translation / rotation

transform-origin 不会随着元素的移动移动,导致不受欢迎的效果,除非除了之前的变换之外还添加了所有变换......)

( The transform-origin doesn't move with the element as it moves, causing undesired effects unless all transforms are added in addition to the previous ones... )

那么我该如何克服这些挑战呢?我怀疑这个片段是如此不稳定,因为添加了无限的变换。如何在没有所有内存丢失/紊乱/ bugginess /无限变换的情况下使其工作方式与现在类似?

So how do I overcome these challenges? I suspect the snippet is so choppy because of the endless transforms being added. How do I get this working similarly to the way it is now without all the memory loss/ choppiness/ bugginess / endless transforms?

编辑:另一个主要问题是一旦按下按键,船将如何连续沿相同方向行进,如果按下正确的按键,即使是圆形的模式也是如此。我希望它像空间一样漂移,但一旦钥匙松开就不能转动。当它漂浮时,轨迹应保持笔直。我做错了什么?。

推荐答案

欲了解更多信息和以下答案的演示见 https://stackoverflow.com/a/43744006/3877726

For more info and a demo of the answer below see https://stackoverflow.com/a/43744006/3877726

如果给定对象位置,缩放和旋转设置变换的最快方法是将其作为单个矩阵 element.style.transform =matrix(a,b,c,d,e,f);

If given a object position, scale and rotation the quickest way to set the transform is to do it as a single matrix element.style.transform = "matrix(a,b,c,d,e,f)";

6个值代表X轴(a,b),Y轴(c,d)和本地原点(e,f)的方向和比例)

The 6 values represent the direction and scale of the X axis (a,b), Y axis (c,d) , and the local origin (e,f)

由于大多数时候你不想歪斜并且比例是均匀的(x和y缩放相同),创建和设置变换的函数是快。你要做的只是传递位置,比例和旋转。

As most of the time you don't want to skew and the scale is uniform (x and y scale the same) the function to create and set the transform is quick. All you do is pass the position, scale and rotation.

const setElementTransform = (function(){
    const matrix = [1,0,0,1,0,0]; // predefine the array (helps ease the GC load
    const m = matrix; // alias for code readability.
    return function(element, x, y, scale, rotation);
        m[3] = m[0] = Math.cos(rotation) * scale;     // set rotation and scale
        m[2] = -(m[1] = Math.sin(rotation) * scale);  // set rotation and scale
        m[4] = x;
        m[5] = y;
        element.style.transform = `matrix(${m.join(",")})`;
    }
}());






不要使用 keyboardEvent.keyCode 它已折旧。



而不是使用旧的(和晦涩的键值) keyCode 属性来读取你应该使用代码的键属性,其字符串表示哪个键已关闭或关闭。


Don't use keyboardEvent.keyCode it has depreciated.

Rather than use the old (and obscure key values) keyCode property to read the keys you should use the code property that has a string representing which key is down or up.

const keys = {
    ArrowLeft : false,  // add only the named keys you want to listen to.
    ArrowRight: false,  
    ArrowUp   : false,  
    ArrowDown : false,  
    stopKeyListener : (function(){  // adds a listener and returns function to stop key listener if needed.
        function keyEvent(e){
            if(keys[e.code] !== undefined){ // is the key on the named list
                keys[e.code] = e.type === "keydown"; // set true if down else false
                e.preventDefault(); // prevent the default Browser action for this key.
        }
        addEventListener("keydown",keyEvent);
        addEventListener("keyup",keyEvent);
        return function(){
            removeEventListener("keydown",keyEvent);
            removeEventListener("keyup",keyEvent);
        }
    }()) //
}

现在,您可以随时检查按键是否按下 if(keys.ArrowLeft){

Now at any time you can just check if a key is down with if(keys.ArrowLeft){

如果您定期对DOM进行许多更改,则应使用 requestAnimationFrame 它告诉浏览器你的意图,并将导致回调中的所有DOM更改与显示硬件以及DOM自己的合成和渲染同步。

If you are making many changes to the DOM at regular intervals you should use requestAnimationFrame and it tells the browser your intention and will cause all DOM changes made from within the callback to sync with the display hardware and the DOM's own compositing and rendering.

requestAnimationFrame(mainLoop);  // will start the animation once code below has been parse and executed.
var player = {  // the player
    x : 0,
    y : 0,
    scale : 1,
    rotate : 0,
    speed : 0,
    element : document.getElementById("thePlayer")
}
function mainLoop(time){ // requestAnimationFrame adds the time as the first argument for the callback
     if(keys.ArrowLeft){ player.rotate -= 1 }
     if(keys.ArrowRight){ player.rotate += 1 }
     if(keys.ArrowUp){ player.speed  += 1 }
     if(keys.ArrowRight){ player.speed -= 1 }
     player.x += Math.cos(player.rotate) * player.speed;
     player.y += Math.sin(player.rotate) * player.speed;
     setElementTransform(
         player.element,
         player.x, player.y,
         player.scale,
         player.rotate
     );
     requestAnimationFrame(mainLoop);
}

演示 https://stackoverflow.com/a/43744006/3877726 (与答案顶部相同的链接)

For a demo https://stackoverflow.com/a/43744006/3877726 (same link as at top of answer)

这篇关于变换......无休止地添加的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆