Creating a Chess Board using Windows Forms - winforms

What is the best way to create chess board using Windows Forms?
I am still new to graphics coding in winforms and I am not sure, which control to use for that?
The user should be able to put chess pieces into the board.
I am trying to write Chess Diagram Editor.
Thank you

There are a lot of ways. Here's an alternative that gets you started with some WinForms concepts:
(It uses a 2D grid of Panel controls to create a chessboard. To extend it you might change the background picture of each Panel to show chess pieces. The game play is up to you to define.)
// class member array of Panels to track chessboard tiles
private Panel[,] _chessBoardPanels;
// event handler of Form Load... init things here
private void Form_Load(object sender, EventArgs e)
{
const int tileSize = 40;
const int gridSize = 12;
var clr1 = Color.DarkGray;
var clr2 = Color.White;
// initialize the "chess board"
_chessBoardPanels = new Panel[gridSize, gridSize];
// double for loop to handle all rows and columns
for (var n = 0; n < gridSize; n++)
{
for (var m = 0; m < gridSize; m++)
{
// create new Panel control which will be one
// chess board tile
var newPanel = new Panel
{
Size = new Size(tileSize, tileSize),
Location = new Point(tileSize * n, tileSize * m)
};
// add to Form's Controls so that they show up
Controls.Add(newPanel);
// add to our 2d array of panels for future use
_chessBoardPanels[n, m] = newPanel;
// color the backgrounds
if (n % 2 == 0)
newPanel.BackColor = m % 2 != 0 ? clr1 : clr2;
else
newPanel.BackColor = m % 2 != 0 ? clr2 : clr1;
}
}
}

