Вход

Просмотр полной версии : Как сделать одноразовое нажатие клавиш.


drakulawz
27.09.2018, 13:40
Здравствуйте!
(Это работа с канвасом.)
Есть скрипт для одновременного нажатия клавиш, всё работает, но мне нужно сделать чтобы при нажатии, например, стрелки в верх и влево, эти клавиши срабатывали лишь раз (аналогично и с одной клавишей), т.е. нужно прервать выполнение функции после того как условие выполнится, но такое ощущения, что то условие которое я написал вообще не проверяется - это я думаю, что так надо сделать - надеюсь меня наставят на путь истинный и помогут решить эту головоломку. Другими словами, мне нужно, чтобы "player" перемещался на "speed" или по оси "х", или по "у", или по оси "х - у" одновременно (по диагонали) - нажал клавишу и держи сколько хочешь, но "player" сдвинется только на "speed", нажмёшь ещё раз - сдвинется ещё раз.
Вот скрипты:

Для обработки клавишь:

var keys = {
'W': 87,
'S': 83,
'A': 65,
'D': 68,
'LEFT': 37,
'RIGHT': 39,
'UP': 38,
'DOWN': 40,
'PAUSE': 32
};

var keyDown = {};

var setKey = function (keyCode) {
keyDown[keyCode] = true;
// console.log(keyCode);
};

var clearKey = function (keyCode) {
keyDown[keyCode] = false;
};

var isKeyDown = function (keyName) {
return keyDown[keys[keyName]] == true;
};

var isAnyKeyDown = function () {
for (var k in keyDown) {
if (keyDown[k])
return true;
}
};

window.onkeydown = function (e) {
setKey(e.keyCode);
};
window.onkeyup = function (e) {
clearKey(e.keyCode);
};


То, что должно двигаться по нажатию:

var player = {
level: 1,
hp: 3,
width: 50,
height: 50,
x: 320,
y: 240,
speed: 2,
dx: 0,
dy: 0,
score: 0,
color: randomColor(),

draw: function () {
drawRect(this.x, this.y, this.width, this.height, this.color);
},

// попытка сделать то что задумал:
move: function () {
if (this.x != this.x + this.width ||
this.y != this.y + this.height ||
this.x != this.x - this.width ||
this.y != this.y - this.height) {
if (isKeyDown('LEFT')) {
this.x -= this.speed;
this.dx = -1;
} else if (isKeyDown('RIGHT')) {
this.x += this.speed;
this.dx = 1;
} else {
this.dx = 0
}
if (isKeyDown('DOWN')) {
this.y += this.speed;
this.dy = 1;
} else if (isKeyDown('UP')) {
this.y -= this.speed;
this.dy = -1;
} else {
this.dy = 0;
}
} else {
return;
}
},

init: function (x, y) {
this.x = x;
this.y = y;
}
};

SuperZen
27.09.2018, 14:23
<html>

<head>
<style>
#hero {
position: fixed;
top: 100px;
left: 100px;
width: 100px;
height: 100px;
background-color: burlywood;
border: 1px dashed #cccccc;
}
</style>
</head>

<body>
<textarea id="keys"></textarea>
<div id="hero"></div>
<script>
const keys = [37, 39, 38, 40]
const speed = 5
const keyPressed = {}
const currentPosition = {
x: 100,
y: 100
}

const hero = document.getElementById('hero')

document.addEventListener('keydown', function (e) {
if (keys.includes(e.keyCode)) {
keyPressed[e.keyCode] = true
}
})

document.addEventListener('keyup', function (e) {
if (keys.includes(e.keyCode)) {
delete keyPressed[e.keyCode]
}
})

setInterval(() => {
document.getElementById('keys').value = JSON.stringify(keyPressed)
update()
}, 100)

update = () => {
if (38 in keyPressed) currentPosition.y -= speed
if (40 in keyPressed) currentPosition.y += speed

if (37 in keyPressed) currentPosition.x -= speed
if (39 in keyPressed) currentPosition.x += speed

hero.style.top = `${currentPosition.y}px`
hero.style.left = `${currentPosition.x}px`
}
</script>
</body>

</html>

у меня как-то так получилось )

