使用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 ...
随机推荐
- 【LeetCode】414. Third Maximum Number 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 替换最大值数组 使用set 三个变量 日期 题目地址 ...
- Once Again...
Once Again... 题目链接 题意 给n个数,然后T次循环后组成一个新的数列,求这个数列的最长不递减子序列. 思路 因为最多就100个元素,所以当m<=100的时候直接暴力求最长不递减子 ...
- Myeclipse查看jdk源代码
过程如下: 1.点 "window"-> "Preferences" -> "Java" -> "Install ...
- (数据科学学习手札133)利用geopandas绘制拓扑着色地图
本文示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 我们在绘制某些地图时,为了凸显出每个独立的 ...
- [AllError错误填坑大全]Jsoncpp logicError
在将Json::Value添加元素子项的时候,不要与(key,Value)的形式共有.容易形成逻辑错误. 举例如下: Json::Value output; Json::Value people; n ...
- IT6563|4LAN DP转HDMI 4K60HZ /2.0转换方案|CS5263替代IT6563
IT6563是一款4通道DisplayPort1.2到HDMI 4K60Hz转换器,IT6563结合DisplayPort接收机和HDMI发射机,通过转换功能支持DisplayPort输入和HDMI输 ...
- 加深理解Java异常概念并熟记5个最常见的运行时异常
加深理解Java异常概念并熟记5个最常见的运行时异常 说明Error与Exception的联系和区别有哪些? 列举最常见的5个运用时异常. 1.Error和Exception的联系和区别: Error ...
- .NET 微服务——CI/CD(2):自动打包镜像
准备工作 一.开启docker的tcp 我的服务器是linux,以端口2376为例,找到docker.service,在ExecStart下新增这段代码即可: -H tcp://0.0.0.0:237 ...
- 使用tomcat搭建HTTP文件下载服务器
使用tomcat搭建HTTP文件下载服务器, 有时我们的应用或者服务需要去外网下载一些资源, 但是如果在内网环境或者网络不好的情况下, 我们可以在内网提供文件下载服务, 将预先下载好的资源放在某个地方 ...
- Redis真的又小又快又持久吗
一本正经 面试官:小伙子,谈谈对Redis的看法. 我:啊,看法呀,坐着看还是躺着看.Redis很小?很快?但很持久? 面试官:一本正经的说,我怀疑你在开车,不仅开开车还搞颜色. 我:... 面试官: ...