right now I'm making a game and a character in it to move the player. I'm just a beginner about programming.
There are 8 buttons, and each button goes to a direction. For example, this my program for
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 + ")";
}
I want to make it move when I press up, down, left or right keys. Also, if possible I want to make it so that when I press right and up at the same time, it triggers this:
private void btnRightUp_Click(object sender, EventArgs e)
{
//move player
y = y - 1;
x = x + 1;
MovePlayer();
UpdateLabelLocation();
}
I appreciate the help.
What you're essentially doing is creating your own simple game engine. As commentors have noted, you're better off using an existing game engine such as Unity. It's far easier and more liberating than going about it with WinForms.
That said, if you really want to continue with this, I strongly suggest you move the code in the Click
handlers to a method. This reduces code duplication. i.e.
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();
}
To move down and left you'd call MovePlayer(-1, 1);
To move up and right you'd call MovePlayer(1, -1);
Next you'll need to respond to KeyPress events. i.e.
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;
}
}
Note that if you have another control that accepts keyboard input(such as a TextBox
), it will intercept the key press. To get around this, use KeyPreview to force the window to preview the input first. args.Handled = true
prevents the event from routing to child controls after your code.
Unfortunately WinForms doesn't record multiple keys pressed at the same time, so using KeyPress alone isn't enough to handle corner movement. You can work around this by hooking onto KeyDown and KeyUp, but it's more trouble than it's worth.
Here's a more robust solution. Bear in mind the following isn't thread safe, so if you plan on introducing other threads you'll need to use appropriate locking.
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);
}
As you can see, there's quite a bit involved. If you want more fine-grained timing, look into this article. Eventually you'll want to transition to a game loop, but that's yet another topic out of the scope of this answer.