俄罗斯方块是一个很经典的游戏,做一个UWP俄罗斯方块没有什么用,我想说的是移植,把经典游戏移植到UWP。

我的所有博客都是抄别人的,这个才是我自己写的。后台很多代码还是抄别人的,我想说的是我们之前有很多游戏,很多软件使用C或者C++之类的来写,或者C#,其实我们可以把之前的算法拿出来,转换为UWP的C#,这时大家会说,界面。对,界面我们没法直接移植,但是用XAML做一个界面很快的,那么现在的问题就是,我们如何使用之前的算法来用现在的界面。

简单的一个,我们可以使用绑定。

MVVM的知识,我觉得看到一篇文章,忘了出处,希望知道的小伙伴提醒。他说,MVVM的ViewModel作用是界面的抽象。我们不用理界面,因为界面总是改,所以我们需要一个抽象的界面,就是我们做的ViewModel,那么model做的就是算法,数据。Model不知道界面怎样,他需要知道数据。ViewModel不知道界面怎样,他知道界面需要什么。

MVVM的知识我说的不算对,也不算错,但从这个看也是可以。

为什么要分开view?

其实可以看下面的:

假设我们需要做一个软件,这个软件是举报恶意转载的功能,他能够在网上搜,找到那些恶意转载的网站。

先吐槽下中国学网那些垃圾网站,全部东西都是转载的。吐槽下百度,搜索到的转载的都是前,找不到我的博客。

还是360好,能找到

我们软件开始界面

发现我们需要改

接着发现还是需要改

如果我们和界面有联系,一改界面就需要改,那么这样我们开发将会很慢。

如果我们能使用抽象,那么界面怎么改,我们修改的也就界面。

上面图片来自:http://my.oschina.net/Android1989/blog/296850

我们需要做一个游戏,我们有了之前的算法,我拿到了一位大神:http://www.cnblogs.com/china_x01/p/5253556.html

看不懂他写的,问了一位大神,他帮我改了UWP,最后我也看不懂,他写的没有注释。

做一个俄罗斯方块算法简单,我们放在后面,现在先和大家说界面。

后面说的有些小白。

我们程序:

  • view:MainPage.xaml
  • viewModel.cs
  • model.cs

我们在界面

放一个Canvas

里面就是游戏

因为我们需要游戏按键,所以我们需要一个TextBox

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBox Margin="10,10,10,10" Width="1" Height="1" KeyDown="keydown"></TextBox>
        <Canvas x:Name="canvas" Margin="10,10,10,10">

        </Canvas>
    </Grid>

每个方块

Rectangle[,] _rectangle

我们需要设计高度宽度 size = 10;,其实这里可以根据你自己需要,每个方块的size可以设置大,可以看到上面的图,我的方块是有些小。

现在就是我们重要的绑定,我们有200个Rectangle,如果每个在xaml,写我觉得我没有这么时间,也容易错

所以我们在

            for (int i = 0; i < view.row; i++)
            {
                for (int j = 0; j < view.col; j++)
                {
                    _rectangle[i, j] = new Rectangle()
                    {
                        Width = size,
                        Height = size,
                        Fill = new SolidColorBrush(Colors.Gray),
                        Stroke = new SolidColorBrush(Colors.LightCoral),
                        AllowDrop = false,
                        CanDrag = false,
                        Margin = new Thickness(j * size, i * size, 0, 0)
                    };
                    canvas.Children.Add(_rectangle[i, j]);
                }
            }

后台写了200个方块,就几句。我们给宽度高度、显示的颜色。显示颜色是没有方块显示的颜色,这里说的没有方块是说没有俄罗斯方块。

然后我们给每个方块边框,Stroke,他们的位置。

这样我们的屏幕就有了200个方块,但是放进去我们会发现和我们上面的图不同,因为宽度和高度不同

            canvas.Width = size * view.col;
            canvas.Height = size * view.row;

这样就好了。

界面大概就需要做的就这样,算法很简单,放在最后。

我们有的model,有俄罗斯方块的初始方块、移动、变形、向下

他把所有的数据保存在一个数组grid_observable,类型grid里面有个rectangle,如果为0表示这个地方没有方块,如果为1表示有方块。

类型grid

  • 是否有方块

我们界面根据rectangle显示,如果有,那么显示灰色,没有显示白色。

因为我们view是不知道后台,所以这个显示需要viewModel把后台的rectangle变为颜色。

我们ViewModel把颜色放ObservableCollection<solid> solid_collection

需要把rectangle变为颜色


            foreach (grid temp in _model.grid_observable)
            {
                if (temp.rectangle == 0)
                {
                    solid_collection[temp.row * col + temp.col].solids = new SolidColorBrush(Colors.Gray);
                }
                else
                {
                    solid_collection[temp.row * col + temp.col].solids = new SolidColorBrush(Colors.White);
                }
            }

为了让solid一修改就可以告诉view

    public class solid : notify_property
    {
        public solid(SolidColorBrush solid)
        {
            _solid = solid;
        }

        public SolidColorBrush solids
        {
            set
            {
                _solid = value;
                OnPropertyChanged();
            }
            get
            {
                return _solid;
            }
        }
        private SolidColorBrush _solid;
    }

因为每次写INotifyPropertyChanged要写很多,我们需要通知有很多 ,所以写notify_property

ViewModel能把后台的rectangle变颜色,那么我们view把颜色显示

我们刚才new 了200个Rectangle我们把他的颜色绑定ViewModel

