Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Обработка нажатия двух клавиш одновременно. (https://javascript.ru/forum/events/78148-obrabotka-nazhatiya-dvukh-klavish-odnovremenno.html)

Temcher 01.08.2019 23:09

Обработка нажатия двух клавиш одновременно.
 
Всем привет! Помогите разобраться, как изменить код, чтобы обрабатывались две нажатые клавиши одновременно. Чтобы две кнопки были независимы друг от друга.
Я так понимаю тут причина в keyCode, которая принимает только какое то одно значение. т.е при получении второго значения(скажем D) значение W удаляется. Нужен массив? пробовал по разному, не понимаю.
var mas = {
	'W':87,
	'D':68
};

window.onkeydown=function(e){
	if(e.keyCode == mas.W){
		console.log('Кнопка W нажата');
	}
	if(e.keyCode == mas.D){
		console.log('Кнопка D нажата');
	}
	window.onkeyup=function(e){
		if(e.keyCode == mas.W){
			console.log('Отжата кнопка W');
		}
		else if(e.keyCode == mas.D){
			console.log('Отжата кнопка D');
		}
	}
}


В консоле при нажатии к примеру клавиши W вижу, как она обрабатывается, но как только нажимаю D обработка W прерывается.

В дальнейшем хочу чтобы объект в canvas мог двигаться не только по вертикали и горизонтали, но и по диагонали.

j0hnik 02.08.2019 00:44

у вас же есть событие keyup, очевидно ведь, что если клавиша была нажата, пока не сработало событие keyup она нажата.

Malleys 02.08.2019 01:57

Зачем на каждом нажатии клавиши переопределяется обработчик отжимания клавиши?

Цитата:

Сообщение от Temcher
e.keyCode

Это не рекомендуемое к использованию свойство, используйте вместо него KeyboardEvent.prototype.key или KeyboardEvent.prototype.code

Исправленный вариант, в объекте pressedKeys хранятся нажатые клавишы...
var pressedKeys = {};

onkeydown = function(e) {
	if(pressedKeys[e.code]) return;
	pressedKeys[e.code] = true;

	if(e.code === "KeyW") {
		console.log('Кнопка W нажата');
	} else if(e.code === "KeyD") {
		console.log('Кнопка D нажата');
	}
}

onkeyup = function(e) {
	delete pressedKeys[e.code];

	if(e.code === "KeyW") {
		console.log('Отжата кнопка W');
	} else if(e.code === "KeyD") {
		console.log('Отжата кнопка D');
	}
}


Можно упростить до...
var pressedKeys = {};

onkeydown = function(e) {
	if(e.code in pressedKeys) return;
	pressedKeys[e.code] = true;
}

onkeyup = function(e) {
	delete pressedKeys[e.code];
}
В pressedKeys находятся зажатые клавиши.

Вот улучшенный вариант... Класс PressedKeysRegistry позволяет включать/выключать отслеживание нажатых клавиш, также используется метод addEventListener, чтобы вы могли добавить и другие обработчики событии keydown и keyup.
<canvas id="app" width="300" height="300" style="border: solid;"></canvas>
<script>

function PressedKeysRegistry() {
	this.handler = this.handler.bind(this);
}

PressedKeysRegistry.prototype = {
	constructor: PressedKeysRegistry,
	start: function() {
		addEventListener("keydown", this.handler);
		addEventListener("keyup", this.handler);
	},
	stop: function() {
		removeEventListener("keydown", this.handler);
		removeEventListener("keyup", this.handler);
	},
	handler: function(event) {
		if(event.type === "keydown") {
			if(this[event.code]) return;
			this[event.code] = true;
		} else if(event.type === "keyup") {
			delete this[event.code];
		}
	}
};

// пример
var pressedKeys = new PressedKeysRegistry();
pressedKeys.start();
var player = { x: 50, y: 50 };
var field = { width: 100, height: 100 };
var ctx = app.getContext("2d");

(function loop() {
	ctx.clearRect(0, 0, app.width, app.height);
	ctx.fillRect(player.x / field.width * app.width, player.y / field.height * app.height, 20, 20);
	
	if("KeyD" in pressedKeys) player.x++;
	if("KeyA" in pressedKeys) player.x--;
	if("KeyS" in pressedKeys) player.y++;
	if("KeyW" in pressedKeys) player.y--;

	setTimeout(loop, 50);
})();

</script>

j0hnik 02.08.2019 06:03

Ставим влаги нажатым клавишам,вся соль в верхушке, остальное мишура (пример для простоты понимания, !не боевой код)
<div id="obj" style="width: 20px; height:20px; background-color:red; position:absolute; "></div>
  <script>

    var key = {
      87: 0,
      68: 0,
      83: 0,
      65: 0,
    };

    window.onkeydown = e => key[e.keyCode] = 1;
    window.onkeyup = e => key[e.keyCode] = 0;

    //остальное мишура
    var rct = obj.getBoundingClientRect();
    pos = [['top',rct.top],['left',rct.left]];
    
    (run =_=> {
      [[87,83],[65,68]].forEach((tl, x)=> tl.forEach((el, i)=> {
        if(key[el]) {
          pos[x][1] += i ? 1 : -1;
          obj.style[pos[x][0]] = pos[x][1]+'px';
        }
      }));
      setTimeout(run, 50);
    })();

  </script>

рони 02.08.2019 07:50

Цитата:

Сообщение от Malleys
var field = { width: 100, height: 100 };

для чего это?

Malleys 02.08.2019 13:52

Цитата:

Сообщение от j0hnik
Ставим влаги нажатым клавишам,вся соль в верхушке, остальное мишура (пример для простоты понимания, !не боевой код)

А в примере выше не тоже самое? И как 87, 68, 83, 65 может быть лёгким для понимания? У вас получается, что правый и левый shift одно и тоже! Live expression в консоли показывает {16: 1, 65: 0, 68: 0, 83: 0, 87: 0} Так какая именно клавиша нажата? Кстати у вас происходит раздувание объекта после других нажатии!

В моём примере вы можете узнать, нажат ли правый shift, или левый или оба, цифра 2 нажата на цифровой клавиатуре или нет. Если не поняли, то вот с пример с информацией о нажатых клавишах... Нажмите кнопку Посмотреть!, а затем нажмите на пустое появившееся поле, чтобы оно могло ловить нажатия клавиш!
<p id="info"></p>
<script>
var pressedKeys = {};

onkeydown = function(e) {
	if(e.code in pressedKeys) return;
	pressedKeys[e.code] = true;
};

onkeyup = function(e) {
	delete pressedKeys[e.code];
};

(function loop() {
	info.textContent = Object.keys(pressedKeys).join(", ");
	setTimeout(loop, 50);
})();
</script>


Цитата:

Сообщение от рони
для чего это?

Размер игрового поля.

j0hnik 02.08.2019 16:56

Malleys,
Я в курсе всего очевидного что вы написали, про шифты тут вообще без разницы, они не участвуют.
Пример демонстрирует идею!, но раз у вас на душе не спокойно то добавьте.Object.preventExtensions(key);

рони 02.08.2019 17:17

Цитата:

Сообщение от Malleys
Размер игрового поля.

ок.

Malleys 02.08.2019 18:35

Цитата:

Сообщение от j0hnik
про шифты тут вообще без разницы, они не участвуют.

Если человек не указал все клавиши, которые используются/будут использоваться в игре, то это не значит, что это не важно. В играх такое различие как раз важно!

Цитата:

Сообщение от j0hnik
Object.preventExtensions(key);

Оно и без этого работает... Я про то, что для игр лучше использовать KeyboardEvent.prototype.key или KeyboardEvent.prototype.code, а не KeyboardEvent.prototype.keyCode

j0hnik 02.08.2019 18:48

Цитата:

Сообщение от Malleys
Оно и без этого работает...

Это что не было эффекта
Цитата:

Сообщение от Malleys
происходит раздувание объекта после других нажатии!

ок, не знаю ни одной игры где шифты по разному работают, но учту ваше замечание ;)


Часовой пояс GMT +3, время: 14:04.