如何将箭头键分配给 C# 中的按钮?
How to assign an arrow key to a button in 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();
}
感谢您的帮助。
您实际上是在创建自己的简单游戏引擎。正如评论员所指出的,您最好使用现有的游戏引擎,例如 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 强制 window 先预览输入。 args.Handled = true
防止事件在您的代码之后路由到子控件。
不幸的是,WinForms 不记录同时按下的多个键,因此单独使用 KeyPress 不足以处理角移动。您可以通过连接到 KeyDown and 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);
}
如您所见,涉及的内容很多。如果您想要更精细的时间安排,请查看 this article. Eventually you'll want to transition to a game loop,但这是本答案范围之外的另一个主题。
现在我正在制作游戏和其中的角色来移动玩家。我只是编程的初学者。
一共有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();
}
感谢您的帮助。
您实际上是在创建自己的简单游戏引擎。正如评论员所指出的,您最好使用现有的游戏引擎,例如 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 强制 window 先预览输入。 args.Handled = true
防止事件在您的代码之后路由到子控件。
不幸的是,WinForms 不记录同时按下的多个键,因此单独使用 KeyPress 不足以处理角移动。您可以通过连接到 KeyDown and 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);
}
如您所见,涉及的内容很多。如果您想要更精细的时间安排,请查看 this article. Eventually you'll want to transition to a game loop,但这是本答案范围之外的另一个主题。