рони
27.09.2018, 14:39
drakulawz,
вариант Rise, добавлено чтобы "player" перемещался на "speed" или по оси "х", или по "у", или по оси "х - у" одновременно (по диагонали) - нажал клавишу и держи сколько хочешь, но "player" сдвинется только на "speed", нажмёшь ещё раз - сдвинется ещё раз.

<!DOCTYPE html>

<html>
<head>
<title>Untitled</title>
<meta charset="utf-8">
<script>
try {
'code' in KeyboardEvent.prototype || Object.defineProperty(KeyboardEvent.prototype, 'code', {
get: function () { return { 37: 'ArrowLeft', 38: 'ArrowUp', 39: 'ArrowRight', 40: 'ArrowDown' }[this.keyCode] }
})
} catch (e) {}

</script>
</head>

<body>
<canvas width="200" height="100" id="myCanvas" style="border: 1px solid red"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var rec = {};
rec.x = 10;
rec.y = 10;
rec.width = 50;
rec.height = 25;
rec.step = 5;
rec.color = 'red';
rec.moveup = function () {
this.y = Math.max(this.y - this.step, 0);
};
rec.movedown = function () {
this.y = Math.min(this.y + this.step, canvas.height - this.height);
};
rec.moveleft = function () {
this.x = Math.max(this.x - this.step, 0);
};
rec.moveright = function () {
this.x = Math.min(this.x + this.step, canvas.width - this.width);
};
rec.draw = function () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
};
rec.draw();
var move = {};
document.onkeydown = function (e) {
e.preventDefault();//только для примера тут
if(move[e.code]) return;
if (e.code == 'ArrowUp') {rec.moveup();move.ArrowUp = true }
else if (e.code == 'ArrowDown') {rec.movedown();move.ArrowDown = true }
else if (e.code == 'ArrowLeft') {rec.moveleft();move.ArrowLeft = true}
else if (e.code == 'ArrowRight') {rec.moveright();move.ArrowRight = true}
else return;
rec.draw();
};
document.onkeyup = function (e) {
if (e.code == 'ArrowUp') move.ArrowUp = false;
else if (e.code == 'ArrowDown') move.ArrowDown = false;
else if (e.code == 'ArrowLeft') move.ArrowLeft = false;
else if (e.code == 'ArrowRight') move.ArrowRight = false;
};

</script>


</body>
</html>

drakulawz
27.09.2018, 14:43
у меня как-то так получилось )
Перефразирую:
мне нужно, что бы после того как нажалась стрелка (любая или две для диагонали), ивент прекращался и плеер был перемещён на спид - всё, он не должен больше двигаться сколько бы клавиша не держалась. Нажал ещё раз - тот же эффект, ещё раз - аналогично. Вот такое решение мне нужно. Плеер не должен перемещаться когда держишь клавишу нажатой! Только один шаг - одно нажатие!

drakulawz
27.09.2018, 14:46
рони,
Круто!:write: Благодарю!


#offtop Кстати, кто-нибудь может сталкивался, не работают всплывающие окна в браузере (UC Browser) - ничего не менял (не помню по крайней мере), вот когда плюсик возле "Карма" жму ничего не выпадает - как и с остальными диалогами на сайте (и на всех остальных). Может какая-то комбинация клавиш такое делает? Если кто не в курсе - это тот же гугл хром (на его основе спиляно).

SuperZen
27.09.2018, 15:09
<html>

<head>
<style>
#hero {
position: fixed;
top: 100px;
left: 100px;
width: 100px;
height: 100px;
background-color: burlywood;
border: 1px dashed #cccccc;
}
</style>
</head>

<body>
<textarea id="keys"></textarea>
<textarea id="previous_keys"></textarea>
<div id="hero"></div>
<script>
const keys = [37, 39, 38, 40]
const speed = 5
const keyPressed = {}
let previousKeyPressed = {}
const currentPosition = {
x: 100,
y: 100
}

const hero = document.getElementById('hero')

document.addEventListener('keydown', function (e) {
e.preventDefault()
if (keys.includes(e.keyCode)) {
keyPressed[e.keyCode] = true
}
})

document.addEventListener('keyup', function (e) {
e.preventDefault()
if (keys.includes(e.keyCode)) {
delete keyPressed[e.keyCode]
}
})

setInterval(() => {
document.getElementById('keys').value = JSON.stringify(keyPressed)
document.getElementById('previous_keys').value = JSON.stringify(previousKeyPressed)
update()
}, 100)

