Как назначить клавишу со стрелкой для кнопки в C#?
Прямо сейчас я делаю игру, и в ней есть персонаж для перемещения игрока. Я просто новичок в программировании.
Есть 8 кнопок, и каждая кнопка идет в направлении. Например, это моя программа для
private void btnUp_Click(object sender, EventArgs e)
{
//move up
y = y - 1;
MovePlayer();
UpdateLabelLocation();
}
public void MovePlayer()
{
picPlayer.Location = new Point(x, y);
}
public void UpdateLabelLocation()
{
lblLocation.Text = "Location: (" + x + ", " + y + ")";
}
Я хочу заставить его двигаться, когда я нажимаю клавиши вверх, вниз, влево или вправо. Также, если возможно, я хочу сделать так, чтобы при нажатии одновременно вправо и вверх это вызывало:
private void btnRightUp_Click(object sender, EventArgs e)
{
//move player
y = y - 1;
x = x + 1;
MovePlayer();
UpdateLabelLocation();
}
Я ценю помощь.
1 ответ
По сути, вы создаете свой собственный простой игровой движок. Как отметили комментаторы, вам лучше использовать существующий игровой движок, такой как Unity. Это гораздо проще и более раскрепощенно, чем работать с WinForms.
Тем не менее, если вы действительно хотите продолжить это, я настоятельно рекомендую вам переместить код в Click
обработчики метода. Это уменьшает дублирование кода. т.е.
private void DownButton_Click(...)
{
MovePlayer(0, 1);
}
private void UpButton_Click(...)
{
MovePlayer(0, -1);
}
public void MovePlayer(float xStep, float yStep)
{
x += xStep;
y += yStep;
MovePlayer();
UpdateLabelLocation();
}
Чтобы двигаться вниз и влево, вы бы позвонили MovePlayer(-1, 1);
Чтобы двигаться вверх и вправо, вы бы позвонили MovePlayer(1, -1);
Далее вам нужно будет ответить на события KeyPress. т.е.
public void Form_KeyPress(object sender, KeyPressEventArgs args)
{
switch (args.KeyChar) {
case 'a': // Left
args.Handled = true;
MovePlayer(-1, 0);
break;
case 'd': // Right
args.Handled = true;
MovePlayer(1, 0);
break;
case 'w': // Up
args.Handled = true;
MovePlayer(0, -1);
break;
case 's': // Down
args.Handled = true;
MovePlayer(0, 1);
break;
}
}
Обратите внимание, что если у вас есть другой элемент управления, который принимает ввод с клавиатуры (например, TextBox
), он будет перехватывать нажатие клавиши. Чтобы обойти это, используйте KeyPreview, чтобы заставить окно предварительно просмотреть ввод. args.Handled = true
предотвращает маршрутизацию события на дочерние элементы управления после вашего кода.
К сожалению, WinForms не записывает несколько нажатых клавиш одновременно, поэтому одного нажатия клавиши недостаточно для управления поворотом. Вы можете обойти это, подключив KeyDown и KeyUp, но это больше проблем, чем стоит.
Вот более надежное решение. Имейте в виду, что следующее не является потокобезопасным, поэтому, если вы планируете вводить другие потоки, вам нужно использовать соответствующую блокировку.
HashSet<KeyCode> state = new HashSet<KeyCode>();
float speed = 120; // 120 pixels/second.
private void Form_KeyDown(object sender, KeyEventArgs args)
{
var key = args.KeyCode;
state.Add(key);
// Fire pressed when a key was up.
if (!state.Contains(key)) {
state.Add(key);
OnKeyPressed(key);
}
}
private void Form_KeyUp(object sender, KeyEventArgs args)
{
var key = args.KeyCode;
state.Remove(key);
// Fire release when a key was down.
if (state.Contains(key)) {
state.Remove(key);
OnKeyReleased(key);
}
}
// Runs when key was up, but pressed just now.
private void OnKeyPressed(KeyCode key)
{
// Trigger key-based actions.
}
// Runs when key was down, but released just now.
private void OnReleased(KeyCode key)
{
// Trigger key-based actions, but on release instead of press.
}
private bool IsDown(KeyCode key)
{
return state.Contains(key);
}
// Trigger this periodically, at least 20 times a second(ideally 60).
// An option to get you started is to use a windows timer, but
// eventually you'll want to use high precision timing instead.
private void Update()
{
var deltaTime = // Calculate the seconds that have passed since the last update.
// Describing it is out of the scope of this answer, but see the links below.
// Determine horizontal direction. Holding both
// A & D down cancels movement on the x-axis.
var directionX = 0;
if (IsDown(KeyCode.A)) {
directionX--;
}
if (IsDown(KeyCode.D)) {
directionX++;
}
// Determine vertical direction. Holding both
// W & S down cancels movement on the y-axis.
var directionY = 0;
if (IsDown(KeyCode.W)) {
directionY--;
}
if (IsDown(KeyCode.S)) {
directionY++;
}
// directionX & directionY should be normalized, but
// I leave that as an exercise for the reader.
var movement = speed * deltaTime;
var offsetX = directionX * movement;
var offsetY = directionY * movement;
MovePlayer(offsetX, offsetY);
}
Как вы можете видеть, в этом есть немало проблем. Если вы хотите более детальный выбор времени, загляните в эту статью. В конце концов вам захочется перейти к игровому циклу, но это еще одна тема, выходящая за рамки этого ответа.