如果使用xaml,我觉得我没法

那么我们在代码

                    _rectangle[i, j] = new Rectangle()
                    {
                        Width = size,
                        Height = size,
                        Fill = new SolidColorBrush(Colors.Gray),
                        Stroke = new SolidColorBrush(Colors.LightCoral),
                        AllowDrop = false,
                        CanDrag = false,
                        Margin = new Thickness(j * size, i * size, 0, 0)
                    };
                    Binding bind = new Binding()
                    {
                        Path = new PropertyPath("solid_collection[" + (i * view.col + j) + "].solids"),
                        Mode = BindingMode.OneWay
                    };
                    _rectangle[i, j].DataContext = view;
                    _rectangle[i, j].SetBinding(Shape.FillProperty, bind);

绑定可以Binding bind = new Binding()

里面写路径,可以数组中Path = new PropertyPath("solid_collection[" + (i * view.col + j) + "].solids"),

其实Path写在new Binding(string Path)

我们可以设置Source = view

                    Binding bind = new Binding()
                    {
                        Path = new PropertyPath("solid_collection[" + (i * view.col + j) + "].solids"),
                        Mode = BindingMode.OneWay,
                        Source = view
                    };

也可以_rectangle[i, j].DataContext = view;

写完我们需要

_rectangle[i, j].SetBinding(Shape.FillProperty, bind);

如果我们后台是可以的,那么我们就能看到

我想说的不是写俄罗斯,而是把之前的软件移植,我们可以把二维表,bool,表示为颜色,把颜色显示,我们有很多游戏都是可以这样,那么移植UWP简单,需要使用绑定,一个转换。

大神:可以直接绑定转换。

其实我是不喜欢直接绑定就转换,因为这样类很多,我们需要文件夹

Convert里面是转换类

我想说的不是做一个俄罗斯方块,而是把之前数据保存二进制矩阵的游戏移植到UWP思路。很简单不用多修改就可以使用,界面我们可以自己来写,只要绑定写了,那么就可以使用。

写到这,后面都是小白

俄罗斯方块

我们先打开vs神器,之前下载vs安装,需要sdk,这个在安装自己弄。

新建项目,我叫tetris

新建一个类叫viewModel,一个model

再新建一个类notify_property,接口INotifyPropertyChanged

    /// <summary>
    /// 提供继承通知UI改变值
    /// </summary>
    public class notify_property : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void UpdateProper<T>(ref T properValue , T newValue , [System.Runtime.CompilerServices.CallerMemberName] string properName = "")
        {
            if (object.Equals(properValue , newValue))
                return;

            properValue = newValue;
            OnPropertyChanged(properName);
        }
        public void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string name="")
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            handler?.Invoke(this , new PropertyChangedEventArgs(name));
        }
    }

这个类是我们每次需要INotifyPropertyChanged都需要写PropertyChanged,觉得还是放成类,让需要的继承

俄罗斯方块有

  • 新建方块
  • 方块移动
  • 方块向下
  • 碰到下面方块
  • 清除

我们把算法写model

方块有

  • straight,

  • square,

  • t,

  • bent

我们需要做一个来保存

    public enum block
    {
        straight,
        square,
        t,
        bent
    }

那么我们需要一个来放我们的方块

    public class grid : notify_property
    {
        public grid()
        {
            _rectangle = 1;
        }

        public grid(int col, int row)
        {
            _col = col;
            _row = row;
            _rectangle = 0;
        }

        public grid clone()
        {
            return new grid(col, row);
        }

        public int row
        {
            set
            {
                _row = value;
                OnPropertyChanged();
            }
            get
            {
                return _row;
            }
        }

        public int col
        {
            set
            {
                _col = value;
                OnPropertyChanged();
            }
            get
            {
                return _col;
            }
        }

        public int rectangle
        {
            set
            {
                _rectangle = value;
            }
            get
            {
                return _rectangle;
            }
        }

        private int _col;

        private int _rectangle;

        private int _row;
    }

行列,是否有方块

我们发现这个只能放一个方块,所以我们写

放着grid[] _grid;

新建方块:

square(block block, int center)

我们需要方块是什么,中心

我们先做直线

        public square(block block, int center)
        {
            _block = block;
            int n = 4;
            _grid = new grid[n];
            for (int i = 0; i < n; i++)
            {
                _grid[i] = new grid();
                switch (block)
                {
                    case block.straight:
                        _grid[i].col = center;
                        _grid[i].row = -i;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException(nameof(block), block, null);
                }
            }
        }

我们来做t

                    case block.t:
                        _grid[0].col = center;
                        _grid[0].row = 0;
                        if (i > 0)
                        {
                            _grid[i].col = center + i - 3;
                            _grid[i].row = -1;
                        }

square

                   case block.square:
                        if (i <= 1)
                        {
                            _grid[i].col = center + i;
                            _grid[i].row = 0;
                        }
                        else
                        {
                            _grid[i].col = center + i - 2;
                            _grid[i].row = -1;
                        }

