WPF介绍和简单的2D跳棋程序
WPF(Windows Presentation Foundation)是微软推出的基于Windows Vista的用户界面框架,属于.NET Framework 3.0的一部分。它提供了统一的编程模型、语言和框架,真正做到了分离界面设计人员与开发人员的工作;同时它提供了全新的多媒体交互用户图形界面。(来自百度百科)
在WPF的框架下,可以使用C#和xmal语言来设计界面。两种设计方法各自的好处,xmal语言是一种标记性语言,使用比较简单和灵活。C#下设计和一般的设计差别不大,但是要注意WPF下的类和接口等。具体的可以参考相关的教程。
关于WPF的入门,可以购买刘铁猛的《深入浅出WPF》,这是一本很好的书,这是他的博客:http://blog.csdn.net/fantasiax ,上面有很多很好的文章,值得一看。
既然WPF可以用来设计很好的界面,所以利用它来做一个简单的跳棋游戏。这里主要使用的C#来设计,下面是主要的程序。程序写的很好乱,没有按照一定的编码规则进行设计和类的设计很差,但是这个程序是我2天之内写出来的,大家可以看看。
源代码:
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;
namespace WPF3
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
Canvas mainPanel = new Canvas();
const int North = 1;
const int NorthWest = 2;
const int SouthWest = 3;
const int South = 4;
const int SouthEast = 5;
const int NorthEast = 6;
const int TotalChess = 10;//the total chesss on the panel for one player
Point center;
double r;
const int APlayer = 1; int AEnterZoon = 0;
const int BPlayer = -1; int BEnterZoon = 0;
Choise choise = new Choise();
Brush Bs;
public MainWindow()
{
InitializeComponent();
this.Content = mainPanel;
DrawMailPanel();
center = GetCenter();
r = GetR();
DrawPanel();
}
/// <summary>
/// this function draw the outline of the mainpanel
/// </summary>
public void DrawMailPanel()
{
this.Width = 800;
this.Height = 600;
LinearGradientBrush myLinearGradientBrush = new LinearGradientBrush();
myLinearGradientBrush.GradientStops.Add(
new GradientStop(Colors.Red, 0.0));
myLinearGradientBrush.GradientStops.Add(
new GradientStop(Colors.LimeGreen, 0.5));
myLinearGradientBrush.GradientStops.Add(
new GradientStop(Colors.Yellow, 1.0));
mainPanel.Background = myLinearGradientBrush;
}
//
//draw the whole panel
//
public void DrawPanel()
{
choise.r = r* 7 / (1.732* 30);
int flag = 0;
for (int i = 0; i < 7; i++)
{
flag = i + 1;
PointCollection PC = GetPoints(r, flag);
DrawPoly(PC, flag);
}
List<KeyValuePair<double, Point>> LKP = new List<KeyValuePair<double, Point>>();
for (int i = 0; i < 6; i++)
{
flag = i + 1;
PointCollection newPC = GetChessPoints(r * 14 / 15, flag);
//used to ommit the same point
for (int j = 0; j < newPC.Count; j++)
{
int FlagOfDraw = 0;
Point p = newPC.ElementAt(j);
double key = (p.Y-center.Y)/(p.X-center.X);
KeyValuePair<double,Point> kp = new KeyValuePair<double,Point>(key,p);
if(Math.Abs(key-1.732)<0.001|| Math.Abs(key+1.732)<0.001 ||Math.Abs(key) <0.001)
{
for(int k=0;k<LKP.Count;k++)
{
if(Math.Abs(key-LKP.ElementAt(k).Key) < 0.001)
{
if(clacNorm(p,LKP.ElementAt(k).Value)==0)
{
FlagOfDraw = 1;
break;
}
}
}
}
if (0==FlagOfDraw)
{
LKP.Add(kp);
DrawPoint(p, flag, r / 30);
}
}
}
DrawPoint(center, flag, r / 30);
}
//
//get the center of the panel
//
public Point GetCenter()
{
Point center = new Point();
center.X = this.Width / 2; center.Y = this.Height / 2;
return center;
}
//
//get the radius
//
public double GetR()
{
return this.Height > this.Width ? this.Width * 2 / 5 : this.Height * 2 / 5;
}
//
//return a collection of points
//
public PointCollection GetPoints(double radius, int flag)
{
PointCollection PC = new PointCollection();
double Offset1 = radius / 2 * Math.Tan(30 * Math.PI / 180);
double Offset2 = radius / 2 / Math.Cos(30 * Math.PI / 180);
//return a set of points which represent the three points in a triangle
switch (flag)
{
case North:
PC.Add(new Point(center.X - Offset1, center.Y - radius / 2));
PC.Add(new Point(center.X, center.Y - radius));
PC.Add(new Point(center.X + Offset1, center.Y - radius / 2));
Bs = Brushes.Yellow;
break;
case NorthWest:
PC.Add(new Point(center.X - Offset1, center.Y - radius / 2));
PC.Add(new Point(center.X - Offset1 - Offset2, center.Y - radius / 2));
PC.Add(new Point(center.X - Offset2, center.Y));
Bs = Brushes.Green;
break;
case SouthWest:
PC.Add(new Point(center.X - Offset2, center.Y));
PC.Add(new Point(center.X - Offset1 - Offset2, center.Y + radius / 2));
PC.Add(new Point(center.X - Offset1, center.Y + radius / 2));
Bs = Brushes.Orange;
break;
case South:
PC.Add(new Point(center.X - Offset1, center.Y + radius / 2));
PC.Add(new Point(center.X, center.Y + radius));
PC.Add(new Point(center.X + Offset1, center.Y + radius / 2));
Bs = Brushes.Red;
break;
case SouthEast:
PC.Add(new Point(center.X + Offset2, center.Y));
PC.Add(new Point(center.X + Offset1 + Offset2, center.Y + radius / 2));
PC.Add(new Point(center.X + Offset1, center.Y + radius / 2));
Bs = Brushes.Blue;
break;
case NorthEast:
PC.Add(new Point(center.X + Offset1, center.Y - radius / 2));
PC.Add(new Point(center.X + Offset1 + Offset2, center.Y - radius / 2));
PC.Add(new Point(center.X + Offset2, center.Y));
Bs = Brushes.Purple;
break;
default://draw the center origon.
PC.Add(new Point(center.X - Offset1, center.Y - radius / 2));
PC.Add(new Point(center.X - Offset2, center.Y));
PC.Add(new Point(center.X - Offset1, center.Y + radius / 2));
PC.Add(new Point(center.X + Offset1, center.Y + radius / 2));
PC.Add(new Point(center.X + Offset2, center.Y));
PC.Add(new Point(center.X + Offset1, center.Y - radius / 2));
Bs = Brushes.LightYellow;
break;
}
return PC;
}
//
//get tht position of the chess,the return result is only a set of points
//
public PointCollection GetChessPoints(double radius, int flag)
{
PointCollection PC = GetPoints(radius, flag);
PointCollection NewPC = new PointCollection();
Point[] MiddleP = new Point[5];
PC.Add(center);
PC.Add(PC.ElementAt(0));
for (int i = 0; i < PC.Count - 1; i++)
{
Point[] p = new Point[3];
GetMiddlePoint(PC.ElementAt(i),PC.ElementAt(i+1),p);
MiddleP[i] = p[1];
for (int j = 0; j < p.Length; j++)
{
NewPC.Add(p[j]);
}
NewPC.Add(PC.ElementAt(i));
}
NewPC.RemoveAt(NewPC.Count-1);
Point[] MiddlePP = new Point[5];
MiddleP[4] = MiddleP[0];
for (int i = 0; i < 4; i++)
{
MiddlePP[i] =new Point((MiddleP[i].X + MiddleP[i+1].X) / 2, (MiddleP[i].Y + MiddleP[i+1].Y) / 2);
NewPC.Add(MiddlePP[i]);
}
MiddlePP[4] = MiddlePP[0];
for (int i = 0; i < 4; i++)
{
NewPC.Add(new Point((MiddlePP[i].X + MiddlePP[i+1].X) / 2, (MiddlePP[i].Y + MiddlePP[i+1].Y) / 2));
}
NewPC.Add(new Point((MiddlePP[0].X + MiddlePP[2].X) / 2, (MiddlePP[0].Y + MiddlePP[2].Y) / 2));
return NewPC;
}
//
//get the innner point on a line.
//
public void GetMiddlePoint(Point p1, Point p2,Point[] p)
{
for(int i=0; i<p.Length; i++)
{
p[i] = new Point(p1.X + (p2.X - p1.X) * (i + 1) / 4, p1.Y + (p2.Y - p1.Y) * (i + 1) / 4);
}
}
//
//draw a polygon in the panel.
//
public void DrawPoly(PointCollection PC, int flag)
{
if (flag > 7 || flag < 1)
{
MessageBox.Show("Error: The input flag is error.Please change the falg!");
return;
}
Polygon DrawPolygon = new Polygon();
DrawPolygon.Fill = Bs;
DrawPolygon.Stroke = Brushes.Black;
DrawPolygon.StrokeThickness = 0.5;
DrawPolygon.Points = PC;
//this is a drawing procedure.
mainPanel.Children.Add(DrawPolygon);
}
/// <summary>
/// draw a point using a cirsle(ellipse)
/// </summary>
/// <param name="PC"></param>
/// <param name="flag"></param>
public void DrawPoint(Point p, int flag,double EllipseR)
{
if (flag > 6 || flag < 1)
{
MessageBox.Show("Error: The input flag is error.Please change the falg!");
return;
}
Ellipse ellipse = new Ellipse();
ellipse.Stroke = System.Windows.Media.Brushes.Black;
if (p.Y < center.Y - r / 2 || p.Y > center.Y + r / 2)
{
if(flag==1 && p.Y<center.Y-r/2){ellipse.Fill = Brushes.Yellow;}
else if (flag == 4 && p.Y > center.Y + r / 2) { ellipse.Fill = Brushes.Red; }
}
else
{
ellipse.Fill = System.Windows.Media.Brushes.Chocolate;
}
Canvas.SetTop(ellipse, p.Y-EllipseR);
Canvas.SetLeft(ellipse, p.X-EllipseR);
ellipse.Width = 2*EllipseR;
ellipse.Height = 2*EllipseR;
ellipse.MouseLeftButtonDown += new MouseButtonEventHandler(ellipse_MouseLeftButtonDown);
ellipse.MouseRightButtonDown += new MouseButtonEventHandler(ellipse_MouseRightButtonDown);
mainPanel.Children.Add(ellipse);
}
/// <summary>
/// when you press on one ellipse, will trigger this handler.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Ellipse ellipse = sender as Ellipse;
if (choise.IsChoosing())
{//you have pressed a ellipse,then your action reprensent that you are moving a chess
//so we need to determine the valitity of your action.
Point SelectP = new Point(Canvas.GetLeft(ellipse), Canvas.GetTop(ellipse));
Point OriginalP = choise.GetChoise();
double ratio = clacNorm(SelectP,OriginalP);
//MessageBox.Show(ratio.ToString());
if (ellipse.Fill == Brushes.Chocolate)
{
UIElementCollection iter = mainPanel.Children;
Ellipse OriginalEllipse = new Ellipse();
Point OriginallEllipsePoint = new Point();
for (int i = 0; i < iter.Count; i++)
{
if (iter[i] is Ellipse)
{
OriginalEllipse = iter[i] as Ellipse;
OriginallEllipsePoint = new Point(Canvas.GetLeft(OriginalEllipse), Canvas.GetTop(OriginalEllipse));
if(clacNorm(OriginalP, OriginallEllipsePoint) < 0.001)
{
break;
}
}
}
if (Math.Abs(ratio-1)<0.001)
{
//this is ok,have no chess on the it.
//MessageBox.Show(ratio.ToString());
OriginalEllipse.Fill = Brushes.Chocolate;
ellipse.Fill = choise.GetBrush();
choise.SetChoosing(false);
clacResult(SelectP.Y,OriginalP.Y);
choise.setFlagOfPlayer(-choise.GetFlagOfPlayer());
}
else
{
int FLagOfMove = 0;
for (int i = 0; i < iter.Count; i++)
{
if (iter[i] is Ellipse)
{
Ellipse MiddleEllipse = iter[i] as Ellipse;
Point MiddleP = new Point(Canvas.GetLeft(MiddleEllipse), Canvas.GetTop(MiddleEllipse));
double SM = Math.Abs(clacNorm(SelectP, MiddleP));
double OM = Math.Abs(clacNorm(OriginallEllipsePoint, MiddleP));
if (Math.Abs(OM +SM - ratio) < 0.001 && OM >0.001 && SM>0.001)
{
//MessageBox.Show();
if (MiddleEllipse.Fill == Brushes.Chocolate)
{
FLagOfMove = 0;
break;
}
else
{
FLagOfMove += 1;
}
}
//MessageBox.Show(FLagOfMove.ToString());
}
}
//MessageBox.Show((FLagOfMove-ratio+1).ToString());
if (Math.Abs(FLagOfMove-ratio+1)<0.001)
{
OriginalEllipse.Fill = Brushes.Chocolate;
ellipse.Fill = choise.GetBrush();
choise.SetChoosing(false);
clacResult(SelectP.Y, OriginalP.Y);
choise.setFlagOfPlayer(-choise.GetFlagOfPlayer());
}
}
}
}
else if(!choise.IsChoosing() && ellipse.Fill != Brushes.Chocolate)
{//you don't choose any ellipse
if (choise.GetFlagOfPlayer() == APlayer)
{
if (ellipse.Fill != Brushes.Yellow)
{
MessageBox.Show("please wait,it is not your turn.");
return;
}
}
else
{
if (ellipse.Fill != Brushes.Red)
{
MessageBox.Show("please wait,it is not your turn.");
return;
}
}
choise.SetChoosing(true);
choise.SetChoise( new Point(Canvas.GetLeft(ellipse),Canvas.GetTop(ellipse)));
choise.setBrush(ellipse.Fill);
ellipse.Fill = Brushes.DarkOrchid;
}
}
void ellipse_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
Ellipse ellipse = sender as Ellipse;
Point p = new Point(Canvas.GetLeft(ellipse),Canvas.GetTop(ellipse));
//MessageBox.Show(clacNorm(choise.GetChoise(), p).ToString());
if (choise.IsChoosing() && clacNorm(choise.GetChoise(),p)==0 && ellipse.Fill==Brushes.DarkOrchid)
{ //you have choose a ellipse,use this method to cancel this choice.
choise.SetChoosing(false);
ellipse.Fill = choise.GetBrush();
}
}
public void clacResult(double NewY,double OldY)
{
if (choise.GetFlagOfPlayer() == APlayer && NewY > center.Y + r / 2 && OldY < center.Y + r / 2)
{
AEnterZoon++;
if (AEnterZoon == TotalChess)
{
MessageBox.Show("Game Over!");
}
}
else if (choise.GetFlagOfPlayer() == BPlayer && NewY < center.Y - r / 2 && OldY >center.Y - r / 2)
{
BEnterZoon++;
if (BEnterZoon == TotalChess)
{
MessageBox.Show("Game Over!");
}
}
}
public double clacNorm(Point p1,Point p2)
{
return Math.Sqrt((p1.X - p2.X)*(p1.X - p2.X)+(p1.Y - p2.Y)*(p1.Y - p2.Y))/choise.r;
}
}
public class Choise
{
private bool isChoosing;
private Point choise;
private Brush brush;
public double r;
int FlagOfplayer;
public Choise()
{
isChoosing = false;
FlagOfplayer = 1;
}
public int GetFlagOfPlayer()
{
return FlagOfplayer;
}
public void setFlagOfPlayer(int flag)
{
if (FlagOfplayer != 1 && FlagOfplayer != -1)
{
MessageBox.Show("Error!");
}
FlagOfplayer = flag;
}
public void setBrush(Brush brush)
{
this.brush = brush;
}
public Brush GetBrush()
{
return brush;
}
public bool IsChoosing()
{
return isChoosing;
}
public void SetChoosing(bool choosing)
{
isChoosing = choosing;
}
public Point GetChoise()
{
return choise;
}
public void SetChoise(Point p)
{
choise = p;
}
}
}
如果要运行上面的程序,只需要建立一个新的WPF应用程序,名字时WPF3,然后把MainWindow.xaml.cs中的源程序直接用上面的程序替了就行。
现在只有红黄两方是可以游戏的,也就是你只能动黄的和红的棋子,并且是黄的先行。用的左键选中一个棋子,如果去取消,使用右键在点一下。然后用左键点你要去的位置就OK了。