使用Xamarin开发移动应用示例——数独游戏(二)创建游戏界面
在本系列第一部分,我们创建了程序框架,现在我们创建游戏的界面,项目代码可以从Github下载:https://github.com/zhenl/ZL.Shudu 。代码随项目进度更新。
首先在Views目录下添加一个内容页面,名称为Game.xaml:

然后,在AppShell.xaml中增加这个页面导航:
<TabBar>
<ShellContent Title="游戏" Icon="icon_about.png" Route="Game" ContentTemplate="{DataTemplate local:Game}" />
<ShellContent Title="关于" Icon="icon_about.png" Route="AboutPage" ContentTemplate="{DataTemplate local:AboutPage}" />
<ShellContent Title="Browse" Icon="icon_feed.png" ContentTemplate="{DataTemplate local:ItemsPage}" />
</TabBar>
如果这时运行程序,会发现页面底部增加了一个“游戏”分页,并且初始页面也改为这个页面。现在我们修改这个页面,改造为数独游戏界面。数独的界面是9X9的格子,这些格子组成九个九宫格,每个格子中是1-9的数字,玩家需要将所有的格子填满,并且行、列和九宫格中的数据不能重复。我们可以使用Grid进行布局,构造九行九列,每个格子中放置一个按钮(Button),用户按下按钮,弹出数字输入框,输入数字后,数字显示在按钮上,完成一个输入。
下面是页面的布局XAML:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ZL.Shudu.Views.Game">
<ContentPage.Content>
<StackLayout x:Name="outerStack" Orientation="Vertical">
<!-- Place new controls here -->
<Grid x:Name="myGrid" IsVisible="True" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="40" x:Name="rowButton" />
<RowDefinition Height="40" x:Name="rowResult" />
</Grid.RowDefinitions>
<Label x:Name="lbFinish" Text="完成" IsVisible="false" Grid.Row="10" Grid.Column="0" Grid.ColumnSpan="2" />
<Label x:Name="lbTime" Grid.Row="10" Grid.Column="3" Grid.ColumnSpan="2" Text="" IsVisible="False"></Label>
<Label x:Name="lbMessage" Grid.Row="10" Grid.Column="5" Grid.ColumnSpan="4" Text="" IsVisible="False"></Label>
</Grid>
<Grid x:Name="grdNumber" IsVisible="false">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
</Grid>
</StackLayout>
</ContentPage.Content>
</ContentPage>
在页面初始化时,生成数字按钮、游戏界面中每个单元格按钮,并根据初始数据确定按钮的文本和使能。
public Game()
{
try
{
InitializeComponent();
SetNumButtons();
SetLayout();
SetNewGame();
}
catch (Exception ex)
{
lbMessage.IsVisible = true;
rowResult.Height = 40;
lbMessage.Text = ex.Message;
//throw;
}
}
设置数字按钮的函数代码如下:
private void SetNumButtons()
{
var num = 1;
for (var i = 0; i < 2; i++)
{
for (var j = 0; j < 5; j++)
{
var btn = new Button();
if (num == 10)
{
btn.Text = "清除";
btn.Clicked += btn_Clear_Clicked;
btn.FontSize = 15;
}
else
{
btn.Text = num.ToString();
btn.Clicked += btn_Num_Clicked;
btn.FontSize = 16;
}
btn.Padding = 0;
grdNumber.Children.Add(btn, j, i);
numbuttons[i, j] = btn;
num++;
}
}
}
设置数独界面按钮的代码如下:
private void SetLayout()
{
for (var i = 0; i < 9; i++)
{
for (var j = 0; j < 9; j++)
{
int m = i / 3;
int n = j / 3;
var btn = new Button();
var c = new Color(0.9, 0.9, 0.9);
if ((m + n) % 2 == 0)
{
c = new Color(0.5,0.5, 0.5);
}
btn.BackgroundColor = c;
btn.Padding = 0;
btn.Margin = 0;
btn.FontSize = 20;
myGrid.Children.Add(btn, i, j);
btn.Clicked += Btn_Clicked;
buttons[i, j] = btn;
}
}
}
根据初始化数据,设置按钮状态的代码如下:
private void SetGame(int[,] inp)
{
for (var i = 0; i < 9; i++)
{
for (var j = 0; j < 9; j++)
{
chess[i, j] = inp[i, j];
}
}
for (var i = 0; i < 9; i++)
{
for (var j = 0; j < 9; j++)
{
var btn = buttons[i, j];
if (chess[i, j] > 0)
{
btn.Text = chess[i, j].ToString();
btn.IsEnabled = false;
}
else
{
btn.Text = "";
btn.IsEnabled = true;
}
}
}
this.lbFinish.IsVisible = false;
this.lbTime.IsVisible = false;
this.lbMessage.IsVisible = false;
this.rowResult.Height = 1;
lbTime.Text = "";
lbMessage.Text = "";
}
按钮的响应事件如下:
private void Btn_Clicked(object sender, EventArgs e)
{
currentButton = sender as Button;
rowResult.Height = 1;
rowButton.Height = 1;
grdNumber.IsVisible = true;
}
private void btn_Clear_Clicked(object sender, EventArgs e)
{
if (currentButton == null) return;
currentButton.Text = "";
grdNumber.IsVisible = false;
myGrid.IsVisible = true;
rowResult.Height = 40;
rowButton.Height = 40;
}
private void btn_Num_Clicked(object sender, EventArgs e)
{
currentNumBtn = sender as Button;
int x = -1, y = -1;
for (var i = 0; i < 9; i++)
{
for (var j = 0; j < 9; j++)
{
if (buttons[i, j] == currentButton)
{
x = i;
y = j;
break;
}
}
}
var num = int.Parse(currentNumBtn.Text);
if (!checkval(x, y, num))
{
return;
}
currentButton.Text = currentNumBtn.Text;
myGrid.IsVisible = true;
grdNumber.IsVisible = false;
rowResult.Height = 40;
rowButton.Height = 40;
if (IsFinish())
{
lbFinish.IsVisible = true;
rowResult.Height = 40;
}
}
判断输入状态和游戏结束的函数如下:
private bool checkval(int x, int y, int num)
{
for (var i = 0; i < 9; i++)
{
var buttonnum = string.IsNullOrEmpty(buttons[x, i].Text) ? 0 : int.Parse(buttons[x, i].Text);
if (i != y && buttonnum == num) return false;
}
for (var i = 0; i < 9; i++)
{
var buttonnum = string.IsNullOrEmpty(buttons[i, y].Text) ? 0 : int.Parse(buttons[i, y].Text);
if (i != x && buttonnum == num) return false;
}
int m = x / 3;
int n = y / 3;
for (int i = m * 3; i < (m + 1) * 3; i++)
{
for (int j = n * 3; j < (n + 1) * 3; j++)
{
var buttonnum = string.IsNullOrEmpty(buttons[i, j].Text) ? 0 : int.Parse(buttons[i, j].Text);
if (i != x && j != y && buttonnum == num) return false;
}
}
return true;
}
private bool IsFinish()
{
for (var i = 0; i < 9; i++)
{
for (var j = 0; j < 9; j++)
{
if (string.IsNullOrEmpty(buttons[i, j].Text)) return false;
}
}
return true;
}
}
运行效果如下:

现在基本界面已经搭建完成,后续需要增加允许回退、历史记录、退出保存以及自动完成等功能。项目代码可以从Github下载:https://github.com/zhenl/ZL.Shudu 。代码随项目进度更新。
使用Xamarin开发移动应用示例——数独游戏(二)创建游戏界面的更多相关文章
- 使用Xamarin开发移动应用示例——数独游戏(一)项目的创建与调试
最近项目中需要移动客户端,由于团队基本上使用.Net产品线,所以决定使用Xmarin进行开发,这样技术路线统一,便于后期维护.官网上是这样介绍的" Xamarin 允许你使用 .NET 代码 ...
- 使用Xamarin开发移动应用示例——数独游戏(五)保存游戏进度
项目代码可以从Github下载:https://github.com/zhenl/ZL.Shudu .代码随项目进度更新. 保存进度是移动应用的基本功能,在应用的使用过程中会有各种各样的可能导致使用中 ...
- 使用Xamarin开发移动应用示例——数独游戏(六)使用数据库
项目代码可以从Github下载:https://github.com/zhenl/ZL.Shudu .代码随项目进度更新. 现在我们希望为应用增加更多的功能,比如记录每个完成的游戏,可以让用户自己添加 ...
- 使用Xamarin开发移动应用示例——数独游戏(七)添加新游戏
项目代码可以从Github下载:https://github.com/zhenl/ZL.Shudu .代码随项目进度更新. 现在我们增加添加新游戏的功能,创建一个页面,编辑初始局面,并保存到数据库. ...
- 使用Xamarin开发移动应用示例——数独游戏(八)使用MVVM实现完成游戏列表页面
项目代码可以从Github下载:https://github.com/zhenl/ZL.Shudu .代码随项目进度更新. 前面我们已经完成了游戏的大部分功能,玩家可以玩预制的数独游戏,也可以自己添加 ...
- 使用Xamarin开发移动应用示例——数独游戏(四)产生新游戏算法改进
项目代码可以从Github下载:https://github.com/zhenl/ZL.Shudu .代码随项目进度更新. 前面我们使用一个数组保存预制的游戏,然后随机从中抽取一个游戏作为新游戏,如果 ...
- 从零开始开发一款H5小游戏(二) 创造游戏世界,启动发条
本系列文章对应游戏代码已开源 Sinuous game 上一节介绍了canvas的基础用法,了解了游戏开发所要用到的API.这篇文章开始,我将介绍怎么运用这些API来完成各种各样的游戏效果.这个过程更 ...
- IOS开发创建开发证书及发布App应用(二)——创建证书
2. 创建证书 证书分为两种,一种是开发者证书,主要是用来真机调试的 另一种就是发布证书,就是用来发布应用的, 最好是两种都要下载,不然编译时候可能报错,我猜想可能苹果怕你没用真机调试 创建证书分为两 ...
- iOS开发 Swift开发数独游戏(一)
一.前言 我姥姥是一名退休数学老师,一直很喜欢玩数独游戏.我以前答应过她要给她写一个数独游戏.本来计划是写一个Android应用的,但恰好我学了好长时间iOS开发一直没做什么"大项目&quo ...
随机推荐
- Oracle根据约束条件名称查找对应的数据
select * from dba_constraints where constraint_name = 'SYS_C0082752'
- JVM调参
今天看了下之前做的一个异步处理任务的服务,发现占用内存量比较大,达到2G,但我检查了代码,基本没有static对象.但这个服务有个特点,就是每次执行一个任务的时候,会从数据库中捞大量的数据做处理,因此 ...
- 一站式元数据治理平台——Datahub入门宝典
随着数字化转型的工作推进,数据治理的工作已经被越来越多的公司提上了日程.作为新一代的元数据管理平台,Datahub在近一年的时间里发展迅猛,大有取代老牌元数据管理工具Atlas之势.国内Datahub ...
- 【算法】main函数的堆栈溢出
main函数的堆栈的大小默认为1mb 如果把数组int x[1000][1000]定义在main函数里 则int为4byte,8bit为1byte,1024byte为1kb,1024kb为1mb 4* ...
- Practical Black-Box Attacks against Machine Learning
目录 概 主要内容 Jacobian-based Dataset Augmentation Note Papernot N, Mcdaniel P, Goodfellow I, et al. Prac ...
- Spring Boot 2 中如何使用 Log4j2 记录日志
上一篇我们介绍了Spring Boot 2.x中默认日志框架Logback的使用.今天继续说说日志,接下来我们要讲是前段时间爆出核弹漏洞的Log4j2.虽然出了漏洞,让很多小伙伴痛苦了1-2周(加班) ...
- Spring练习,使用Properties类型注入方式,注入MySQL数据库连接的基本信息,然后使用JDBC方式连接数据库,模拟执行业务代码后释放资源,最后在控制台输出打印结果。
相关 知识 >>> 相关 练习 >>> 实现要求: 使用Properties类型注入方式,注入MySQL数据库连接的基本信息,然后使用JDBC方式连接数据库,模拟执 ...
- 你在寻找Vue3移动端项目框架嘛?请看这里
现在web开发变得更加美妙高效,在于开发工具设计得更好了,丰富性与易用性,都有所提高.丰富性带来了一个幸福的烦恼,就是针对实际应用场景,如何选择工具 ? 1. Vue Cli和Vite之间的选择 Vi ...
- MySQL启用SSL连接
1.手动创建自认证证书 1.1 创建CA证书 openssl genrsa 2048 > ca-key.pem openssl req -new -x509 -nodes -days 3600 ...
- 使用 SSH 隧道实现端口转发、SOCKS 代理
SSH隧道 本地端口转发 本地客户端通过 local_port 连接到 MobaXterm: MobaXterm 绕过防火墙,使用 user 用户连接到 ssh_server_ip:ssh_serve ...