bent

                    case block.bent:
                        if (i <= 1)
                        {
                            _grid[i].col = center + i;
                            _grid[i].row = 0;
                        }
                        else
                        {
                            _grid[i].col = center + i - 3;
                            _grid[i].row = -1;
                        }

        public square(block block, int center)
        {
            _block = block;
            int n = 4;
            _grid = new grid[n];
            for (int i = 0; i < n; i++)
            {
                _grid[i] = new grid();
                switch (block)
                {
                    case block.straight:
                        _grid[i].col = center;
                        _grid[i].row = -i;
                        break;
                    case block.t:
                        _grid[0].col = center;
                        _grid[0].row = 0;
                        if (i > 0)
                        {
                            _grid[i].col = center + i - 3;
                            _grid[i].row = -1;
                        }
                        break;
                    case block.square:
                        if (i <= 1)
                        {
                            _grid[i].col = center + i;
                            _grid[i].row = 0;
                        }
                        else
                        {
                            _grid[i].col = center + i - 2;
                            _grid[i].row = -1;
                        }
                        break;
                    case block.bent:
                        if (i <= 1)
                        {
                            _grid[i].col = center + i;
                            _grid[i].row = 0;
                        }
                        else
                        {
                            _grid[i].col = center + i - 3;
                            _grid[i].row = -1;
                        }
                        break;
                    default:
                        throw new ArgumentOutOfRangeException(nameof(block), block, null);
                }
            }
        }

这样看起来代码很多,这样不好,我们需要把每个放在一个函数

        public square(block block, int center)
        {
            _block = block;
            int n = 4;
            _grid = new grid[n];
            for (int i = 0; i < n; i++)
            {
                _grid[i] = new grid();
                switch (block)
                {
                    case block.straight:
                        block_straight(center, i);
                        break;
                    case block.t:
                        block_t(center, i);
                        break;
                    case block.square:
                        block_square(center, i);
                        break;
                    case block.bent:
                        block_bent(center, i);
                        break;
                    default:
                        throw new ArgumentOutOfRangeException(nameof(block), block, null);
                }
            }
        }

        private void block_straight(int center, int i)
        {
            _grid[i].col = center;
            _grid[i].row = -i;
        }

        private void block_t(int center, int i)
        {
            _grid[0].col = center;
            _grid[0].row = 0;
            if (i > 0)
            {
                _grid[i].col = center + i - 3;
                _grid[i].row = -1;
            }
        }

        private void block_bent(int center, int i)
        {
            if (i <= 1)
            {
                _grid[i].col = center + i;
                _grid[i].row = 0;
            }
            else
            {
                _grid[i].col = center + i - 3;
                _grid[i].row = -1;
            }
        }

我们model还没写东西

我们先做新建方块

我们需要最大值

        public int row
        {
            set
            {
                _row = value;
            }
            get
            {
                return _row;
            }
        }
        public int col
        {
            set
            {
                _col = value;
            }
            get
            {
                return _col;
            }
        }

        private int _col = 10;
        private int _row = 20;

当前方块

        public square _square
        {
            set;
            get;
        }

新建方块

        private void new_block()
        {
            block _block = (block)ran.Next(4);
            int center = _col / 2;
            _square = new square(_block, center);
        }

我们现在没有想着去什么,我们需要显示

每次下降

        public void down()
        {
            if (_square == null)
            {
                new_block();
            }
        }

我们在ViewModel

        public viewModel()
        {
            solid_collection = new ObservableCollection<solid>();
            for (int i = 0; i < col * row; i++)
            {
                solid_collection.Add(new solid(new SolidColorBrush(Colors.Gray)));
            }
            DispatcherTimer time = new DispatcherTimer
            {
                Interval = TimeSpan.FromSeconds(0.5)
            };
            time.Tick += tick;
            time.Start();
        }
        public int col
        {
            set
            {
                value = 0;
            }
            get
            {
                return _model.col;
            }
        }

        public int row
        {
            set
            {
                value = 0;
            }
            get
            {
                return _model.row;
            }
        }
        public ObservableCollection<solid> solid_collection
        {
            set;
            get;
        }
        private void tick(object sender, object e)
        {
            DispatcherTimer time = sender as DispatcherTimer;
            time?.Stop();
            down();
            time?.Start();
        }

        public void down()
        {
            _model.down();
        }

我们需要DispatcherTimer,给他时间Interval = TimeSpan.FromSeconds(0.5)就向下

如果model

            if (_square == null)
            {
                new_block();
            }

我们现在新建出来,还没有显示

我们需要把_square显示

viewModel

        public void down()
        {
            _model.down();
            foreach (grid temp in _model._square._grid.Where(temp => temp.col >= 0 && temp.row >= 0))
            {
                solid_collection[temp.row * col + temp.col].solids = new SolidColorBrush(Colors.White);
            }
        }

我们现在除了界面,都做好了。

打开MainPage

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBox Margin="10,10,10,10" Width="1" Height="1" KeyDown="keydown"></TextBox>
        <Canvas x:Name="canvas" Margin="10,10,10,10">

        </Canvas>
    </Grid>

TextBox 我们需要按键

        private viewModel view;
        public MainPage()
        {
            InitializeComponent();
            rectangle();
        }

rectangle绑定我们的界面