update = () => {
if (38 in keyPressed && !(38 in previousKeyPressed)) currentPosition.y -= speed
if (40 in keyPressed && !(40 in previousKeyPressed)) currentPosition.y += speed

if (37 in keyPressed && !(37 in previousKeyPressed)) currentPosition.x -= speed
if (39 in keyPressed && !(39 in previousKeyPressed)) currentPosition.x += speed

hero.style.top = `${currentPosition.y}px`
hero.style.left = `${currentPosition.x}px`

previousKeyPressed = { ...keyPressed }
}
</script>
</body>

</html>

drakulawz
27.09.2018, 15:20
рони, а почему нужно использовать именно Math.max и Math.min?
Разве не правильней будет Math.ceil ?

рони
27.09.2018, 15:26
а почему нужно использовать именно Math.max и Math.min?
так проще всего получить ограничение диапазона, без всяких if.
Math.ceil не знаю каким образом это применить.

drakulawz
27.09.2018, 15:27
SuperZen, не работает ведь.:) И я не понимаю, по большей части 50% вашего кода.:p Вариант рони, мне подходит.:yes:

drakulawz
27.09.2018, 15:28
не знаю каким образом это применить.
Так если у меня координаты дробными получаются, разве не лучше применить Math.ceil ? Или в канвасе лучше так не делать?
А, не так выразился. Имею в виду, если взять вот так:
в функции движения сделать так:
this.x = this.x + this.step
а уже в инициализации отрисовки:
Math.ceil(canvas.width - player.width)

рони
27.09.2018, 15:33
Так если у меня координаты дробными получаются, разве не лучше применить Math.ceil
если нужно применяйте, не понимаю как связано ограничение движения блока в пределах canvas и точность позиционирования

SuperZen
27.09.2018, 15:36
Ладно, тогда, последний "не работающий" пример... ))

<html>

<head>
<style>
#hero {
position: fixed;
top: 100px;
left: 100px;
width: 100px;
height: 100px;
background-color: burlywood;
border: 1px dashed #cccccc;
}
</style>
</head>

<body>
<textarea id="keys"></textarea>
<textarea id="previous_keys"></textarea>
<div id="hero"></div>
<script>
const keys = [37, 39, 38, 40]
const speed = 5
const keyPressed = {}
const previousKeyPressed = {}
const currentPosition = {
x: 100,
y: 100
}

keys.forEach(key => keyPressed[key] = previousKeyPressed[key] = false)

const hero = document.getElementById('hero')

document.addEventListener('keydown', function (e) {
e.preventDefault()
if (keys.includes(e.keyCode)) {
keyPressed[e.keyCode] = true
}
})

document.addEventListener('keyup', function (e) {
e.preventDefault()
if (keys.includes(e.keyCode)) {
keyPressed[e.keyCode] = false
}
})

setInterval(() => {
document.getElementById('keys').value = JSON.stringify(keyPressed)
document.getElementById('previous_keys').value = JSON.stringify(previousKeyPressed)
update()
}, 100)

update = () => {
if (keyPressed[38] && !previousKeyPressed[38]) currentPosition.y -= speed
if (keyPressed[40] && !previousKeyPressed[40]) currentPosition.y += speed

if (keyPressed[37] && !previousKeyPressed[37]) currentPosition.x -= speed
if (keyPressed[39] && !previousKeyPressed[39]) currentPosition.x += speed

hero.style.top = `${currentPosition.y}px`
hero.style.left = `${currentPosition.x}px`

Object.keys(keyPressed).forEach(key => previousKeyPressed[key] = keyPressed[key])
}
</script>
</body>

</html>

рони
27.09.2018, 15:37
drakulawz,
если очень хочется, замените строку
ctx.fillRect(this.x, this.y, this.width, this.height);
на ctx.fillRect(Math.ceil(this.x), Math.ceil(this.y), this.width, this.height);
но по моему это что-то бесполезное в данном случае

drakulawz
27.09.2018, 15:40
эх....это фигню какую-то написал, ща я так попробую, а потом целый скрипт выложу, а то наглядности не получиться, только вопросы неправильно заданные - понимаю, что хочу спросить, а спросить не могу. :))

