Tetris Movement - Implementation
Posted
by
James Brauman
on Game Development
See other posts from Game Development
or by James Brauman
Published on 2011-02-17T07:30:03Z
Indexed on
2011/02/17
7:33 UTC
Read the original article
Hit count: 306
Hi gamedev, I'm developing a Tetris clone and working on the input at the moment.
When I was prototyping, movement was triggered by releasing a directional key. However, in most Tetris games I've played the movement is a bit more complex.
When a directional key is pressed, the shape moves one space in that direction. After a short interval, if the key is still held down, the shape starts moving in the direction continuously until the key is released.
In the case of the down key being pressed, there is no pause between the initial movement and the subsequent continuous movement.
I've come up with a solution, and it works well, but it's totally over-engineered. Hey, at least I can recognize when things are getting silly, right? :)
public class TetrisMover
{
List registeredKeys;
Dictionary continuousPressedTime;
Dictionary totalPressedTime;
Dictionary initialIntervals;
Dictionary continousIntervals;
Dictionary keyActions;
Dictionary initialActionDone;
KeyboardState currentKeyboardState;
public TetrisMover()
{
*snip*
}
public void Update(GameTime gameTime)
{
currentKeyboardState = Keyboard.GetState();
foreach (Keys currentKey in registeredKeys)
{
if (currentKeyboardState.IsKeyUp(currentKey))
{
continuousPressedTime[currentKey] = TimeSpan.Zero;
totalPressedTime[currentKey] = TimeSpan.Zero;
initialActionDone[currentKey] = false;
}
else
{
if (initialActionDone[currentKey] == false)
{
keyActions[currentKey]();
initialActionDone[currentKey] = true;
}
totalPressedTime[currentKey] += gameTime.ElapsedGameTime;
if (totalPressedTime[currentKey] >= initialIntervals[currentKey])
{
continuousPressedTime[currentKey] += gameTime.ElapsedGameTime;
if (continuousPressedTime[currentKey] >= continousIntervals[currentKey])
{
keyActions[currentKey]();
continuousPressedTime[currentKey] = TimeSpan.Zero;
}
}
}
}
}
public void RegisterKey(Keys key, TimeSpan initialInterval, TimeSpan continuousInterval, Action keyAction)
{
if (registeredKeys.Contains(key))
throw new InvalidOperationException(
string.Format("The key %s is already registered.", key));
registeredKeys.Add(key);
continuousPressedTime.Add(key, TimeSpan.Zero);
totalPressedTime.Add(key, TimeSpan.Zero);
initialIntervals.Add(key, initialInterval);
continousIntervals.Add(key, continuousInterval);
keyActions.Add(key, keyAction);
initialActionDone.Add(key, false);
}
public void UnregisterKey(Keys key)
{
*snip*
}
}
I'm updating it every frame, and this is how I'm registering keys for movement:
tetrisMover.RegisterKey(
Keys.Left, keyHoldStartSpecialInterval, keyHoldMovementInterval,
() => { Move(Direction.Left); });
tetrisMover.RegisterKey(
Keys.Right, keyHoldStartSpecialInterval, keyHoldMovementInterval,
() => { Move(Direction.Right); });
tetrisMover.RegisterKey(
Keys.Down, TimeSpan.Zero, keyHoldMovementInterval,
() => { PerformGravity(); });
Issues that this doesn't address:
- If both left and right are held down, the shape moves back and forth really quick.
- If a directional key is held down and the turn finishes and the shape is replaced by a new one, the new one will move quickly in that direction instead of the little pause it is supposed to have.
I could fix the issues, but I think it will make the solution even worse. How would you implement this?
© Game Development or respective owner