绑定在上面有写了

        private void rectangle()
        {
            view = new viewModel();
            Rectangle[,] _rectangle = new Rectangle[view.row, view.col];
            double height = 600;
            double size = height / view.row;
            if (size < 10)
            {
                size = 10;
            }
            canvas.Width = size * view.col;
            canvas.Height = size * view.row;
            canvas.Background = new SolidColorBrush(Colors.BurlyWood);
            for (int i = 0; i < view.row; i++)
            {
                for (int j = 0; j < view.col; j++)
                {
                    _rectangle[i, j] = new Rectangle()
                    {
                        Width = size,
                        Height = size,
                        Fill = new SolidColorBrush(Colors.Gray),
                        Stroke = new SolidColorBrush(Colors.LightCoral),
                        AllowDrop = false,
                        CanDrag = false,
                        Margin = new Thickness(j * size, i * size, 0, 0)
                    };
                    Binding bind = new Binding()
                    {
                        Path = new PropertyPath("solid_collection[" + (i * view.col + j) + "].solids"),
                        Mode = BindingMode.OneWay
                    };
                    _rectangle[i, j].DataContext = view;
                    _rectangle[i, j].SetBinding(Shape.FillProperty, bind);
                    canvas.Children.Add(_rectangle[i, j]);
                }
            }
        }

我们可以开始运行,就可以看到,只下来一块

我们要让整个方块向下

        public void down()
        {
            if (_square == null)
            {
                new_block();
            }

            foreach (grid temp in _square._grid)
            {
                temp.row++;
            }
        }

每个都向下

我们会发现我们的方块下到最下还是没有停下来

我们需要判断方块是不是到最下

判断方块是不是要到的位置不可以,这句话是说判断是不是在grid里,位置超过最大可以的位置,或者小于0,位置是不是有方块。

        private bool rectangle(square _square)
        {
            bool _rectangle = true;

            foreach (grid temp in _square._grid)
            {
                if (temp.col >= 0 && temp.row >= 0)
                {
                    int n = (temp.row ) * col + temp.col;
                    if (_grid_observable.Count > n && _grid_observable[n].rectangle != 0)
                    {
                        _rectangle = false;
                    }
                }
                else if (temp.col < 0)
                {
                    return false;
                }

                if (temp.row >= _row || temp.col >= _col)
                {
                    return false;
                }
            }
            return _rectangle;
        }

我们先复制方块,然后让方块向下,判断是个方块是不是可以在他的位置,如果可以,复制回去。

        public void down()
        {
            if (_square == null)
            {
                new_block();
            }
            square temp = _square.clone();
            foreach (grid t in temp._grid)
            {
                t.row++;
            }
            if (rectangle(temp))
            {
                _square = temp;
            }
        }

复制

        public square clone()
        {
            square temp = new square(_block, 0);
            for (int i = 0; i < _grid.Length; i++)
            {
                temp._grid[i] = _grid[i].clone();
            }
            temp.rotate_count = rotate_count;
            return temp;
        }

运行我们可以看到方块能向下,在最下停下,但是不会出新方块,我们需要判断向下,如果没有可以位置,那么新方块

        public void down()
        {
            if (_square == null)
            {
                new_block();
            }
            square temp = _square.clone();
            foreach (grid t in temp._grid)
            {
                t.row++;
            }
            if (!rectangle(temp))//修改
            {
                draw();          //画出来
                new_block();
            }
            else
            {
                _square = temp; //为什么不clone
            }
        }

上面代码留有一个问题,就是最后的把可以的位置复制回去怎么不需要写复制,当然这个简单。

我们现在还需要看画出来

我们需要把方块画在grid,那些我们无法移动的方块需要画在grid

        private void draw()
        {
            int n = 0;
            foreach (grid temp in _square._grid)
            {
                if (temp.col >= 0 && temp.row >= 0)
                {
                    n = temp.row * col + temp.col;
                    if (_grid_observable.Count > n)
                    {
                        _grid_observable[n].rectangle = 1;
                    }
                }
            }
            clean();
        }

画完我们判断是不是可以删掉,判断一行是不是有方块,有就删掉

        private void clean()
        {
            bool _rectangle = true;
            int n = 1;
            foreach (grid temp in _grid_observable)
            {
                if (temp.col < _col - 1)
                {
                    _rectangle = _rectangle && temp.rectangle != 0;
                }
                else if (temp.col == _col - 1)
                {
                    _rectangle = _rectangle && temp.rectangle != 0;
                    if (_rectangle)
                    {
                        for (int i = n*_col - 1; i > _col; i--)
                        {
                            _grid_observable[i].rectangle = _grid_observable[i - _col].rectangle;
                        }
                        n--;
                    }
                    n++;
                    _rectangle = true;
                }
            }
        }

现在我们需要写移动

左移col–,判断是否可以存在,可以,复制回去

        public void move(bool left)
        {
            square temp = _square.clone();
            foreach (grid t in temp._grid)
            {
                if (left)
                {
                    t.col--;
                }
                else
                {
                    t.col++;
                }
            }

            if (rectangle(temp))
            {
                _square = temp;
            }
        }

我们基本做好了俄罗斯方块算法

我们去mainpage写

        private void keydown(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e)
        {
            if (e.Key == VirtualKey.Up)
            {
                view.translate();
            }
            else if (e.Key == VirtualKey.Left)
            {
                view.move(true);
            }
            else if(e.Key==VirtualKey.Right)
            {
                view.move(false);
            }
            else if (e.Key == VirtualKey.Down)
            {
                view.down();
            }
        }

viewmode只是使用model

        public void move(bool left)
        {
            _model.move(left);
        }

运行,我们可以开始玩了,然后你会发现好像我们还少个没有写

我把全部代码放下面,我希望等到你不知道怎么写才去,我的变量命名其实有问题,如果可以去改下,因为按shift然后大写实在不会,所以都是_。如果觉得_需要两个键,就让我卖关子,其实我只需要使用-,怎么做我会在之后告诉大家