drakulawz
27.09.2018, 16:11
SuperZen, этот работает, только от этого он мне знакомее не становится.:(
Кстати, а почему прямоугольник в место того, что бы двигаться в верх и вниз уменьшается и увеличивается?:-?

SuperZen
27.09.2018, 16:22
хз, проверял только в chrome на макпуке

может быть такой стиль нужен,

html,
body {
height: 100%;
}

хотя ) div position: fixed, и все должно быть как надо...

drakulawz
27.09.2018, 16:43
SuperZen, а с канвасом не работаете? Интересная штука. CSS вообще не нужен. :D
Как и HTML, в прочем.

SuperZen
27.09.2018, 16:53
почему-то для конвы эта библа запала в душу https://konvajs.github.io/
юзал несколько раз, остался доволен, и есть биндинги для реакта )

еще вот эту штуку юзал, она конечно серьезнее конвы, тоже остался доволен, https://www.babylonjs.com/

еще есть такая http://www.pixijs.com/ - но эту не юзал

drakulawz
27.09.2018, 17:11
SuperZen, для такого нуба как я ещё рановато библиотеки изучать :). Хочу сперва нормально изучить сам канвас.

Dilettante_Pro
27.09.2018, 18:26
"не работающий" пример
А не работает оно, само собой, в IE

drakulawz
27.09.2018, 18:34
SuperZen, а где вы учились использовать эти фреймворки? Я не могу найти русскоязычных ресурсов или хотя бы видео-уроков.:(

drakulawz
27.09.2018, 18:35
Dilettante_Pro,
Здесь не работало :)...я его не копипастил никуда.

drakulawz
27.09.2018, 18:52
рони, чё-то я напортачил. Вышло то же, что и было.:p
Буду дальше голову ломать.

P.S.: Ваш вариант не ходит по диагонали. Или всё таки я где-то СИЛЬНО напортачил.

рони
27.09.2018, 19:59
Ваш вариант не ходит по диагонали.
ходит, жмите две кнопки одновременно резче :)

рони
27.09.2018, 20:10
по диагонали
или так с setTimeout
<!DOCTYPE html>

<html>
<head>
<title>Untitled</title>
<meta charset="utf-8">
<script>
try {
'code' in KeyboardEvent.prototype || Object.defineProperty(KeyboardEvent.prototype, 'code', {
get: function () { return { 37: 'ArrowLeft', 38: 'ArrowUp', 39: 'ArrowRight', 40: 'ArrowDown' }[this.keyCode] }
})
} catch (e) {}

</script>
</head>

<body>
<canvas width="200" height="100" id="myCanvas" style="border: 1px solid red"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var rec = {};
rec.x = 10;
rec.y = 10;
rec.width = 50;
rec.height = 25;
rec.step = 5;
rec.color = 'red';
rec.moveup = function () {
this.y = Math.max(this.y - this.step, 0);
};
rec.movedown = function () {
this.y = Math.min(this.y + this.step, canvas.height - this.height);
};
rec.moveleft = function () {
this.x = Math.max(this.x - this.step, 0);
};
rec.moveright = function () {
this.x = Math.min(this.x + this.step, canvas.width - this.width);
};
rec.draw = function () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
};
rec.draw();
var move = {};
var timer;
document.onkeydown = function (e) {
e.preventDefault();
if(move[e.code]) return;
if (e.code == 'ArrowUp') {rec.moveup();move.ArrowUp = true }
else if (e.code == 'ArrowDown') {rec.movedown();move.ArrowDown = true }
else if (e.code == 'ArrowLeft') {rec.moveleft();move.ArrowLeft = true}
else if (e.code == 'ArrowRight') {rec.moveright();move.ArrowRight = true}
else return;
window.clearTimeout(timer);
timer = window.setTimeout(rec.draw.bind(rec), 120);
};
document.onkeyup = function (e) {
if (e.code == 'ArrowUp') move.ArrowUp = false;
else if (e.code == 'ArrowDown') move.ArrowDown = false;
else if (e.code == 'ArrowLeft') move.ArrowLeft = false;
else if (e.code == 'ArrowRight') move.ArrowRight = false;
};

</script>


</body>
</html>

SuperZen
28.09.2018, 13:13
SuperZen, а где вы учились использовать эти фреймворки? Я не могу найти русскоязычных ресурсов или хотя бы видео-уроков.:(

читаю все на английском...