This article is currently in the process of being translated into Portuguese (~29% done).

Criando um jogo: SnakeWPF:
Chapter introduction:

In this article series, we're building a complete Snake game from scratch. It makes sense to start with the Introduction and then work your way through the articles one by one, to get the full understanding.

If you want to get the complete source code for the game at once, to get started modifying and learning from it right now, consider downloading all our samples!

Improving SnakeWPF: Making it look more like a game

Nos últimos artigos, construímos um jogo Snake em WPF. Implementamos todo o mecanismo do jogo e o resultado foi um jogo completamente funcional. Contudo, existe muitos melhoramentos que podemos fazer pois a implementação actual é minimalista. Portanto, nos próximos artigos vamos fazer diversos melhoramentos ao nosso jogo SnakeWPF - neste artigo vamos nos forcar em melhorar o aspecto visual para que se pareça mais com um jogo!

A nossa implementação actual não se parece como a de um jogo por causa do estilo por defeito da janela, seus contornos e a barra. Porém, já utilizámos préviamente a barra do título para mostrar informações relativas ao resultado, velocidade e o bonus. Temos também os botões habituais do windows para minimizar, maximizar e fechar a janela:

At this point, I would like to completely remove the default Windows title bar and instead implement our own top status bar, which should show the current score and speed, as well as a customized close button. All of it should match the current look of the game. Fortunately for us, this is quite easy to accomplish with WPF.

Adding a custom title bar

The first step is to add a couple of properties and a new event to the Window declaration. It should now look like this:

<Window x:Class="WpfTutorialSamples.Games.SnakeWPFSample"
Title="SnakeWPF - Score: 0" SizeToContent="WidthAndHeight" ContentRendered="Window_ContentRendered" KeyUp="Window_KeyUp"
ResizeMode="NoResize" WindowStyle="None" Background="Black" MouseDown="Window_MouseDown">

The changes are all in the last line. We set the ResizeMode to NoResize and the WindowStyle to None. This will completely remove the title bar as well as any default borders around the Window - that's no problem for us though, because the main area of our game already has a 5 px black border.

You will also notice that I have subscribed to a new event - the MouseDown event. The reason is that since we lose the default title bar, there's no longer any way for the user to drag the game from one point of the screen to another. Fortunately for us, it's easy to re-create this behavior, e.g. on our own, custom title bar. However, since it doesn't look like the regular title bar, the user might be confused about where to drag, so I decided simply to make the entire window surface draggable. So, in your Code-behind, define the Window_MouseDown event handler like this:

private void Window_MouseDown(object sender, MouseButtonEventArgs e)

With that in place, your window can be dragged around no matter where you use the mouse. The next step is to add our custom title bar, which should display the score and speed, as well as a close button. The inner part of the Window XAML should now look like this:

<DockPanel Background="Black">  
    <Grid DockPanel.Dock="Top" Name="pnlTitleBar">  
    <ColumnDefinition Width="*" />  
    <ColumnDefinition Width="*" />  
    <ColumnDefinition Width="Auto" />  

    <Style TargetType="TextBlock">  
<Setter Property="FontFamily" Value="Consolas" />  
<Setter Property="Foreground" Value="White" />  
<Setter Property="FontSize" Value="24" />  
<Setter Property="FontWeight" Value="Bold" />  

<WrapPanel Margin="10,0,0,0">  
    <TextBlock Name="tbStatusScore">0</TextBlock>  
<WrapPanel Grid.Column="1">  
    <TextBlock Name="tbStatusSpeed">0</TextBlock>  
<Button Grid.Column="2" DockPanel.Dock="Right" Background="Transparent" Foreground="White" FontWeight="Bold" FontSize="20" BorderThickness="0" Name="btnClose" Click="BtnClose_Click" Padding="10,0">X</Button>  
    <Border BorderBrush="Black" BorderThickness="5">  
<Canvas Name="GameArea" ClipToBounds="True" Width="400" Height="400">  


E não se esqueça de definir o evento BtnClose_Click

private void BtnClose_Click(object sender, RoutedEventArgs e)

Nós anteriormente implementamos um método chamado UpdateGameStatus(), que atualizava a propriedade Titulo da nossa janela - esse método deverá ser alterado para usar os novos TextBlock's:

private void UpdateGameStatus()
    this.tbStatusScore.Text = currentScore.ToString();
    this.tbStatusSpeed.Text = gameTickTimer.Interval.TotalMilliseconds.ToString();

Vou lhe contar tudo sobre o que acabamos de fazer, mas primeiro, vamos verificar a aparência do jogo agora :

It looks quite a bit cooler, right? But let's discuss what we just did: As you can see, the original Border control with the GameArea Canvas inside of it has now been surrounded by a DockPanel. This makes it easy for us to attach our new title bar, in the form of a Grid panel, to the top of the Window.

The Grid uses several cool WPF techniques which have been discussed elsewhere in this tutorial: We use ColumnDefinition's to divide the area into two equally sized areas (for the score and speed), plus an auto-sized third column for the close button. You will also notice that we use WPF Style's to apply the same visual look to all the TextBlock controls - the same custom font, font size, color and weight are applied to all of them, thanks to a Style defined in the Grid, targeting TextBlock controls.

Also notice how easy it is to customize the Button control used for closing the window, to completely match the rest of the look and feel of the game, simply by using the standard properties - WPF is so flexible!


Neste artigo, fizemos nossa implementação do SnakeWPF parecer muito mais com um jogo, removendo a aparência padrão do Windows e aplicando nossa própria barra de título personalizada. Nos próximos artigos, faremos muito mais melhorias!

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!