https://code.msdn.microsoft.com/win10-uwp-def86f86

MainPage.xaml

<Page
    x:Class="tetris.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:tetris"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBox Margin="10,10,10,10" Width="1" Height="1" KeyDown="keydown"></TextBox>
        <Canvas x:Name="canvas" Margin="10,10,10,10">

        </Canvas>
    </Grid>
</Page>
// lindexi
// 11:22

#region

using System.Runtime.CompilerServices;
using Windows.System;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Shapes;

#endregion

//“空白页”项模板在 http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 上有介绍

namespace tetris
{
    /// <summary>
    /// 可用于自身或导航至 Frame 内部的空白页。
    /// </summary>
    public sealed partial class MainPage : Page
    {
        private viewModel view;
        public MainPage()
        {
            InitializeComponent();
            rectangle();
        }

        private void keydown(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e)
        {
            if (e.Key == VirtualKey.Up)
            {
                view.translate();
            }
            else if (e.Key == VirtualKey.Left)
            {
                view.move(true);
            }
            else if(e.Key==VirtualKey.Right)
            {
                view.move(false);
            }
            else if (e.Key == VirtualKey.Down)
            {
                view.down();
            }
        }

        private void rectangle()
        {
            view = new viewModel();
            Rectangle[,] _rectangle = new Rectangle[view.row, view.col];
            double height = 600;
            double size = height / view.row;
            if (size < 10)
            {
                size = 10;
            }
            canvas.Width = size * view.col;
            canvas.Height = size * view.row;
            canvas.Background = new SolidColorBrush(Colors.BurlyWood);
            for (int i = 0; i < view.row; i++)
            {
                for (int j = 0; j < view.col; j++)
                {
                    _rectangle[i, j] = new Rectangle()
                    {
                        Width = size,
                        Height = size,
                        Fill = new SolidColorBrush(Colors.Gray),
                        Stroke = new SolidColorBrush(Colors.LightCoral),
                        AllowDrop = false,
                        CanDrag = false,
                        Margin = new Thickness(j * size, i * size, 0, 0)
                    };
                    Binding bind = new Binding()
                    {
                        Path = new PropertyPath("solid_collection[" + (i * view.col + j) + "].solids"),
                        Mode = BindingMode.OneWay
                    };
                    _rectangle[i, j].DataContext = view;
                    _rectangle[i, j].SetBinding(Shape.FillProperty, bind);
                    canvas.Children.Add(_rectangle[i, j]);
                }
            }
        }
    }
}

viewModel

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;

namespace tetris
{
    public class viewModel : notify_property
    {
        public viewModel(Rectangle[,] rectangle)
        {
            _rectangle = rectangle;
        }

        public viewModel()
        {
            //_solid = new SolidColorBrush[row, col];
            solid_collection = new ObservableCollection<solid>();
            for (int i = 0; i < col * row; i++)
            {
                solid_collection.Add(new solid(new SolidColorBrush(Colors.Gray)));
            }
            visibility = new Visibility[row * col];
            rectangle_visibility = new Visibility[row, col];
            DispatcherTimer time = new DispatcherTimer
            {
                Interval = TimeSpan.FromSeconds(0.5)
            };
            time.Tick += tick;
            time.Start();
        }

        public void translate()
        {
            _model.translate();
        }

        public void move(bool left)
        {
            _model.move(left);
        }

        private void tick(object sender, object e)
        {
            DispatcherTimer time = sender as DispatcherTimer;
            time?.Stop();
            down();
            time?.Start();
        }

        //Rectangle
        private Rectangle[,] _rectangle;
        //private SolidColorBrush[,] _solid;
        public ObservableCollection<solid> solid_collection
        {
            set;
            get;
        }

        //private void draw()
        //{
        //    foreach (grid temp in _model.grid_observable)
        //    {

        //    }
        //}

        public int col
        {
            set
            {
                value = 0;
            }
            get
            {
                return _model.col;
            }
        }

        public int row
        {
            set
            {
                value = 0;
            }
            get
            {
                return _model.row;
            }
        }

        //public SolidColorBrush[,] solid
        //{
        //    set
        //    {
        //        _solid = value;
        //        OnPropertyChanged();
        //    }
        //    get
        //    {
        //        return _solid;
        //    }
        //}

        public Visibility[,] rectangle_visibility
        {
            set
            {
                _rectangle_visibility = value;
                OnPropertyChanged();
            }
            get
            {
                return _rectangle_visibility;
            }

        }

        private Visibility[,] _rectangle_visibility;
        private Visibility[] _visibility;

        public Visibility[] visibility
        {
            set
            {
                _visibility = value;
                OnPropertyChanged();
            }
            get
            {
                return _visibility;
            }
        }

