变换......无休止地添加 [英] Transforms are added...endlessly
问题描述
我正在使用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屋!