Best way is to use a 'chess starter kit': http://www.chessbin.com/page/Chess-Game-Starer-Kit.aspx (alternative project: http://www.codeproject.com/KB/game/SrcChess.aspx)
Nowadays a lot of things have starter kits (for C#) which gives you a sample to get started on.

In the controls OnPaint eventhandler, you start out by drawing the chessboard pattern either implicitly using the formula (floor(x * 8) mod 2) = (floor(y * 8) mod 2) or by just drawing the squares with Graphics.FillRectangle. The second step would be to draw the pieces on top with Graphics.DrawImage.

I don't know what you want to do with this chess board, but if it's only a background to display after pieces, your best shot is to set a background image.

Related

Aligning a card array in-game

I'm creating a tcg (trading card game) and I would like to know how can I change the layout of the cards while playing. I mean that the cards will be spread in line aligned to the center of the screen both vertically and horizontaly, on a canvas, and when I draw/dismiss a card I would like the cards to fill in the space and align again in game. How can I do that? any ideas? I thought of a solution about when your turn begins (Start from the center of the screen then step back the length of a step X the number of cards / 2 and then spawn the cards one after another), but I can't figure out how to change the alignment of cards when you dismiss one of them without loading them all again...
Image for example
Using the same method you used for the initial position you should be able to get the new position. Now you have two positions for each card: oldPos and newPos.
Your cards are already instantiated. Their positions are stored in Transform.position. Your goal is to move from oldPos to newPos. The simplest way would be:
myCard.transform.position = newPos;
This will instantly move your cards to their new positions. However, it's not common to teleport your objects because it does not often present good feelings to users. A better solution is to smoothly move the object from a position to another.
To do this, you can move around an existing object by transform.Translate(new Vector3());, where the Vector3 will decide its moving speed. The method Translate() is doing position += movementDirection * movementAmount as you would've expected.
Moving any object over frames is called Animation. There are techniques for animation to make movements look more better (look faster than it really is, or look natural). One common method from mathematics is called linear interpolation, or lerp. Using lerp, you can easily compute intermediate points between two end-positions, and it will look natural and nice if you put your objects along the points you calculated. I believe this is what you are looking for.
========
Edit:
Here's an example of how this could be achieved. Note that Card is moving by the same amount of distance per frame in this example. Using lerp (ease-in, ease-out, etc), you could make this animation even better.
Another point I would like you to note is that I'm doing if (Vector2.Distance(nextPosition, transform.position) < 10), not if(oldPosition.equals(newPosition)). The reason is that equals() is not safe to compare floats because they are often stored as 0.4999999 and 0.50001 instead of 0.5 and 0.5. So the best way of checking floats is to test if they are "Close Enough" to each other.
Finally, you could improve the following code may improve in MANY DIFFERNET WAYS. For instnace:
Destroy() and Instantiate() is very slow operations and you
should use Object Pooling because you know you will perform these
operations constantly.
The movement of Card could be improved by better animation technique like lerp.
There may be other ways of storing List<Card> Cards
OnCardClick() is using FindObjectOfType<CardSpawner>().OnCardDeleted(this) and this requires Card to know about CardSpawner. This is called Tight Coupling, which is known as evil. There are a lot of discussions you can find why this is bad. A recommended solution would be to use event (better UnityEvent in Unity3d).
CardSpawner.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CardSpawner : MonoBehaviour
{
[SerializeField] GameObject CardParent;
[SerializeField] GameObject CardPrefab;
Vector2 DefaultSpawnPosition = new Vector2(Screen.width / 2f, Screen.height / 10f);
List<Card> Cards = new List<Card>();
public void OnClickButton()
{
SpawnNewCard();
AssignNewPositions();
AnimateCards();
}
public void OnCardDeleted(Card removedCard)
{
Cards.Remove(removedCard);
AssignNewPositions();
AnimateCards();
}
void SpawnNewCard()
{
GameObject newCard = (GameObject)Instantiate(CardPrefab, DefaultSpawnPosition, new Quaternion(), CardParent.GetComponent<Transform>());
Cards.Add(newCard.GetComponent<Card>());
}
void AssignNewPositions()
{
int n = Cards.Count;
float widthPerCard = 100;
float widthEmptySpaceBetweenCards = widthPerCard * .2f;
float totalWidthAllCards = (widthPerCard * n) + (widthEmptySpaceBetweenCards * (n-1));
float halfWidthAllCards = totalWidthAllCards / 2f;
float centreX = Screen.width / 2f;
float leftX = centreX - halfWidthAllCards;
for (int i = 0; i < n; i++)
{
if (i == 0)
Cards[i].nextPosition = new Vector2(leftX + widthPerCard / 2f, Screen.height / 2f);
else
Cards[i].nextPosition = new Vector2(leftX + widthPerCard / 2f + ((widthPerCard + widthEmptySpaceBetweenCards) * i), Screen.height / 2f);
}
}
void AnimateCards()
{
foreach (Card card in Cards)
card.StartMoving();
}
}
Card.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Card : MonoBehaviour
{
public Vector2 oldPosition;
public Vector2 nextPosition;
bool IsMoving;
void Update ()
{
if (IsMoving)
{
int steps = 10;
Vector2 delta = (nextPosition - oldPosition) / steps;
transform.Translate(delta);
if (Vector2.Distance(nextPosition, transform.position) < 10)
IsMoving = false;
}
}
public void StartMoving()
{
IsMoving = true;
oldPosition = transform.position;
}
public void OnCardClick()
{
UnityEngine.Object.Destroy(this.gameObject);
Debug.Log("AfterDestroy");
FindObjectOfType<CardSpawner>().OnCardDeleted(this);
}
}

An efficient way to paint gradient rectangles

I'm generating a bunch of RectangleF objects having different sizes and positions. What would be the best way to fill them with a gradient Brush in GDI+?
In WPF I could create a LinearGradientBrush, set Start and End relative points and WPF would take care of the rest.
In GDI+ however, the gradient brush constructor requires the position in absolute coordinates, which means I have to create a Brush for each of the rectangle, which would be a very complex operation.
Am I missing something or that's indeed the only way?
You can specify a transform at the moment just before the gradient is applied if you would like to declare the brush only once. Note that using transformations will override many of the constructor arguments that can be specified on a LinearGradientBrush.
LinearGradientBrush.Transform Property (System.Drawing.Drawing2D)
To modify the transformation, call the methods on the brush object corresponding to the desired matrix operations. Note that matrix operations are not commutative, so order is important. For your purposes, you'll probably want to do them in this order for each rendition of your rectangles: Scale, Rotate, Offset/Translate.
LinearGradientBrush.ResetTransform Method # MSDN
LinearGradientBrush.ScaleTransform Method (Single, Single, MatrixOrder) # MSDN
LinearGradientBrush.RotateTransform Method (Single, MatrixOrder) # MSDN
LinearGradientBrush.TranslateTransform Method (Single, Single, MatrixOrder) # MSDN
Note that the system-level drawing tools don't actually contain a stock definition for gradient brush, so if you have performance concerns about making multiple brushes, creating a multitude of gradient brushes shouldn't cost any more than the overhead of GDI+/System.Drawing maintaining the data required to define the gradient and styling. You may be just as well off to create a Brush per rectangle as needed, without having to dive into the math required to customize the brush via transform.
Brush Functions (Windows) # MSDN
Here is a code example you can test in a WinForms app. This app paints tiles with a gradient brush using a 45 degree gradient, scaled to the largest dimension of the tile (naively calculated). If you fiddle with the values and transformations, you may find that it isn't worth using the technique setting a transform for all of your rectangles if you have non-trivial gradient definitions. Otherwise, remember that your transformations are applied at the world-level, and in the GDI world, the y-axis is upside down, whereas in the cartesian math world, it is ordered bottom-to-top. This also causes the angle to be applied clockwise, whereas in trigonometry, the angle progresses counter-clockwise in increasing value for a y-axis pointing up.
using System.Drawing.Drawing2D;
namespace TestMapTransform
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Rectangle rBrush = new Rectangle(0,0,1,1);
Color startColor = Color.DarkRed;
Color endColor = Color.White;
LinearGradientBrush br = new LinearGradientBrush(rBrush, startColor, endColor, LinearGradientMode.Horizontal);
int wPartitions = 5;
int hPartitions = 5;
int w = this.ClientSize.Width;
w = w - (w % wPartitions) + wPartitions;
int h = this.ClientSize.Height;
h = h - (h % hPartitions) + hPartitions;
for (int hStep = 0; hStep < hPartitions; hStep++)
{
int hUnit = h / hPartitions;
for (int wStep = 0; wStep < wPartitions; wStep++)
{
int wUnit = w / wPartitions;
Rectangle rTile = new Rectangle(wUnit * wStep, hUnit * hStep, wUnit, hUnit);
if (e.ClipRectangle.IntersectsWith(rTile))
{
int maxUnit = wUnit > hUnit ? wUnit : hUnit;
br.ResetTransform();
br.ScaleTransform((float)maxUnit * (float)Math.Sqrt(2d), (float)maxUnit * (float)Math.Sqrt(2d), MatrixOrder.Append);
br.RotateTransform(45f, MatrixOrder.Append);
br.TranslateTransform(wUnit * wStep, hUnit * hStep, MatrixOrder.Append);
e.Graphics.FillRectangle(br, rTile);
br.ResetTransform();
}
}
}
}
private void Form1_Resize(object sender, EventArgs e)
{
this.Invalidate();
}
}
}
Here's a snapshot of the output:
I recommend you to create a generic method like this:
public void Paint_rectangle(object sender, PaintEventArgs e)
{
RectangleF r = new RectangleF(0, 0, e.ClipRectangle.Width, e.ClipRectangle.Height);
if (r.Width > 0 && r.Height > 0)
{
Color c1 = Color.LightBlue;
Color c2 = Color.White;
Color c3 = Color.LightBlue;
LinearGradientBrush br = new LinearGradientBrush(r, c1, c3, 90, true);
ColorBlend cb = new ColorBlend();
cb.Positions = new[] { 0, (float)0.5, 1 };
cb.Colors = new[] { c1, c2, c3 };
br.InterpolationColors = cb;
// paint
e.Graphics.FillRectangle(br, r);
}
}
then, for every rectangle just call:
yourrectangleF.Paint += new PaintEventHandler(Paint_rectangle);
If the gradrients colors are all the same, you can make that method shorter. Hope that helped..