        public void down()
        {
            //visibility = visibility == Visibility.Collapsed ? Visibility.Visible : Visibility.Collapsed;
            _model.down();

            foreach (grid temp in _model.grid_observable)
            {
                //SolidColorBrush _sld=new SolidColorBrush();
                if (temp.rectangle == 0)
                {
                    //solid[temp.row, temp.col] = new SolidColorBrush(Colors.Gray);
                    solid_collection[temp.row * col + temp.col].solids = new SolidColorBrush(Colors.Gray);
                    //rectangle_visibility[temp.row, temp.col] = Visibility.Collapsed;
                    //visibility[temp.row * col + temp.col] = Visibility.Collapsed;
                }
                else //if(temp.rectangle == 1)
                {
                    //solid[temp.row, temp.col] = new SolidColorBrush(Colors.White);
                    solid_collection[temp.row * col + temp.col].solids = new SolidColorBrush(Colors.White);
                    //rectangle_visibility[temp.row, temp.col] = Visibility.Visible;
                    //visibility[temp.row * col + temp.col] = Visibility.Visible;
                }
            }

            foreach (grid temp in _model.grid_observable)
            {
                if (temp.rectangle == 0)
                {
                    solid_collection[temp.row * col + temp.col].solids = new SolidColorBrush(Colors.Gray);
                }
                else
                {
                    solid_collection[temp.row * col + temp.col].solids = new SolidColorBrush(Colors.White);
                }
            }

            foreach (grid temp in _model._square._grid.Where(temp => temp.col >= 0 && temp.row >= 0))
            {
                solid_collection[temp.row * col + temp.col].solids = new SolidColorBrush(Colors.White);
            }
        }

        private model _model = new model();
    }

    public class solid : notify_property
    {
        public solid(SolidColorBrush solid)
        {
            _solid = solid;
        }

        public SolidColorBrush solids
        {
            set
            {
                _solid = value;
                OnPropertyChanged();
            }
            get
            {
                return _solid;
            }
        }
        private SolidColorBrush _solid;
    }
}

model

// lindexi
// 10:41

#region

using System;
using System.Collections.ObjectModel;

#endregion

namespace tetris
{
    public class model
    {
        public model()
        {
            _grid_observable = new ObservableCollection<grid>();
            for (int i = 0; i < _row; i++)
            {
                for (int j = 0; j < _col; j++)
                {
                    _grid_observable.Add(new grid(j, i));
                }
            }
        }

        public square _square
        {
            set;
            get;
        }

        public int col
        {
            set
            {
                _col = value;
            }
            get
            {
                return _col;
            }
        }

        public ObservableCollection<grid> grid_observable
        {
            set
            {
                _grid_observable = value;
            }
            get
            {
                return _grid_observable;
            }
        }

        public int row
        {
            set
            {
                _row = value;
            }
            get
            {
                return _row;
            }
        }

        public void translate()
        {
            square rotate = _square.clone();
            rotate.rotate();

            if (rectangle(rotate))
            {
                _square = rotate;
            }
        }

        public void move(bool left)
        {
            square temp = _square.clone();
            foreach (grid t in temp._grid)
            {
                if (left)
                {
                    t.col--;
                }
                else
                {
                    t.col++;
                }
            }

            if (rectangle(temp))
            {
                _square = temp;
            }
        }

        public void down()
        {
            if (_square == null)
            {
                new_block();
            }
            square temp = _square.clone();
            foreach (grid t in temp._grid)
            {
                t.row++;
            }
            if (!rectangle(temp))
            {
                draw();
                new_block();
            }
            else
            {
                _square = temp;
            }
        }

        private Random ran
        {
            set
            {
                _ran = value;
            }
            get
            {
                return _ran;
            }
        }

        private int _col = 10;

        private ObservableCollection<grid> _grid_observable;
        private Random _ran = new Random();
        private int _row = 20;

        private void new_block()
        {
            block _block = (block) ran.Next(4);
            int center = _col/2;
            _square = new square(_block, center);
            //_square = new square(block.straight, center);
        }

        private void draw()
        {
            int n = 0;
            foreach (grid temp in _square._grid)
            {
                if (temp.col >= 0 && temp.row >= 0)
                {
                    n = temp.row*col + temp.col;
                    if (_grid_observable.Count > n)
                    {
                        _grid_observable[n].rectangle = 1;
                    }
                }
            }
            clean();
        }

        private bool rectangle(square _square)
        {
            bool _rectangle = true;

            foreach (grid temp in _square._grid)
            {
                if (temp.col >= 0 && temp.row >= 0)
                {
                    int n = temp.row*col + temp.col;
                    if (_grid_observable.Count > n && _grid_observable[n].rectangle != 0)
                    {
                        _rectangle = false;
                    }
                }
                else if (temp.col < 0)
                {
                    return false;
                }

                if (temp.row >= _row || temp.col >= _col)
                {
                    return false;
                }
            }
            return _rectangle;
        }

        private void clean()
        {
            bool _rectangle = true;
            int n = 1;
            foreach (grid temp in _grid_observable)
            {
                if (temp.col < _col - 1)
                {
                    _rectangle = _rectangle && temp.rectangle != 0;
                }
                else if (temp.col == _col - 1)
                {
                    _rectangle = _rectangle && temp.rectangle != 0;
                    if (_rectangle)
                    {
                        for (int i = n*_col - 1; i > _col; i--)
                        {
                            _grid_observable[i].rectangle = _grid_observable[i - _col].rectangle;
                        }
                        n--;
                    }
                    n++;
                    _rectangle = true;
                }
            }
        }
    }

    public class grid : notify_property
    {
        public grid()
        {
            _rectangle = 1;
        }

        public grid(int col, int row)
        {
            _col = col;
            _row = row;
            _rectangle = 0;
        }

        public int col
        {
            set
            {
                _col = value;
                OnPropertyChanged();
            }
            get
            {
                return _col;
            }
        }

        public int rectangle
        {
            set
            {
                _rectangle = value;
            }
            get
            {
                return _rectangle;
            }
        }

        public int row
        {
            set
            {
                _row = value;
                OnPropertyChanged();
            }
            get
            {
                return _row;
            }
        }

