patterncsharpMinor
Basic console game architecture
Viewed 0 times
consolegamebasicarchitecture
Problem
I'm working on some simple console game and I'm starting to get stranded in my modelling. There is some fragmentation and tight coupling going on!
In this version I would just want to be able to move my paddle over the screen (but this needs to be extended to multiple players, ill get back to that later).
This paddle is modeled as follows:
```
public class Paddle : IDynamicRenderable, ICommandObserver
{
public int Top { get; private set; }
public int Left { get; private set; }
public bool RenderStateChanged { get; private set; }
private int LastTop { get; set; }
private int LastLeft { get; set; }
private Dictionary configuration;
public Paddle()
{
Top = LastTop = 10;
Left = LastLeft = 35;
RenderStateChanged = false;
configuration = new Dictionary()
{
{ "UpCommand", ConsoleKey.UpArrow },
{ "DownCommand", ConsoleKey.DownArrow },
{ "LeftCommand", ConsoleKey.LeftArrow },
{ "RightCommand", ConsoleKey.RightArrow }
};
Draw();
}
public void Render()
{
Clear();
Draw();
RenderStateChanged = false;
}
private void Draw()
{
Console.SetCursorPosition(Left, Top);
Console.Write('█');
}
private void Clear()
{
Console.SetCursorPosition(LastLeft, LastTop);
Console.Write(' ');
}
public void Notify(ConsoleKey consoleCommand)
{
if (consoleCommand == configuration["DownCommand"])
{
LastLeft = Left;
LastTop = Top;
Top += 1;
RenderStateChanged = true;
}
else if (consoleCommand == configuration["UpCommand"])
{
LastLeft = Left;
LastTop = Top;
Top -= 1;
RenderStateChanged = true;
}
else if (consoleCommand == configuration["LeftCommand"])
In this version I would just want to be able to move my paddle over the screen (but this needs to be extended to multiple players, ill get back to that later).
This paddle is modeled as follows:
```
public class Paddle : IDynamicRenderable, ICommandObserver
{
public int Top { get; private set; }
public int Left { get; private set; }
public bool RenderStateChanged { get; private set; }
private int LastTop { get; set; }
private int LastLeft { get; set; }
private Dictionary configuration;
public Paddle()
{
Top = LastTop = 10;
Left = LastLeft = 35;
RenderStateChanged = false;
configuration = new Dictionary()
{
{ "UpCommand", ConsoleKey.UpArrow },
{ "DownCommand", ConsoleKey.DownArrow },
{ "LeftCommand", ConsoleKey.LeftArrow },
{ "RightCommand", ConsoleKey.RightArrow }
};
Draw();
}
public void Render()
{
Clear();
Draw();
RenderStateChanged = false;
}
private void Draw()
{
Console.SetCursorPosition(Left, Top);
Console.Write('█');
}
private void Clear()
{
Console.SetCursorPosition(LastLeft, LastTop);
Console.Write(' ');
}
public void Notify(ConsoleKey consoleCommand)
{
if (consoleCommand == configuration["DownCommand"])
{
LastLeft = Left;
LastTop = Top;
Top += 1;
RenderStateChanged = true;
}
else if (consoleCommand == configuration["UpCommand"])
{
LastLeft = Left;
LastTop = Top;
Top -= 1;
RenderStateChanged = true;
}
else if (consoleCommand == configuration["LeftCommand"])
Solution
I'm going architectural because coupling is an architectural issue and there is a fairly common general architecture for screen oriented games.
Game Engine
I think it will be difficult to create a screen oriented game without using a traditional game loop architecture. The basic loop might look like:
In the abstract screen oriented games are simple: every so often, process the event queue and update the screen. A screen oriented game is a controlled animation.
Events
The basic event in any animation is the the transition to the next frame. To insure that there is a next frame, games have timers to generate events. Keypress events are less frequent.
All the bussiness logic is in the handlers for events. The handlers transform events into messages and send them to the screen.
Screen
A screen interprets the messages and creates and then executes a set of instructions for painting the screen. The screen is where logic that scrolls the display or bounces a ball off a paddle lives.
Sprites
Given a location and a "color", a sprite knows how to draw itself. That's it. A sprite does not know anything about screens or events. It doesn't know anything about why it is being drawn. For example, if
might be executed by a screen in response to some particular event.
Game State
Their can be a data structure sitting above all this which keeps track of game configuration such as the list of high scores or the mapping of logical keys like
Analysis
The big issue is that
The second issue is that there are no timer events, so besides the paddle, there aren't a lot of places for
Game Engine
I think it will be difficult to create a screen oriented game without using a traditional game loop architecture. The basic loop might look like:
while(true) {
timerState = timerList.tick(timerState);
keyboardState = keyboardState.nextState(keyboardState);
UpdateScreen(timerState, keyboardState);
pause(frameRate);
}In the abstract screen oriented games are simple: every so often, process the event queue and update the screen. A screen oriented game is a controlled animation.
Events
The basic event in any animation is the the transition to the next frame. To insure that there is a next frame, games have timers to generate events. Keypress events are less frequent.
All the bussiness logic is in the handlers for events. The handlers transform events into messages and send them to the screen.
Screen
A screen interprets the messages and creates and then executes a set of instructions for painting the screen. The screen is where logic that scrolls the display or bounces a ball off a paddle lives.
Sprites
Given a location and a "color", a sprite knows how to draw itself. That's it. A sprite does not know anything about screens or events. It doesn't know anything about why it is being drawn. For example, if
paddle1 is a sprite:paddle1.draw(paddle1.x, (paddle1.y + player1.paddle().delta_y), foregroundColor);might be executed by a screen in response to some particular event.
Game State
Their can be a data structure sitting above all this which keeps track of game configuration such as the list of high scores or the mapping of logical keys like
paddle_move_up to physical keys such as w.Analysis
The big issue is that
paddles know too much...or rather way way too much. They know about the hardware [key presses], they know about rendering, eventually they will have to know about other paddles.The second issue is that there are no timer events, so besides the paddle, there aren't a lot of places for
render() to live.Code Snippets
while(true) {
timerState = timerList.tick(timerState);
keyboardState = keyboardState.nextState(keyboardState);
UpdateScreen(timerState, keyboardState);
pause(frameRate);
}paddle1.draw(paddle1.x, (paddle1.y + player1.paddle().delta_y), foregroundColor);Context
StackExchange Code Review Q#67803, answer score: 3
Revisions (0)
No revisions yet.