Creating chess GUI in WPF

Firstly: apologies if this is a duplicate post. Things got a bit confusing as I'm trying to post/register at same time.
I started investigating running UCI chess engines from a simple WPF window, got the hang of having the chess engine running onf a different thread to the interface, and have created a reasonably servcieable text-based front end.
I'm getting a bit more ambitious now, and would like to start building a GUI with chess pieces on it that will feed the player's moves to the chess engine, and represent the engine's moves on the board as well. I'm aiming for draggable pieces rather than clicking squares.
My current attempts involve using draggable user controls for the pieces on a <canvas> element. I'd be really interested to hear how other, more experienced WPF/.NET programmers would approach this, as I'm not entirely convinced I'm on the right track.
For example: would it be better to use a uniform grid and drag piece data between child elements? Should I create an abstract 'piece' class from which pieces such as pawns could derive? That kind of thing.
Any thoughts? This isn't a homework assignment or anything, just something I'm noodling around with in my spare time as an exercise.
I have implemented a chess board for my Silverlight Online Chess system.
Here is how I did it.
I made a seperate user control for the chess board
I added a grid 8x8 onto the control
I then added 64 Borders shading each one a different color (dark squares and light squares) Make sure to name each one. Each of the borders were placed on the grid using the Grid.Row and Grid.Col properties.
Within each Border I added an Image that will hold the chess piece image.
You will have to code some methods around setting the image to the correct chess piece based on your current game state.
Each of the Images received the same event (this is important), all 64 call the same piece of code:
MouseLeftButtonDown="Image_MouseLeftButtonDown"
MouseMove="Image_MouseMove"
MouseLeftButtonUp="Image_MouseLeftButtonUp"
The idea behind these 3 events is that we record when I click on the image (MouseLeftButtonDown) that gets me the origin of the click, then I call the event as the mouse is moving, that allows me to update the screen as the piece is moving, and the last event I record when I let go of the mouse button (MouseLeftButtonUp), this allows me to get the destination and send the move to my chess engine. Once the move is recorded by the chess engine I just redraw the chess board.
private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Image image = (Image)sender;
Border border = (Border)image.Parent;
image.CaptureMouse();
isMouseCapture = true;
mouseXOffset = e.GetPosition(border).X;
mouseYOffset = e.GetPosition(border).Y;
var chessPiece = (Image) sender;
var chessSquare = (Border) chessPiece.Parent;
var row = (byte) (Grid.GetRow(chessSquare));
var column = (byte) (Grid.GetColumn(chessSquare) - 1);
if (engine.HumanPlayer == ChessPieceColor.White)
{
SelectionChanged(row, column, false);
}
else
{
SelectionChanged((byte)(7 - row), (byte)(7 - column), false);
}
}
SelectionChanged is my own method for recording what source square the user selected.
isMouseCapture is also my own variable for recording when the user started draging the piece.
private void Image_MouseMove(object sender, MouseEventArgs e)
{
Image image = (Image)sender;
Border border = (Border)image.Parent;
if (!currentSource.Selected)
{
image.ReleaseMouseCapture();
isMouseCapture = false;
translateTransform = new TranslateTransform();
translateTransform.X = 0;
translateTransform.Y = 0;
mouseXOffset = 0;
mouseYOffset = 0;
}
if (isMouseCapture)
{
translateTransform = new TranslateTransform();
translateTransform.X = e.GetPosition(border).X - mouseXOffset;
translateTransform.Y = e.GetPosition(border).Y - mouseYOffset;
image.RenderTransform = translateTransform;
CalculateSquareSelected((int)translateTransform.X, (int)translateTransform.Y, false);
}
}
In the above CalculareSquareSelected converts the pixels moved to where I think the piece is moving to in the 8x8 chess board. For example say I moved 100 pixels and the chess board square is only 50 pixels than I moved 2 chess board squares.
private void Image_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (translateTransform == null)
{
return;
}
Image image = (Image)sender;
image.ReleaseMouseCapture();
isMouseCapture = false;
if (translateTransform.X > 10 || translateTransform.Y > 10 || translateTransform.X < -10 || translateTransform.Y < -10)
{
CalculateSquareSelected((int)translateTransform.X, (int)translateTransform.Y, true);
}
translateTransform = new TranslateTransform();
translateTransform.X = 0;
translateTransform.Y = 0;
mouseXOffset = 0;
mouseYOffset = 0;
image.RenderTransform = translateTransform;
}
If you have any questions feel free to contact me.