        public grid clone()
        {
            return new grid(col, row);
        }

        private int _col;

        private int _rectangle;

        private int _row;
    }

    public enum block
    {
        straight, //直
        square,
        t,
        bent
    }

    public class square
    {
        public square(block block, int center)
        {
            _block = block;
            int n = 4;
            //col = new int[n];
            //row = new int[n];
            _grid = new grid[n];
            for (int i = 0; i < n; i++)
            {
                _grid[i] = new grid();
                switch (block)
                {
                    case block.straight:
                        //col[i] = center;
                        //row[i] = -i;
                        _grid[i].col = center;
                        _grid[i].row = -i;
                        break;
                    case block.t:
                        _grid[0].col = center;
                        _grid[0].row = 0;
                        if (i > 0)
                        {
                            _grid[i].col = center + i - 3;
                            _grid[i].row = -1;
                        }
                        break;
                    case block.square:
                        if (i <= 1)
                        {
                            //col[i] = center + i;
                            //row[i] = 0;
                            _grid[i].col = center + i;
                            _grid[i].row = 0;
                        }
                        else
                        {
                            //col[i] = center + i - 2;
                            //row[i] = -1;
                            _grid[i].col = center + i - 2;
                            _grid[i].row = -1;
                        }
                        break;
                    case block.bent:
                        if (i <= 1)
                        {
                            //col[i] = center + 1;
                            //row[i] = 0;
                            _grid[i].col = center + i;
                            _grid[i].row = 0;
                        }
                        else
                        {
                            //col[i] = center + i - 3;
                            //row[i] = -1;
                            _grid[i].col = center + i - 3;
                            _grid[i].row = -1;
                        }
                        break;
                    default:
                        throw new ArgumentOutOfRangeException(nameof(block), block, null);
                }
            }
        }

        public void rotate()
        {
            switch (_block)
            {
                case block.straight:
                    if (rotate_count == 0 || rotate_count == 2)
                    {
                        int row = _grid[2].row;
                        int col = _grid[2].col;
                        _grid[0].row = row;
                        _grid[0].col = col + 2;

                        _grid[1].row = row;
                        _grid[1].col = col + 1;

                        _grid[3].row = row;
                        _grid[3].col = col - 1;
                    }
                    else if (rotate_count == 1 || rotate_count == 3)
                    {
                        int row = _grid[2].row;
                        int col = _grid[2].col;

                        _grid[0].row = row - 2;
                        _grid[0].col = col;

                        _grid[1].row = row - 1;
                        _grid[1].col = col;

                        _grid[3].row = row + 1;
                        _grid[3].col = col;
                    }
                    break;
                case block.square:
                    break;
                case block.t:
                    if (rotate_count == 0)
                    {
                        int row = _grid[2].row;
                        int col = _grid[2].col;

                        _grid[0].row = row + 1;
                        _grid[0].col = col - 1;

                        _grid[1].row--;
                        _grid[1].col++;

                        _grid[3].row++;
                        _grid[3].col--;
                    }
                    else if (rotate_count == 1)
                    {
                        int row = _grid[3].row;
                        int col = _grid[3].col;

                        _grid[0].row--;

                        _grid[1].row = row;
                        _grid[1].col = col + 1;

                        _grid[2].row = row;
                        _grid[2].col = col - 1;
                    }
                    else if (rotate_count == 2)
                    {
                        int row = _grid[2].row;
                        int col = _grid[2].col;

                        _grid[0].col++;

                        _grid[1].row = row - 1;
                        _grid[1].col = col;

                        _grid[3].row = row + 1;
                        _grid[3].col = col;
                    }
                    else if (rotate_count == 3)
                    {
                        int row = _grid[2].row;
                        int col = _grid[2].col;

                        _grid[0].row = row + 1;
                        _grid[0].col = col + 2;

                        _grid[1].row = row;
                        _grid[1].col = col;

                        _grid[2].row = row;
                        _grid[2].col = col + 1;

                        _grid[3].row = row;
                        _grid[3].col = col + 2;
                    }
                    break;
                case block.bent:
                    if (rotate_count == 0 || rotate_count == 2)
                    {
                        _grid[1].row = _grid[2].row - 1;
                        _grid[1].col = _grid[2].col;
                    }
                    else if (rotate_count == 1 || rotate_count == 3)
                    {
                        _grid[1].row = _grid[0].row;
                        _grid[1].col = _grid[0].col + 1;
                    }
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
            rotate_count++;
        }

        public square clone()
        {
            square temp = new square(_block, 0);
            for (int i = 0; i < _grid.Length; i++)
            {
                temp._grid[i] = _grid[i].clone();
            }
            temp.rotate_count = rotate_count;
            return temp;
        }

        private int rotate_count
        {
            set
            {
                if (value >= 4)
                {
                    value = value%4;
                }
                _rotate_count = value;
            }
            get
            {
                if (_rotate_count > 4)
                {
                    _rotate_count = 0;
                }
                return _rotate_count;
            }
        }

        //public int[] col
        //{
        //    set
        //    {
        //        _col = value;
        //    }
        //    get
        //    {
        //        return _col;
        //    }
        //}

        //public int[] row
        //{
        //    set
        //    {
        //        _row = value;
        //    }
        //    get
        //    {
        //        return _row;
        //    }
        //}

        private block _block;

        private int _rotate_count;

        public grid[] _grid;
    }
}

win10 uwp 俄罗斯方块的更多相关文章

