Всем привет! Создаю игру, в ней (как не удивительно) можно нажимать на клавиши и управлять персонажем. Как я могу при нажатии на определенные клавиши заблокировать нажатие других на некоторое время? Хотела применить многопоточность, однако не совсем понимаю, как это сделать. Есть пример такого кода, где я пытаюсь создать поток при нажатии на клавишу:
protected override void OnKeyDown(KeyEventArgs e)
{
Thread t = new Thread(() => PlayerControl.KeyDown(player, e));
t.Start();
}
Во-первых, этот код не работает, как должен, т.к. все нажатия воспринимаются абсолютно так же и Thread.Sleep(), который я вызываю в методе PlayerControl.KeyDown(), не заставляет поток "уснуть", тем самым заблокировав клавиатуру. Во-вторых, я понимаю, что это неправильно, ведь новый поток создается каждый раз, когда происходит обработка нажатия на клавишу, что очень даже плохо. Как все-таки реализовать это? Если есть способы и без использования классов Threading и Threading.Tasks, буду только рада выслушать =)
Реализация персонажа:
public class Player : RigidBody
{
public EntityState State { get; set; } = EntityState.Idle;
public int Damage { get; set; }
public int HealthPoint { get; set; }
public float Width { get; set; }
public float Height { get; set; }
public float Speed { get; set; } = 20f;
public RectangleF Hitbox { get; set; }
public float JumpForce { get; set; } = 50;
public float RollForce { get; set; } = 60;
public Direction Direction { get; set; } = Direction.Left;
public Player(PointF startPoint, SizeF size) : base()
{
Width = size.Width;
Height = size.Height;
Hitbox = new RectangleF(Position, new SizeF(Width, Height));
Position = startPoint;
}
public Player(PointF startPoint, SizeF size, int hp, int dmg) : base()
{
Width = size.Width;
Height = size.Height;
Hitbox = new RectangleF(Position, new SizeF(Width, Height));
Position = startPoint;
HealthPoint = hp;
Damage = dmg;
}
public void Run()
{
Force = Direction == Direction.Right ? new Vector2(Speed, 0) : new Vector2(-Speed, 0);
}
public void StopRun()
{
Force = new Vector2(0, 0);
}
public void Jump()
{
if (Collisions.HasCollision(Hitbox).OnGround)
Velocity = new Vector2(Velocity.X, Velocity.Y - JumpForce);
}
public void Roll()
{
if (Collisions.HasCollision(Hitbox).OnGround)
Velocity = Direction == Direction.Right
? new Vector2(RollForce, Velocity.Y)
: new Vector2(-RollForce, Velocity.Y);
}
public void Hook()
{
Velocity = Vector2.Zero;
Force = Vector2.Zero;
Velocity = new Vector2(-(Position.X - World.Monster.Position.X) * 0.7f, -(Position.Y - World.Monster.Position.Y) * 0.7f);
}
public override void Update(float dt)
{
Hitbox = new RectangleF(new PointF(Position.X, Position.Y),
new SizeF(Width, Height));
var collision = Collisions.HasCollision(Hitbox);
if (collision.OnGround)
OnGroundCollision(collision.Platform.Position.Y - Height);
CollisionWithMonster();
base.Update(dt);
}
}
Реализация его контроллера:
public static class PlayerControl
{
private static bool IsHooking = false;
private static bool IsJumping = false;
private static bool IgnoreFloor;
public static void KeyDown(Player player, KeyEventArgs e)
{
if (e.KeyCode == Keys.D)
{
player.Direction = Direction.Right;
player.State = EntityState.Move;
player.Run();
}
if (e.KeyCode == Keys.A)
{
player.Direction = Direction.Left;
player.State = EntityState.Move;
player.Run();
}
if (e.KeyCode == Keys.Space && !IsJumping)
{
IsJumping = true;
player.State = EntityState.Up;
player.Jump();
}
if (e.KeyCode == Keys.Z)
{
player.State = EntityState.Roll;
player.Roll();
}
if (e.KeyCode == Keys.R)
{
player.Hook();
}
}
public static void KeyUp(Player player, KeyEventArgs e)
{
if (e.KeyCode == Keys.D || e.KeyCode == Keys.A)
{
player.StopRun();
}
if (e.KeyCode == Keys.Space)
{
IsJumping = false;
}
}
}
bool holdи проверяйтеif (hold) return;. И этот код до боли мне Unity напоминает. Вот пример, как я делал управление. – aepot May 07 '22 at 17:58ifи однаboolвас спасут. И не лезьте в многопоточку, с ней много проблем будет, например с UI компонентами можно работать только из основного потока. Если уж вам надо несколько дел одновременно делать, есть таймеры и асинхронность. https://ru.stackoverflow.com/a/1257322/373567, плюс изучите шаблон многопоточного проектирования Producer/Consumer, это даст больше свободы в понимании, как перекачивать данные и события из потока в поток и обратно. – aepot May 07 '22 at 18:08IsRollingсделатьtrue, когда закончится, то сделатьfalse– alecs May 07 '22 at 18:16