How to model a scrolling line graph in WPF?

I'm trying to re-learn WPF and I've started a little project that has a line graph, kind of like the CPU performance one you would see in Taskmanager. The graph is basically a canvas that has a punch of lines added to it's children and is based on an Avalon sample I found here http://msdn.microsoft.com/en-us/library/aa480159.aspx
Currently, when I get to the far right edge of the graph I clear my data set and reset my x-coordinate back to zero and the graph starts redrawing from the left hand side after a clear.
y = value;
x = x + 1;
if (x == samples)
{
CpuGraphAnimation2d.Children.RemoveRange(0, samples);
x = 0;
}
What I want to do is have the graph 'scroll' to the left as new values arrive, and effectively have all the old values shuffle to the left and drop the left most value.
What would be the most efficient way to achieve this effect in WPF?
You could try creating a StreamGeometry as follows, removing the first element of yourarray before doing the following:
StreamGeometry sg = new StreamGeometry();
using (StreamGeometryContext context = sg.Open())
{
context.BeginFigure(new Point(0, yourarray[0]), false, false);
for (int x = 0; x < len; x++)
{
context.LineTo(new Point(x, yourarray[x], true, true);
}
sg.Freeze();
System.Windows.Shapes.Path path = new System.Windows.Shapes.Path();
path.Data = sg;
path.Stroke = Brushes.Red;
}
which is a fast way of regenerating your graph each pass. the path created at the end of the code would need to be added to a control or panel in your window.

Selecting an object on a WPF Canvas?

I have a WPF Canvas with some Ellipse objects on it (displayed as circles). Each circle is from a collection class instance which is actually a custom hole pattern class. Each pattern has a certain number of circles, and each circle then gets added to the canvas using an iteration over the collection using the code below.
So, the canvas is populated with a bunch of circles and each circle belongs to a certain pattern instance. You can see a screenshot here: http://twitpic.com/1f2ci/full
Now I want to add the ability to click on a circle on the canvas, and be able to determine the collection it belongs to, so that I can then do some more work on the selected pattern to which that circle belongs.
public void DrawHoles()
{
// Iterate over each HolePattern in the HolePatterns collection...
foreach (HolePattern HolePattern in HolePatterns)
{
// Now iterate over each Hole in the HoleList of the current HolePattern...
// This code adds the HoleEntity, HoleDecorator, and HoleLabel to the canvas
foreach (Hole Hole in HolePattern.HoleList)
{
Hole.CanvasX = SketchX0 + (Hole.AbsX * _ZoomScale);
Hole.CanvasY = SketchY0 - (Hole.AbsY * _ZoomScale);
canvas1.Children.Add(Hole.HoleEntity);
}
}
}
All FrameworkElements have a Tag property which is of type object that can be used to hold arbitrary information. You could assign the HolePattern to the Tag property and easily use that later to get the associated collection.
i.e.:
...
Hole.HoleEntity.Tag = HolePattern as object;
canvas1.Children.Add(Hole.HoleEntity);
later on in the click event:
event(object sender,....)
{
Ellipse e = sender as Ellipse;
HolePattern hp = e.Tag as HolePattern;
...
}
So you probably already read my reply where I said I had it working. And it does work perfectly, (except that it requires great precision with the mouse), but I want to ask this: is it really smart to add an event handler to EVERY ellipse that gets added to a canvas? Now I don't know what kind of memory bog that could be, or maybe it is a piece of cake for WPF and Windows to handle.
In a practical case, I guess there would be not more that 30-50 holes even on a screen that had multiple patterns, but still; FIFTY event handlers? It just seems scary. And actually, each "Hole" is visually represented by two concentric circles and a text label (see the screenshow here: http://twitpic.com/1f2ci/full ), and I know the user would expect to be able to click on any one of those elements to select a hole. That means an event handler on 3 elements for every hole. Now we could be talking about 100 or more event handlers.
It seems like there should be a solution where you could have just one event handler on the Canvas and read the element reference under the mouse, then work off of that to get the .Tag property of that elment, and so on.
I thought I'd post my final and more refined solution in case it helps anyone else.
void canvas1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
int ClickMargin = 2;// Adjust here as desired. Span is in both directions of selected point.
var ClickMarginPointList = new Collection<Point>();
Point ClickedPoint = e.GetPosition(canvas1);
Point ClickMarginPoint=new Point();
for (int x = -1 * ClickMargin; x <= ClickMargin; x++)
{
for (int y = -1 * ClickMargin; y <= ClickMargin; y++)
{
ClickMarginPoint.X = ClickedPoint.X + x;
ClickMarginPoint.Y = ClickedPoint.Y + y;
ClickMarginPointList.Add(ClickMarginPoint);
}
}
foreach (Point p in ClickMarginPointList)
{
HitTestResult SelectedCanvasItem = System.Windows.Media.VisualTreeHelper.HitTest(canvas1, p);
if (SelectedCanvasItem.VisualHit.GetType().BaseType == typeof(Shape))
{
var SelectedShapeTag = SelectedCanvasItem.VisualHit.GetValue(Shape.TagProperty);
if (SelectedShapeTag!=null && SelectedShapeTag.GetType().BaseType == typeof(Hole))
{
Hole SelectedHole = (Hole)SelectedShapeTag;
SetActivePattern(SelectedHole.ParentPattern);
SelectedHole.ParentPattern.CurrentHole = SelectedHole;
return; //Get out, we're done.
}
}
}
}

Resources