  1. Win10 UWP开发系列:使用VS2015 Update2+ionic开发第一个Cordova App

    安装VS2015 Update2的过程是非常曲折的.还好经过不懈的努力,终于折腾成功了. 如果开发Cordova项目的话,推荐大家用一下ionic这个框架,效果还不错.对于Cordova.PhoneG ...

  2. Win10 UWP开发系列:实现Master/Detail布局

    在开发XX新闻的过程中,UI部分使用了Master/Detail(大纲/细节)布局样式.Win10系统中的邮件App就是这种样式,左侧一个列表,右侧是详情页面.关于这种 样式的说明可参看MSDN文档: ...

  3. Win10 UWP开发实现Bing翻译

    微软在WP上的发展从原来的Win7到Win8,Win8.1,到现在的Win10 UWP,什么是UWP,UWP即Windows 10 中的Universal Windows Platform简称.即Wi ...

  4. Win10/UWP开发—使用Cortana语音与App后台Service交互

    上篇文章中我们介绍了使用Cortana调用前台App,不熟悉的移步到:Win10/UWP开发—使用Cortana语音指令与App的前台交互,这篇我们讲讲如何使用Cortana调用App的后台任务,相比 ...

  5. 【Win10 UWP】后台任务与动态磁贴

    动态磁贴(Live Tile)是WP系统的大亮点之一,一直以来受到广大用户的喜爱.这一讲主要研究如何在UWP应用里通过后台任务添加和使用动态磁贴功能. 从WP7到Win8,再到Win10 UWP,磁贴 ...

  6. 【Win10 UWP】URI Scheme(一):Windows Store协议的解析和使用

    协议是Windows Phone和Windows Store应用的一个重要特点,可以做到在不同应用之间进行互相呼起调用.小小协议,学问大着呢.我打算写几篇关于协议在UWP中使用的文章. 这一讲的主要对 ...

  7. 【Win10 UWP】QQ SDK(二):SDK的回调处理

    上一讲,我们介绍了QQ SDK的使用方法,请看<[Win10 UWP]QQ SDK(一):SDK基本使用方法> 一. 回调的基本形式 从前面的介绍中我们知道,我们的应用和QQ客户端之间需要 ...

  8. Win10 UWP应用发布流程

    简介 Win10 UWP应用作为和Win8.1 UAP应用不同的一种新应用形式,其上传至Windows应用商店的流程也有了一些改变. 这篇博文记录了我们发布一款Win10 UWP应用的基本流程,希望为 ...

  9. 【Win10 UWP】QQ SDK(一):SDK基本使用方法

    每当开发一个应用需要社交分享的应用时,总是心里咯噔一下:到底什么时候分享能加上QQ和微信?除了WP8.0版本的微信SDK,官方似乎从未正面发布过适应时代发展的QQ SDK,就连后台,也没有一个可以创建 ...

随机推荐

  1. sudoku--设想

    在查阅了一些资料和自己动手写一写后,找到一种可行的解法. 第一步 首先将9x9的数独方格分成九份3x3的九宫格,如下图 B1 B2 B3 B4 B5 B6 B7 B8 B9 而后在左上角的B1上随机生 ...

  2. 201521123119《Java程序设计》第7周学习总结

    1. 本周学习总结 2. 书面作业 Q1.ArrayList代码分析 Q1.1 解释ArrayList的contains源代码 这段代码的主要目的是判断在对ArrayList遍历时所用的方法,在输入参 ...

  3. 201521123053《Java程序设计》第十三周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 TCP和UDP两者之间的区别: UDP:1)将数据及源和目的封装成数据包中,不需要建立连接 ...

  4. 使用tcpdump拦截linux服务端网络数据

    语法范例: tcpdump -vv -i ens3 '((tcp)&&(host 183.239.240.48)&&(port 3001))'  -c 100 -w 1 ...

  5. 逆向实战干货,快速定位自动捡阳光Call,或者标志

    逆向实战干货,快速定位自动捡阳光Call,或者标志 注意: 关于CE和OD的使用,这里不再多说,快速定位,默认大家已经有了CE基础,或者OD基础. 第一种方法,找Call 第一步,打开CE,搜索阳光值 ...

  6. xml解析案例

    步骤:Channel是java bean类 public static List<Channel> parsexml(InputStream inputStream) {//注意服务器种是 ...

  7. Java 制作证书的工具keytool用法总结

    一.keytool的概念 keytool 是个密钥和证书管理工具.它使用户能够管理自己的公钥/私钥对及相关证书,用于(通过数字签名)自我认证(用户向别的用户/服务认证自己)或数据完整性以及认证服务.在 ...

  8. Go语言备忘录:基本数据结构

    本文内容是本人对Go语言的变量.常量.数组.切片.映射.结构体的备忘录,记录了关键的相关知识点,以供翻查. 文中如有错误的地方请大家指出,以免误导!转摘本文也请注明出处,多谢! 参考书籍<Go语 ...

  9. 关于 HashTable

    hashTable 的一些认识: 底层使用散列表,存贮键值对,键值非null 使用synchronize 保证线程安全 (线程安全) ■全局变量 //The hash table data. //底层 ...

  10. Hive简记

    在大数据工作中难免遇到数据仓库(OLAP)架构,以及通过Hive SQL简化分布式计算的场景.所以想通过这篇博客对Hive使用有一个大致总结,希望道友多多指教! 摘要: 1.Hive安装 2.Hive ...