24天学完C#第一篇
本章节中将要构建一个动物配对游戏,向玩家展示一个包含十六种动物的网格,玩家需要点击成对的动物使它们消失。
1. 如何构建游戏
首先要在VS中创建一个新的桌面应用项目、
使用XMAL构建窗口
编写C#代码想这个窗口增加后端逻辑
增加计时器

1.2 使用XMAL构建窗口
设计需求:窗口需要5行4列的网格建立布局;每个动物显示再一个TextBlock控件中;计时器显示在一个TexBlock中,放在最下面一行,横跨4列。
(选择主页面)

(修改窗口大小)

(修改窗口标题)

(为 XMAL网格增加行和列)

tips:此处宽度和高度中的1*代表比例。
(为网格增加TextBlock控件)
关于TextBlock的属性:
Text告诉TextBlock要在窗口中显示什么文本
HorizontalAlignment控制文本左、右对齐或水平居中
Margin设置它与其窗口四周的偏移量(页边距)
TextWarpping指出是否增加换行符将文本换行

<Window x:Class="MatchGame.MainWindow"
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:MatchGame"
mc:Ignorable="d"
Title="Find all of the matching animals" Height="450" Width="400">
<Grid Margin="1,1,-1,-1">
<!-- 划分网格 -->
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<!--第一行-->
<TextBlock Grid.Column="0" Grid.Row="0" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Grid.Row="0" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
<TextBlock Grid.Column="2" Grid.Row="0" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
<TextBlock Grid.Column="3" Grid.Row="0" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
<!--第二行-->
<TextBlock Grid.Column="0" Grid.Row="1" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Grid.Row="1" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
<TextBlock Grid.Column="2" Grid.Row="1" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
<TextBlock Grid.Column="3" Grid.Row="1" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
<!--第三行-->
<TextBlock Grid.Column="0" Grid.Row="2" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Grid.Row="2" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
<TextBlock Grid.Column="2" Grid.Row="2" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
<TextBlock Grid.Column="3" Grid.Row="2" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
<!--第四行-->
<TextBlock Grid.Column="0" Grid.Row="3" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Grid.Row="3" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
<TextBlock Grid.Column="2" Grid.Row="3" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
<TextBlock Grid.Column="3" Grid.Row="3" HorizontalAlignment="Center" FontSize="36" TextWrapping="Wrap" Text="?" VerticalAlignment="Center"/>
</Grid>
</Window>
1.3 使用C#编写后端
(打开主页面对应的cs文件)

(编写SetUpGame方法)
重命名网格的名字

public void SetUpGame() {
// 创建一个有关动物表情的容器并初始化
List<string> animalEmoji = new List<string>() {
"🐵","🐵",
"🐒","🐒",
"🦍 ","🦍",
"🐺 ","🐺 ",
"🦝 ","🦝 ",
"🐔 ","🐔 ",
"🐉 ","🐉 ",
"🕷 ","🕷 ",
};
//初始化一个Random对象
Random random = new Random();
//遍历在名为mainGird组件中所有类型为TextBlock的子集
foreach (TextBlock textBlock in mainGrid.Children.OfType<TextBlock>())
{
//随机生成一个0-animalEmoji长度之间的索引
int index = random.Next(animalEmoji.Count);
//获得这个随机的Emoji并写入textBlock中
string nextEmoji = animalEmoji[index];
textBlock.Text = nextEmoji;
//为了防止重复产生3个以上的相同Emoji,需要在赋值后对容器内对应的Emoji进行删除
animalEmoji.RemoveAt(index);
}
}
将项目加入源代码控制Git

(处理鼠标点击)
当玩家点击某个动物时都应该调用一个名为TextBlock_MouseDown的方法。



也可以直接在XAML中添加属性

TextBlock lastTextBlockClicked; //上一个点击的文字块
bool findingMatch = false; //用来判断是否已经连续点击两个文字块(算上当前点击的)
private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
TextBlock textBlock = sender as TextBlock;
if (findingMatch == false) // 还没有连续选中两个文字块
{
textBlock.Visibility = Visibility.Hidden; //将选中的文字块先隐藏
lastTextBlockClicked = textBlock;
findingMatch = true;
}
else if (textBlock.Text != lastTextBlockClicked.Text) //已经连续选中两个文字块但是不匹配
{
lastTextBlockClicked.Visibility = Visibility.Visible; //恢复上一个选中文字块为显示
findingMatch = false;
}
else { //选中了两个文字块且文字匹配
textBlock.Visibility = Visibility.Hidden;
findingMatch = false;
}
}
}
1.4 增加计时器
(创建内部参数和委托)

(在XAML中添加负责计时的文字块)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace MatchGame
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
DispatcherTimer timer = new DispatcherTimer();
int tenthsOfSeconsElapsed = 0;
int mathcesFound;
public MainWindow()
{
InitializeComponent();
SetUpGame();
timer.Interval = TimeSpan.FromSeconds(.1); //设置计时器的回调频率
timer.Tick += Timer_Tick; //为计时器绑定回调函数(委托)
}
private void Timer_Tick(object sender,EventArgs e) {
tenthsOfSeconsElapsed++;
timeTextBlock.Text = (tenthsOfSeconsElapsed / 10F).ToString("0.0s");
if (mathcesFound == 8) {
timer.Stop();
timeTextBlock.Text = timeTextBlock + " - Play again ?";
}
}
public void SetUpGame() {
// 创建一个有关动物表情的容器并初始化
List<string> animalEmoji = new List<string>() {
"🐵","🐵",
"🐒","🐒",
"🦍 ","🦍",
"🐺 ","🐺 ",
"🦝 ","🦝 ",
"🐔 ","🐔 ",
"🐉 ","🐉 ",
"🕷 ","🕷 ",
};
//初始化一个Random对象
Random random = new Random();
//遍历在名为mainGird组件中所有类型为TextBlock的子集
foreach (TextBlock textBlock in mainGrid.Children.OfType<TextBlock>())
{
if (textBlock.Name == "timeTextBlock") continue;
//随机生成一个0-animalEmoji长度之间的索引
int index = random.Next(animalEmoji.Count);
//获得这个随机的Emoji并写入textBlock中
string nextEmoji = animalEmoji[index];
textBlock.Text = nextEmoji;
//为了防止重复产生3个以上的相同Emoji,需要在赋值后对容器内对应的Emoji进行删除
animalEmoji.RemoveAt(index);
}
timer.Start();
tenthsOfSeconsElapsed = 0;
mathcesFound= 0;
}
TextBlock lastTextBlockClicked; //上一个点击的文字块
bool findingMatch = false; //用来判断是否已经连续点击两个文字块(算上当前点击的)
private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
TextBlock textBlock = sender as TextBlock;
if (findingMatch == false) // 还没有连续选中两个文字块
{
textBlock.Visibility = Visibility.Hidden; //将选中的文字块先隐藏
lastTextBlockClicked = textBlock;
findingMatch = true;
}
else if (textBlock.Text != lastTextBlockClicked.Text) //已经连续选中两个文字块但是不匹配
{
lastTextBlockClicked.Visibility = Visibility.Visible; //恢复上一个选中文字块为显示
findingMatch = false;
}
else { //选中了两个文字块且文字匹配
mathcesFound++;
textBlock.Visibility = Visibility.Hidden;
findingMatch = false;
}
}
private void TimeTextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
if (tenthsOfSeconsElapsed == 8) {
SetUpGame();
}
}
}
}