WPF的砖块消除,基本实现砖块消除公共
- 实现效果:
-
使用方式:
第一步:设置砖块数量
第二步:点击刷新界面
第三步:按住键盘的 “A” 或点击 “启动”按钮启动游戏
移动方式:在橘黄色区域按住鼠标左键即可移动挡板,或者移动挡板左右坐标即可 -
前台代码:
<Window x:Class="打砖块.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:打砖块"
mc:Ignorable="d"
Title="打砖块V0.0.1" Height="600" Width="600" MinHeight="600" MinWidth="600" Loaded="Window_Loaded" Closing="Window_Closing" SizeChanged="Window_SizeChanged" >
<Window.Resources>
<RoutedUICommand x:Key="Start_Game" Text="Start game" />
</Window.Resources>
<Window.InputBindings>
<KeyBinding Key="A" Command="{StaticResource Start_Game}"/>
</Window.InputBindings>
<Window.CommandBindings>
<CommandBinding x:Name="cb_start_game" Command="{StaticResource Start_Game}" CanExecute="cb_start_game_CanExecute" Executed="cb_start_game_Executed"/>
</Window.CommandBindings>
<Grid x:Name="gd_min">
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF3B41CF" Offset="0"/>
<GradientStop Color="#FFB82274" Offset="0.992"/>
<GradientStop Color="#FF4A4A4A" Offset="0.229"/>
<GradientStop Color="#FF7AD65E" Offset="0.562"/>
</LinearGradientBrush>
</Grid.Background>
<Grid.RowDefinitions>
<RowDefinition Height="80"/>
<RowDefinition Height="9*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="210"/>
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Grid.Column="0">
<Grid.RowDefinitions >
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition Width="0.1*"/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="砖块总数:" Foreground="Azure"/>
<Label Grid.Row="1" Grid.Column="0" Content="已消除总数:" Foreground="Azure"/>
<Label Grid.Row="2" Grid.Column="0" Content="当前用时:" Foreground="Azure"/>
<Label x:Name="lb_brick_count" Grid.Row="0" Grid.Column="1" Content="-" Foreground="Azure"/>
<Label x:Name="lb_re_count" Grid.Row="1" Grid.Column="1" Content="-" Foreground="Azure"/>
<Label x:Name="lb_time" Grid.Row="2" Grid.Column="1" Content="-" Foreground="Azure"/>
<Label Grid.Row="0" Grid.Column="3" Content="剩余砖块:" Foreground="Azure"/>
<Label Grid.Row="1" Grid.Column="3" Content="弹起数:" Foreground="Azure"/>
<Label Grid.Row="2" Grid.Column="3" Content="-" Foreground="Azure"/>
<Label x:Name="lb_lost_count" Grid.Row="0" Grid.Column="4" Content="-" Foreground="Azure"/>
<Label x:Name="lb_run_stpe" Grid.Row="1" Grid.Column="4" Content="-" Foreground="Azure"/>
<Label Grid.Row="2" Grid.Column="4" Content="-" Foreground="Azure"/>
</Grid>
<TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" TextWrapping="Wrap" Text="第①步:设置砖块数量和小球速度 第②步:点击刷新界面生成砖块 第③步:点击启动(或单击“a”开始)开始消除砖块 移动方式:按住鼠标左键即可移动挡板" Foreground="Red" Grid.ColumnSpan="2" />
<Grid Grid.Row="1" Grid.Column="0" Background="BlanchedAlmond" MouseMove="gd_ball_MouseMove">
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Grid.Row="1" Grid.Column="1" x:Name="gd_table" Background="AliceBlue"/>
</Grid>
</Grid>
<Grid Grid.Row="1" Grid.Column="0" x:Name="gd_ball" Background="{x:Null}" >
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="10"/>
</Grid.RowDefinitions>
<Ellipse x:Name="ep_boll" Grid.Row="0" Grid.RowSpan="3" Width="10" Height="10" VerticalAlignment="Bottom" HorizontalAlignment="Center">
<Ellipse.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFF7642C" Offset="0"/>
<GradientStop Color="#FF4058A8" Offset="1"/>
<GradientStop Color="#FFA66147" Offset="0.402"/>
<GradientStop Color="#FF6E4739" Offset="0.546"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Rectangle Visibility="Collapsed" x:Name="rt_wb" Grid.Row="1" Width="100" Height="10" VerticalAlignment="Bottom" HorizontalAlignment="Center"
RadiusY="5" RadiusX="5">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF787878" Offset="0"/>
<GradientStop Color="Black" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle Grid.Row="1" x:Name="rt_rect" Height="10" Width="100" Fill="#CCCD2C2C"/>
</Grid>
<Grid Grid.Row="1" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Vertical" Background="Aqua">
<Label Content="球坐标:"/>
<Label Name="lb_ball_addr" Content="0:0" HorizontalAlignment="Center"/>
<Label Content="距离:"/>
<Label Name="lb_leng" Content="-" HorizontalAlignment="Center" />
</StackPanel>
<StackPanel Grid.Row="1" VerticalAlignment="Center">
<Label Content="砖块数量:"/>
<Slider Margin="2" Width="50" x:Name="sd_brick_num" MinWidth="150" IsSnapToTickEnabled="True" Minimum="10" Maximum="500" Value="40" Orientation="Horizontal"/>
<Label Content="{Binding Path=Value,ElementName=sd_brick_num}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="速度比:"/>
<Slider Margin="2" Width="50" x:Name="sd_bool_speed" MinWidth="150" IsSnapToTickEnabled="True" Minimum="0" Maximum="50" Value="45" Orientation="Horizontal" ValueChanged="sd_bool_speed_ValueChanged"/>
<Label Content="{Binding Path=Value,ElementName=sd_bool_speed}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Button x:Name="bt_crt" Margin="3" Height="40" Content="刷新界面" Click="bt_crt_Click"/>
<Button Content="启动" Margin="3" Height="40" x:Name="bt_start" Click="bt_start_Click"/>
<Label Content="挡板中心坐标:"/>
<Slider Margin="2" Width="50" x:Name="sd_x" MinWidth="150" ValueChanged="sd_x_ValueChanged" IsSnapToTickEnabled="True" Minimum="-200" Maximum="200" Value="0" Orientation="Horizontal"/>
<Label Content="{Binding Path=Value,ElementName=sd_x}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
<TextBlock Grid.Row="2" Text="Power By Bilibili-火狐鞥 2021-01-14" HorizontalAlignment="Center" VerticalAlignment="Center" TextAlignment="Center" FontSize="15" Foreground="Gray"/>
</Grid>
</Grid>
</Window>
- 后台代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
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 打砖块
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.ep_boll.RenderTransform=new TranslateTransform();
this.rt_rect.RenderTransform=new TranslateTransform();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
timer_init();
CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
Max_leng = Math.Sqrt(Math.Pow(rect_info.Width / 2, 2) + Math.Pow(rect_info.Height / 2, 2)) + ball_info.Radius;
sd_x.Maximum = gd_ball.ActualWidth / 2;
sd_x.Minimum = -gd_ball.ActualWidth / 2;
}
#region 申明类
public struct Ball
{
public Point Addr; //位置
public Point Speed; //运行速度
public Point Dir; //运行方向
public int Radius; //球半径
}
//public struct Rect
//{
// public Point Addr; //位置
// public double Width;
// public double Height;
// public int Stat;
//}
public class Rect
{
private Point _addr = new Point(0, 0);
private double _width = 0;
private double _height = 0;
private int _stat = 0;
private int _index = 0;
public Point Addr
{
set { _addr = value; }
get { return _addr; }
}
public double Width
{
set { _width = value; }
get { return _width; }
}
public double Height
{
set { _height = value; }
get { return _height; }
}
public int Stat
{
set { _stat = value; }
get { return _stat; }
}
public int Index
{
set { _index = value; }
get { return _index; }
}
}
#endregion
#region///全局变量
private ProcessCount processCount;//统计运行时间
private int brick_run_stpe = 0; //运行步数
private int re_brick_count = 0;
private Ball ball_info = new Ball() { Addr = new Point(0, -10), Speed = new Point(0, 0), Dir = new Point(0, -1), Radius = 5 };
private Rect rect_info = new Rect() { Addr = new Point(0, 0), Height = 10, Width = 100, Stat = 99 };
private List<Rect> brick_list = new List<Rect>();//砖块列表
private Point brick_info = new Point(20, 18); //生成砖的大小
private int brick_num = 40; //生成砖的数量
private List<int> brick_addr = new List<int>();
double Max_leng = 0;
#endregion
#region 定时器
MillisecondTimer aTimer;
private int timer_count=0;
void timer_init()
{
aTimer = new MillisecondTimer();
aTimer.Tick += timedo; ;
aTimer.Interval = 1; //每秒执行
processCount = new ProcessCount(0);
//aTimer.Start();
aTimer.Stop();
}
private void timedo(object sender, EventArgs e) //定时中断
{
this.Dispatcher.Invoke(new Action(delegate
{
ball_move();
timer_count++;
if (timer_count > 1000)
{
timer_count = 0;
processCount.ProcessCountUp();
lb_time.Content = processCount.GetHour() + ":" + processCount.GetMinute() + ":" + processCount.GetSecond();
}
}));
}
#endregion
#region //功能函数
[DllImport("kernel32.dll")]
private static extern bool SetProcessWorkingSetSize(IntPtr proc, int min, int max);
/// <summary>
/// 内存回收
/// </summary>
private void ClearMemory()
{
GC.Collect();
GC.WaitForPendingFinalizers();
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
}
}
/// <summary>
/// 产生指定随机数 且不重复
/// </summary>
/// <param name="Number">产生随机数个数</param>
/// <param name="minNum">最小值</param>
/// <param name="maxNum">最大值</param>
/// <returns></returns>
public List<int> GetRandomArray(int Number, int minNum, int maxNum)
{
int j;
int[] b = new int[Number];
List<int> buf = new List<int>();
Random r = new Random();
while (buf.Count < Number)
{
int i = r.Next(minNum, maxNum);
int num = 0;
for (int k = 0; k < buf.Count; k++) //判断是否和以前的数据重复
{
if (buf[k] == i) //新生成的数据和原来的数据重复
{
num = num + 1;
break;
}
}
if (num == 0)
{
//b[j] = i;
buf.Add(i);
}
}
//for (j = 0; j < Number; j++)
//{
// int i = r.Next(minNum, maxNum + 1);
// int num = 0;
// for (int k = 0; k < j; k++) //判断是否和以前的数据重复
// {
// if (b[k] == i) //新生成的数据和原来的数据重复
// {
// num = num + 1;
// }
// }
// if (num == 0)
// {
// b[j] = i;
// }
// else
// {
// j = j - 1;
// }
//}
//Array.Sort(buf);
buf.Sort();
return buf;
}
/// <summary>
/// WPF控件查找
/// </summary>
/// <typeparam name="T">空间类型</typeparam>
/// <param name="parent">父控件</param>
/// <param name="childName">查找空间名称</param>
/// <returns></returns>
public static T FindChild<T>(DependencyObject parent, string childName) where T : DependencyObject
{
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
// 如果bai子控件不是需查找的控件类型
T childType = child as T;
if (childType == null)
{
// 在下一级控件中递归查找
foundChild = FindChild<T>(child, childName);
// 找到控件就可以中断递归操作
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
// 如果控件名称符合参数条件
if (frameworkElement != null && frameworkElement.Name == childName)
{
foundChild = (T)child;
break;
}
}
else
{
// 查找到了控件
foundChild = (T)child;
break;
}
}
return foundChild;
}
#endregion
#region ///界面刷新
private void CompositionTarget_Rendering(object sender, EventArgs e)
{
TranslateTransform bool_translate = (TranslateTransform)ep_boll.RenderTransform;
TranslateTransform rect_translate = (TranslateTransform)rt_rect.RenderTransform;
bool_translate.X = ball_info.Addr.X;
bool_translate.Y = ball_info.Addr.Y;
rect_translate.X = rect_info.Addr.X;
rect_translate.Y = rect_info.Addr.Y;
lb_ball_addr.Content = ball_info.Addr.X.ToString("0.00") + ":" + ball_info.Addr.Y.ToString("0.00");
lb_leng.Content=check_leng(rect_info, ball_info)[1].ToString("0.00");
}
#endregion
#region ///核心算法
/// <summary>
/// 获取距离最近的点的距离
/// </summary>
/// <param name="p">矩形信息</param>
/// <param name="b">圆信息</param>
/// <returns>
/// re[0] -1 错误(内部) 0 X轴方向距离最短 1 Y轴距离最短
/// re[1] -1 错误 其他:最短距离
/// </returns>
private double[] check_leng(Rect p, Ball b)
{
double leng = Math.Sqrt(Math.Pow(p.Addr.X - b.Addr.X, 2) + Math.Pow(p.Addr.Y - b.Addr.Y, 2));
double max_len = Math.Sqrt(Math.Pow(p.Width / 2, 2) + Math.Pow(p.Height / 2, 2)) + b.Radius;
double min_len = Math.Min(Math.Min(p.Height / 2, p.Width / 2), b.Radius);
double min_x = -1;
double min_y = -1;
double min_1 = -1;
double min_2 = -1;
double min_3 = -1;
double min_4 = -1;
double[] re = new double[2];
re[0] = -1;
re[1] = -1;
if (leng < min_len) //小于最小距离,两物体相交 或位于内部
{
//逻辑上不允许出现此种情况
return re;
}
else
{
//根据中心坐标位置确定需要判断的边界(有可能交互的边界)
if ((b.Addr.X >= p.Addr.X - p.Width / 2 + b.Radius) && (b.Addr.X <= p.Addr.X + p.Width / 2 - b.Radius)) //位于Y轴方向区域类
{
if (b.Addr.Y <= p.Addr.Y - p.Height / 2 - b.Radius) //圆心位于矩形的下边沿
{
min_y = Math.Abs(b.Addr.Y + b.Radius - (p.Addr.Y - p.Height / 2));
}
else if (b.Addr.Y >= p.Addr.Y + p.Height / 2 + b.Radius) //圆心位于的上边沿
{
min_y = Math.Abs(b.Addr.Y - b.Radius - (p.Addr.Y + p.Height / 2));
}
else //圆心位于矩形内
{
min_y = -1;
}
re[0] = 1;
re[1] = min_y;
return re;
}
else if ((b.Addr.Y >= p.Addr.Y - p.Height / 2 + b.Radius) && (b.Addr.Y <= p.Addr.Y + p.Height / 2 - b.Radius))//位于矩形X轴方向区域类
{
if (b.Addr.X <= p.Addr.X - p.Width / 2 - b.Radius) //圆心位于矩形的左边沿
{
min_x = Math.Abs(b.Addr.X + b.Radius - (p.Addr.X - p.Width / 2));
}
else if (b.Addr.X >= p.Addr.X + p.Width / 2 + b.Radius) //圆心位于矩形的右边沿
{
min_x = Math.Abs(b.Addr.X - b.Radius - (p.Addr.X + p.Width / 2));
}
else //圆心位于矩形内
{
min_x = -1;
}
re[0] = 0;
re[1] = min_x;
return re;
}
else if ((b.Addr.X <= p.Addr.X - p.Width / 2 + b.Radius) && (b.Addr.Y <= p.Addr.Y - p.Height / 2 + b.Radius)) //第四象域
{
for (int rad_t = 270; rad_t <= 360; rad_t++)
{
double x = b.Addr.X + b.Radius * Math.Cos(Math.PI * rad_t / 180);
double y = b.Addr.Y - b.Radius * Math.Sin(Math.PI * rad_t / 180); //算出球边沿的坐标
double m = p.Addr.X - p.Width / 2;
double n = p.Addr.Y - p.Height / 2;
double mint_t = Math.Sqrt(Math.Pow(m - x, 2) + Math.Pow(n - y, 2));
re[0] = 1;
if (b.Addr.X > m)
{
mint_t = Math.Min(mint_t, Math.Abs(y - n));
re[0] = 1;
}
else if (b.Addr.Y > n)
{
mint_t = Math.Min(mint_t, Math.Abs(x - m));
re[0] = 1;
}
if (min_4 != -1)
{
if ((x > p.Addr.X - p.Width / 2) && (y > p.Addr.Y - p.Height / 2))
{
min_4 = -1;
break;
}
else
{
if (mint_t < min_4)
{
min_4 = mint_t;
}
}
}
else
{
if ((x > p.Addr.X - p.Width / 2) && (y > p.Addr.Y - p.Height / 2))
{
min_4 = -1;
break;
}
else
{
min_4 = mint_t;
}
}
}
re[1] = min_4;
return re;
//return min_4;
}
else if ((b.Addr.X > p.Addr.X + p.Width / 2 - b.Radius) && (b.Addr.Y <= p.Addr.Y - p.Height / 2 + b.Radius)) //第三象域
{
for (int rad_t = 180; rad_t <= 270; rad_t++)
{
double x = b.Addr.X + b.Radius * Math.Cos(Math.PI * rad_t / 180);
double y = b.Addr.Y - b.Radius * Math.Sin(Math.PI * rad_t / 180); //算出球边沿的坐标
double m = p.Addr.X + p.Width / 2;
double n = p.Addr.Y - p.Height / 2;
double mint_t = Math.Sqrt(Math.Pow(m - x, 2) + Math.Pow(n - y, 2));
re[0] = 1;
if (b.Addr.X < m)
{
mint_t = Math.Min(mint_t, Math.Abs(y - n));
re[0] = 1;
}
else if (b.Addr.Y > n)
{
mint_t = Math.Min(mint_t, Math.Abs(x - m));
re[0] = 0;
}
//double mint_t = Math.Sqrt(Math.Pow(p.Addr.X + p.Width / 2 - x, 2) + Math.Pow(p.Addr.Y - p.Height / 2 - y, 2));
if (min_3 != -1)
{
if ((x < p.Addr.X + p.Width / 2) && (y > p.Addr.Y - p.Height / 2))
{
min_3 = -1;
break;
}
else
if (mint_t < min_3)
{
min_3 = mint_t;
}
}
else
{
if ((x < p.Addr.X + p.Width / 2) && (y > p.Addr.Y - p.Height / 2))
{
min_3 = -1;
break;
}
else
{
}
min_3 = mint_t;
}
}
re[1] = min_3;
return re;
//return min_3;
}
else if ((b.Addr.X > p.Addr.X + p.Width / 2 - b.Radius) && (b.Addr.Y > p.Addr.Y + p.Height / 2 - b.Radius))//第二象域
{
for (int rad_t = 90; rad_t <= 180; rad_t++)
{
double x = b.Addr.X + b.Radius * Math.Cos(Math.PI * rad_t / 180);
double y = b.Addr.Y - b.Radius * Math.Sin(Math.PI * rad_t / 180); //算出球边沿的坐标
double m = p.Addr.X + p.Width / 2;
double n = p.Addr.Y + p.Height / 2;
double mint_t = Math.Sqrt(Math.Pow(m - x, 2) + Math.Pow(n - y, 2));
re[0] = 0;
if (b.Addr.X < m)
{
mint_t = Math.Min(mint_t, Math.Abs(y - n));
re[0] = 1;
}
else if (b.Addr.Y < n)
{
mint_t = Math.Min(mint_t, Math.Abs(x - m));
re[0] = 0;
}
if (min_2 != -1)
{
if ((x < p.Addr.X + p.Width / 2) && (y < p.Addr.Y + p.Height / 2))
{
min_2 = -1;
break;
}
else
{
if (mint_t < min_2)
{
min_2 = mint_t;
}
}
}
else
{
if ((x < p.Addr.X + p.Width / 2) && (y < p.Addr.Y + p.Height / 2))
{
min_2 = -1;
break;
}
else
{
min_2 = mint_t;
}
}
}
re[1] = min_2;
return re;
}
else if ((b.Addr.X <= p.Addr.X - p.Width / 2 + b.Radius) && (b.Addr.Y > p.Addr.Y + p.Height / 2 - b.Radius)) //第一象域
{
for (int rad_t = 0; rad_t <= 90; rad_t++)
{
double x = b.Addr.X + b.Radius * Math.Cos(Math.PI * rad_t / 180);
double y = b.Addr.Y - b.Radius * Math.Sin(Math.PI * rad_t / 180); //算出球边沿的坐标
double m = p.Addr.X - p.Width / 2;
double n = p.Addr.Y + p.Height / 2;
double mint_t = Math.Sqrt(Math.Pow(m - x, 2) + Math.Pow(n - y, 2));
re[0] = 0;
if (b.Addr.X > m)
{
mint_t = Math.Min(mint_t, Math.Abs(y - n));
re[0] = 1;
}
else if (b.Addr.Y < n)
{
mint_t = Math.Min(mint_t, Math.Abs(x - m));
re[0] = 0;
}
if (min_1 != -1)
{
if ((x > p.Addr.X - p.Width / 2) && (y < p.Addr.Y + p.Height / 2))
{
min_1 = -1;
break;
}
else
{
if (mint_t < min_1)
{
min_1 = mint_t;
}
}
}
else
{
if ((x > p.Addr.X - p.Width / 2) && (y < p.Addr.Y + p.Height / 2))
{
min_1 = -1;
break;
}
else
{
min_1 = mint_t;
}
}
}
re[1] = min_1;
return re;
}
return re;
//return -98;
}
}
private double wb_val = 0;
private int time_count = 0;
/// <summary>
/// 球体移动判断
/// </summary>
private void ball_move()
{
try
{
time_count++;
double max_x = (gd_ball.ActualWidth - ep_boll.ActualWidth) / 2;
double max_y = gd_ball.ActualHeight - ep_boll.ActualHeight;
wb_val = rect_info.Addr.X;
if (time_count >= 20)
{
time_count = 0;
}
if ((int)(51 - ball_info.Speed.X) != 0 && ball_info.Speed.X != 0)
{
if (time_count % ((int)(51 - ball_info.Speed.X)) == 0)
{
ball_info.Addr.X += ball_info.Dir.X;
}
}
if ((int)(51 - ball_info.Speed.Y) != 0 && ball_info.Speed.Y != 0)
{
if (time_count % ((int)(51 - ball_info.Speed.Y)) == 0)
{
ball_info.Addr.Y += ball_info.Dir.Y;
}
}
if (ball_info.Addr.X >= (max_x))
{
ball_info.Dir.X = -1;
ball_info.Addr.X = max_x;
}
else if (ball_info.Addr.X <= -max_x)
{
ball_info.Dir.X = 1;
ball_info.Addr.X = -max_x;
}
if (ball_info.Addr.Y <= (-max_y))
{
ball_info.Dir.Y = 1;
ball_info.Addr.Y = -max_y;
}
else if (ball_info.Addr.Y > 0)
{
ball_info.Addr.X = 0;
ball_info.Addr.Y = -10;
ball_info.Speed.X = 0;
ball_info.Speed.Y = 0;
ball_info.Dir.X = 0;
ball_info.Dir.Y = -1;
brick_run_stpe++;
lb_run_stpe.Content = brick_run_stpe;
Debug.WriteLine("重置");
}
else if (ball_info.Addr.Y > -5)
{
if (System.Math.Abs(ball_info.Addr.X - wb_val) > 50)
{
Debug.WriteLine("掉了");
}
else if (System.Math.Abs(ball_info.Addr.X - wb_val) > 45)
{
if (ball_info.Dir.Y != -1)
{
ball_info.Dir.Y = -1;
brick_run_stpe++;
lb_run_stpe.Content = brick_run_stpe;
}
if (ball_info.Addr.X - wb_val < 0)
{
if (ball_info.Dir.X != -1)
{
ball_info.Dir.X = -1;
}
}
else
{
if (ball_info.Dir.X != 1)
{
ball_info.Dir.X = 1;
}
}
ball_info.Speed.X = (Math.Abs((ball_info.Addr.X - wb_val)));
Debug.WriteLine("起飞1");
}
else //0~45理论还是输了。
{
}
}
else if (ball_info.Addr.Y > -10)
{
if (System.Math.Abs(ball_info.Addr.X - wb_val) > 50)
{
// Debug.WriteLine("掉了");
}
else
{
if (ball_info.Dir.Y != -1)
{
ball_info.Dir.Y = -1;
brick_run_stpe++;
lb_run_stpe.Content = brick_run_stpe;
}
if (ball_info.Addr.X - wb_val < 0)
{
if (ball_info.Dir.X != -1)
{
ball_info.Dir.X = -1;
}
}
else
{
if (ball_info.Dir.X != 1)
{
ball_info.Dir.X = 1;
}
}
ball_info.Speed.X = (Math.Abs((ball_info.Addr.X - wb_val)));
Debug.WriteLine("起飞2");
}
}
if (brick_list != null && brick_list.Count != 0)
{
for (int i = 0; i < brick_list.Count; i++) //判断砖块与球的距离
{
if (brick_list[i].Stat != 0)
{
if ((Math.Abs(brick_list[i].Addr.X - ball_info.Addr.X) < Max_leng)&&(Math.Abs(brick_list[i].Addr.Y - ball_info.Addr.Y) < Max_leng))
{
double[] leng = check_leng(brick_list[i], ball_info);
if (leng[1] <= 0)
{
if (leng[0] == 0)
{
ball_info.Dir.X = -ball_info.Dir.X;
}
else
{
ball_info.Dir.Y = -ball_info.Dir.Y;
}
//触发移除操作
if (brick_list[i].Stat != 99)
{
brick_list[i].Stat--;
if (brick_list[i].Stat <= 0)
{
//移除砖块
brick_list[i].Stat = 0;
//界面移除
Rectangle ret_t = null;
string name = "rect_" + brick_list[i].Index.ToString();
ret_t = FindChild<Rectangle>(gd_table, name);
if (ret_t != null)
{
BrushConverter conv = new BrushConverter();
Brush bru;
bru = conv.ConvertFromInvariantString("#000000FF") as Brush;
ret_t.Fill = bru;
ret_t.Stroke = bru;
re_brick_count++;
lb_re_count.Content =re_brick_count;
lb_lost_count.Content = brick_num - re_brick_count;
if (brick_num <= re_brick_count)
{
aTimer.Stop();
MessageBox.Show("恭喜,已完成拆除\r\n" + "拆除砖块:" + re_brick_count.ToString() + " 总共用时:" + processCount.TotalSecond.ToString()+"s") ; ;
}
}
}
}
}
}
}
}
}
}
catch
{
}
}
/// <summary>
/// 生成砖块
/// </summary>
/// <param name="brick_info">砖块信息</param>
/// <param name="num">砖块数量</param>
private void crt_zhuan(Point brick_info,int num)
{
int widght_num = (int)((gd_ball.ActualWidth - 40) / brick_info.X);
int height_num = (int)(((gd_ball.ActualHeight) / 3 * 2 - 20) / brick_info.Y);
int max_num = widght_num * height_num;
if (max_num < num)
{
MessageBox.Show("砖过大或数量过多,请重新生成\r\n" + "最多生成 " + max_num.ToString() + " 块");
return;
}
Point point_start = new Point();
point_start.X = 20 - (gd_ball.ActualWidth / 2);
point_start.Y = 20 - gd_ball.ActualHeight; ;
brick_addr = GetRandomArray(num, 0, max_num);
int count = 0;
brick_list.Clear();
brick_list = new List<Rect>();
gd_table.Children.Clear();
gd_table.RowDefinitions.Clear();
gd_table.ColumnDefinitions.Clear();
for (int i = 0; i < height_num; i++)
{
RowDefinition rowDefinition = new RowDefinition();
rowDefinition.MinHeight = brick_info.Y;
rowDefinition.MaxHeight = brick_info.Y;
gd_table.RowDefinitions.Add(rowDefinition);
}
for (int j = 0; j < widght_num; j++)
{
ColumnDefinition columnDefinition = new ColumnDefinition();
columnDefinition.MinWidth = brick_info.X;
columnDefinition.MaxWidth = brick_info.X;
gd_table.ColumnDefinitions.Add(columnDefinition);
}
for (int i = 0; i < height_num; i++)
{
for (int j = 0; j < widght_num; j++)
{
for (int k = 0; k < num; k++)
{
//if (count == addr[k])
if (count == brick_addr[k])
{
//添加砖
Rect rect_t = new Rect();
Point p = new Point(0, 0);
p.X= point_start.X + j * brick_info.X + brick_info.X / 2;
p.Y= point_start.Y + i * brick_info.Y + brick_info.Y / 2;
//rect_t.Addr.X = point_start.X + j * brick_info.X + brick_info.X / 2;
//rect_t.Addr.Y = point_start.Y + i * brick_info.Y + brick_info.Y / 2;
rect_t.Addr = p;
rect_t.Width = brick_info.X;
rect_t.Height = brick_info.Y;
rect_t.Stat = 1;
rect_t.Index = count;
brick_list.Add(rect_t);
//显示
BrushConverter conv = new BrushConverter();
Brush bru;
bru = conv.ConvertFromInvariantString("#FFB6BFBF") as Brush;
Brush back;
back = conv.ConvertFromInvariantString("#FF00BFBF") as Brush;
//Rectangle ret_t = new Rectangle() { Width = rect_t.Width, Name= "rect_"+count.ToString(), Height = rect_t.Height, Fill = bru, Stroke = back };
Rectangle ret_t = new Rectangle() { Width = rect_t.Width, Name = "rect_" + count.ToString(), Height = rect_t.Height, Fill = bru, Stroke = back };
ret_t.SetValue(Grid.RowProperty, i);
ret_t.SetValue(Grid.ColumnProperty, j);
gd_table.Children.Add(ret_t);
break;
}
}
count++;
}
}
}
#endregion
#region///控件事件
/// <summary>
/// 速度更改按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void sd_bool_speed_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
// bool_speed = (int)(sd_bool_speed.Value);
ball_info.Speed.Y = (int)(sd_bool_speed.Value);
}
/// <summary>
/// 底板移动事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void gd_ball_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Point p = e.GetPosition((IInputElement)sender);
Point d = new Point(0, 0);
double max_leng = (gd_ball.ActualWidth - rt_wb.ActualWidth - rt_rect.ActualWidth) / 2;
d.X= p.X - max_leng;
d.Y = rect_info.Addr.Y;
//rect_info.Addr.X = p.X - max_leng;
if (d.X < -max_leng)
{
d.X = -max_leng;
}
if (d.X > max_leng)
{
d.X = max_leng;
}
rect_info.Addr = d;
sd_x.Value = rect_info.Addr.X;
}
}
/// <summary>
/// 更改挡板坐标
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void sd_x_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Point d = new Point(0, 0);
d.X= sd_x.Value;
d.Y = rect_info.Addr.Y;
//rect_info.Addr.X = sd_x.Value;
double max_leng = (gd_ball.ActualWidth - rt_wb.ActualWidth - rt_rect.ActualWidth) / 2;
if (d.X < -max_leng)
{
d.X = -max_leng;
}
if (d.X > max_leng)
{
d.X = max_leng;
}
rect_info.Addr = d;
sd_x.Value = rect_info.Addr.X;
}
/// <summary>
/// 重新开始游戏
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void bt_crt_Click(object sender, RoutedEventArgs e)
{
aTimer.Stop();
System.Threading.Thread.Sleep(100);
ball_info.Speed.X = 0;
ball_info.Addr.X = 0;
ball_info.Addr.Y = -10;
brick_num = (int)sd_brick_num.Value;
brick_run_stpe = 0;
re_brick_count = 0;
processCount.TotalSecond = 0;
processCount.Stpe = 0;
crt_zhuan(brick_info, brick_num);
lb_brick_count.Content = brick_num;
lb_re_count.Content = 0;
lb_lost_count.Content = brick_list.Count - re_brick_count;
lb_run_stpe.Content = brick_run_stpe;
lb_time.Content = processCount.GetHour() + ":" + processCount.GetMinute() + ":" + processCount.GetSecond();
}
/// <summary>
/// 启动运行
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void bt_start_Click(object sender, RoutedEventArgs e)
{
ball_info.Speed.X = 0;
ball_info.Speed.Y = sd_bool_speed.Value;
brick_num = (int)sd_brick_num.Value;
aTimer.Start();
}
/// <summary>
/// 关闭窗口
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_Closing(object sender, CancelEventArgs e)
{
aTimer.Stop();
}
/// <summary>
/// 关联A键
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cb_start_game_Executed(object sender, ExecutedRoutedEventArgs e)
{
bt_start_Click(null, null);
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cb_start_game_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
/// <summary>
/// 窗体大小改变
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
sd_x.Maximum = gd_ball.ActualWidth / 2;
sd_x.Minimum = -gd_ball.ActualWidth / 2;
}
#endregion
}
/// <summary>
/// 实现倒计时功能的类
/// </summary>
public class ProcessCount
{
private Int32 _TotalSecond;
private int _stpe = 0;
public Int32 TotalSecond
{
get { return _TotalSecond; }
set { _TotalSecond = value; }
}
public int Stpe
{
get { return _stpe; }
set { _stpe = value; }
}
/// <summary>
/// 构造函数
/// </summary>
public ProcessCount(Int32 totalSecond, int s = 0)
{
this._TotalSecond = totalSecond;
this.Stpe = s;
}
/// <summary>
/// 减秒
/// </summary>
/// <returns></returns>
public bool ProcessCountDown()
{
if (_TotalSecond == 0)
return false;
else
{
_TotalSecond--;
return true;
}
}
/// <summary>
/// 加秒
/// </summary>
/// <returns></returns>
public bool ProcessCountUp()
{
_TotalSecond++;
return true;
}
/// <summary>
/// 获取小时显示值
/// </summary>
/// <returns></returns>
public string GetHour()
{
return String.Format("{0:D2}", (_TotalSecond / 3600));
}
/// <summary>
/// 获取分钟显示值
/// </summary>
/// <returns></returns>
public string GetMinute()
{
return String.Format("{0:D2}", (_TotalSecond % 3600) / 60);
}
/// <summary>
/// 获取秒显示值
/// </summary>
/// <returns></returns>
public string GetSecond()
{
return String.Format("{0:D2}", _TotalSecond % 60);
}
}
public sealed class MillisecondTimer : IComponent, IDisposable
{
private static TimerCaps caps;
private int interval;
private bool isRunning;
private int resolution;
private TimerCallback timerCallback;
private int timerID;
public int Interval
{
get
{
return this.interval;
}
set
{
if ((value < caps.periodMin) || (value > caps.periodMax))
{
throw new Exception("超出计时范围!");
}
this.interval = value;
}
}
/// <summary>
///
/// </summary>
public bool IsRunning
{
get
{
return this.isRunning;
}
}
/// <summary>
///
/// </summary>
public ISite Site
{
set;
get;
}
public event EventHandler Disposed; // 这个事件实现了IComponet接口
public event EventHandler Tick;
static MillisecondTimer()
{
timeGetDevCaps(ref caps, Marshal.SizeOf(caps));
}
public MillisecondTimer()
{
this.interval = caps.periodMin; //
this.resolution = caps.periodMin; //
this.isRunning = false;
this.timerCallback = new TimerCallback(this.TimerEventCallback);
}
public MillisecondTimer(IContainer container)
: this()
{
container.Add(this);
}
~MillisecondTimer()
{
timeKillEvent(this.timerID);
}
public void Start()
{
if (!this.isRunning)
{
this.timerID = timeSetEvent(this.interval, this.resolution, this.timerCallback, 0, 1); // 间隔性地运行
if (this.timerID == 0)
{
throw new Exception("无法启动计时器");
}
this.isRunning = true;
}
}
public void Stop()
{
if (this.isRunning)
{
timeKillEvent(this.timerID);
this.isRunning = false;
}
}
/// <summary>
/// 实现IDisposable接口
/// </summary>
public void Dispose()
{
timeKillEvent(this.timerID);
GC.SuppressFinalize(this);
EventHandler disposed = this.Disposed;
if (disposed != null)
{
disposed(this, EventArgs.Empty);
}
}
//*************************************************** 内部函数 ******************************************************************
[DllImport("winmm.dll")]
private static extern int timeSetEvent(int delay, int resolution, TimerCallback callback, int user, int mode);
[DllImport("winmm.dll")]
private static extern int timeKillEvent(int id);
[DllImport("winmm.dll")]
private static extern int timeGetDevCaps(ref TimerCaps caps, int sizeOfTimerCaps);
// The timeGetDevCaps function queries the timer device to determine its resolution.
private void TimerEventCallback(int id, int msg, int user, int param1, int param2)
{
if (this.Tick != null)
{
this.Tick(this, null); // 引发事件
}
}
//*************************************************** 内部类型 ******************************************************************
private delegate void TimerCallback(int id, int msg, int user, int param1, int param2); // timeSetEvent所对应的回调函数的签名
/// <summary>
/// 定时器的分辨率(resolution)。单位是ms,毫秒
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct TimerCaps
{
public int periodMin;
public int periodMax;
}
}
}
- 代码下载:
打砖块代码V0.0.1_20210118
试用程序:
链接:https://pan.baidu.com/s/1HFWxnroo2Hgk6d7TtQ3p1w
提取码:3ayx