This article has been localized into Vietnamese by the community.
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!
Cải thiện SnakeWPF: Làm cho nó trông giống một trò chơi hơn
Trong vài bài viết trước, chúng tôi đã xây dựng một trò chơi Snake thú vị trong WPF. Chúng tôi đã thực hiện tất cả các cơ chế trò chơi và kết quả là một trò chơi đầy đủ chức năng. Tuy nhiên, chắc chắn có rất nhiều cải tiến có thể được thực hiện, bởi vì việc triển khai hiện tại là rất tối thiểu. Vì vậy, trong các bài viết tiếp theo, tôi sẽ thực hiện một số cải tiến cho trò chơi SnakeWPF của chúng tôi - trong bài viết này, tôi sẽ tập trung vào việc làm cho trò chơi của chúng tôi trông giống như một trò chơi thực tế!
Như hiện tại, với thanh viền/tiêu đề mặc định của Windows, việc triển khai của chúng tôi không giống như một trò chơi. Tuy nhiên, trước đây chúng tôi cần thanh tiêu đề để hiển thị thông tin điểm/tốc độ và như một phần thưởng tuyệt vời, chúng tôi tự động có các nút Windows mặc định để thu nhỏ/phóng to/ đóng cửa sổ:
Tại thời điểm này, tôi muốn xóa hoàn toàn thanh tiêu đề mặc định của Windows và thay vào đó thực hiện thanh trạng thái của riêng chúng tôi, sẽ hiển thị điểm và tốc độ hiện tại, cũng như nút đóng tùy chỉnh. Tất cả phải phù hợp với giao diện hiện tại của trò chơi. May mắn cho chúng tôi, điều này khá dễ thực hiện với WPF.
Thêm một thanh tiêu đề tùy chỉnh
Bước đầu tiên là thêm một vài thuộc tính và một sự kiện mới vào khai báo Window. Bây giờ nó sẽ trông như thế này:
<Window x:Class="WpfTutorialSamples.Games.SnakeWPFSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfTutorialSamples.Games"
mc:Ignorable="d"
Title="SnakeWPF - Score: 0" SizeToContent="WidthAndHeight" ContentRendered="Window_ContentRendered" KeyUp="Window_KeyUp"
ResizeMode="NoResize" WindowStyle="None" Background="Black" MouseDown="Window_MouseDown">
Những thay đổi là tất cả trong dòng cuối cùng. Chúng tôi đặt ResizeMode thành NoResize và WindowStyle thành None. Điều này sẽ loại bỏ hoàn toàn thanh tiêu đề cũng như mọi đường viền mặc định xung quanh Window - điều đó không có vấn đề gì với chúng tôi, vì khu vực chính của trò chơi của chúng tôi đã có viền đen 5 px.
Bạn cũng sẽ nhận thấy rằng tôi đã đăng ký một sự kiện mới - sự kiện MouseDown. Lý do là vì chúng tôi mất thanh tiêu đề mặc định, người dùng không còn có thể kéo trò chơi từ điểm này sang điểm khác trên màn hình nữa. May mắn thay cho chúng tôi, thật dễ dàng để tạo lại hành vi này, ví dụ như trên thanh tiêu đề tùy chỉnh của riêng chúng tôi. Tuy nhiên, vì nó không giống như thanh tiêu đề thông thường, người dùng có thể bị nhầm lẫn về nơi kéo, vì vậy tôi quyết định chỉ đơn giản là làm cho toàn bộ bề mặt cửa sổ có thể kéo được. Vì vậy, trong Code-behind của bạn, hãy xác định trình xử lý sự kiện Window_MouseDown như thế này:
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
Với vị trí đó, cửa sổ của bạn có thể được kéo xung quanh bất kể bạn sử dụng chuột ở đâu. Bước tiếp theo là thêm thanh tiêu đề tùy chỉnh của chúng tôi, sẽ hiển thị điểm số và tốc độ, cũng như một nút đóng. Phần bên trong của Window XAML sẽ trông như thế này:
<DockPanel Background="Black">
<Grid DockPanel.Dock="Top" Name="pnlTitleBar">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontFamily" Value="Consolas" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="24" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
</Grid.Resources>
<WrapPanel Margin="10,0,0,0">
<TextBlock>Score:</TextBlock>
<TextBlock Name="tbStatusScore">0</TextBlock>
</WrapPanel>
<WrapPanel Grid.Column="1">
<TextBlock>Speed:</TextBlock>
<TextBlock Name="tbStatusSpeed">0</TextBlock>
</WrapPanel>
<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>
</Grid>
<Border BorderBrush="Black" BorderThickness="5">
<Canvas Name="GameArea" ClipToBounds="True" Width="400" Height="400">
</Canvas>
</Border>
</DockPanel>
Và đừng quên xác định trình xử lý sự kiện BtnClose_Click:
private void BtnClose_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
Trước đây chúng tôi đã triển khai một phương thức có tên UpdateGameStatus(), cập nhật thuộc tính Title của Window - nên thay đổi phương thức này để sử dụng TextBlock mới:
private void UpdateGameStatus()
{
this.tbStatusScore.Text = currentScore.ToString();
this.tbStatusSpeed.Text = gameTickTimer.Interval.TotalMilliseconds.ToString();
}
Tôi sẽ nói với bạn tất cả về những gì chúng tôi vừa làm, nhưng trước tiên, hãy xem thử trò chơi bây giờ như thế nào:
Nó trông khá đẹp, phải không? Nhưng hãy thảo luận về những gì chúng ta vừa làm: Như bạn có thể thấy, điều khiển Border ban đầu với GameArea Canvas bên trong nó hiện đã được bao quanh bởi DockPanel. Điều này giúp chúng tôi dễ dàng gắn thanh tiêu đề mới của mình, dưới dạng bảng điều khiển Grid, lên trên cùng của Window.
Grid sử dụng một số kỹ thuật WPF thú vị đã được thảo luận ở nơi khác trong hướng dẫn này: Chúng tôi sử dụng ColumnDefinition để chia khu vực thành hai khu vực có kích thước bằng nhau (cho điểm và tốc độ), cộng với cột thứ ba có kích thước tự động cho nút đóng. Bạn cũng sẽ nhận thấy rằng chúng tôi sử dụng WPF Style để áp dụng giao diện trực quan giống nhau cho tất cả các điều khiển TextBlock - cùng một phông chữ, kích thước phông chữ, màu sắc và trọng lượng tùy chỉnh được áp dụng cho tất cả chúng, nhờ một Style được xác định trong Grid, nhắm mục tiêu điều khiển TextBlock.
Cũng lưu ý cách dễ dàng tùy chỉnh Nút được sử dụng để đóng cửa sổ, để hoàn toàn khớp với phần còn lại của giao diện trò chơi, chỉ đơn giản bằng cách sử dụng các thuộc tính tiêu chuẩn - WPF rất linh hoạt!
Tổng kết
Trong bài viết này, chúng tôi đã làm cho việc triển khai SnakeWPF của chúng tôi trông giống một trò chơi hơn, bằng cách loại bỏ giao diện Windows tiêu chuẩn và áp dụng thanh tiêu đề tùy chỉnh của riêng chúng tôi. Trong các bài viết sắp tới, chúng tôi sẽ cải thiện nhiều hơn nữa!