I recently tried out a Free-To-Play MMORPG game called AIKA
While trying the game out, I found a very nice PIN Pad that allows for you to protect your characters. I have a screen shot attached:
It allows for a user to enter (through mouse-only) a four digit numeric code. A cool thing is that the numeric digits around the InputBox are always shuffled every time this screen comes on.
My purpose behind this question is: Is there someone out there who has created something like this before? I'm interested in using this in my WinForms and WPF application.
Note I have done a lot of searching but I guess I really don't know if I'm using the correct keywords. In case, such a control doesn't exist, and someone is willing to make one, kindly drop a line here. I'm very interested.
If it pops up on the screen, it's really just a form with buttons on it. You can create a simple randomization routine to populate the button numbers.
private void Form1_Load(object sender, EventArgs e)
{
int[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Random rnd = new Random();
for (int i = array.Length - 1; i > 0; i--)
{
int j = rnd.Next(i);
int k = array[j];
array[j] = array[i - 1];
array[i - 1] = k;
}
for (int i = 0; i < array.Length; i++)
{
panel1.Controls["Button" + (i + 1).ToString()].Text = array[i].ToString();
}
Related
I am trying to draw multiple lines on a winforms panel using it's graphics object in paint event. I am actually drawing a number of lines joining given points. So, first of all I did this,
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLines(new Pen(new SolidBrush(Color.Crimson), 3), PointFs.ToArray());
float width = 10;
float height = 10;
var circleBrush = new SolidBrush(Color.Crimson);
foreach (var point in PointFs)
{
float rectangleX = point.X - width / 2;
float rectangleY = point.Y - height / 2;
var r = new RectangleF(rectangleX, rectangleY, width, height);
e.Graphics.FillEllipse(circleBrush, r);
}
}
Which produces a result like the image below,
As you can see lines are drawn with having a little bit of extension at sharp turns, which is not expected. So, I changed the drawlines code to,
var pen = new Pen(new SolidBrush(Color.Crimson), 3);
for (int i = 1; i < PointFs.Count; i++)
{
e.Graphics.DrawLine(pen, PointFs[i - 1], PointFs[i]);
}
And now the drawing works fine.
Can anyone tell the difference between the two approaches?
I have just had the same problem (stumbled upon this question during my research), but I have now found the solution.
The problem is caused by the LineJoin property on the Pen used. This DevX page explains the different LineJoin types (see Figure 1 for illustrations). It seems that Miter is the default type, and that causes the "overshoot" when you have sharp angles.
I solved my problem by setting the LineJoin property to Bevel:
var pen = new Pen(new SolidBrush(Color.Crimson), 3);
pen.LineJoin = Drawing2D.LineJoin.Bevel;
Now DrawLines no longer overshoot the points.
I have created a from which takes the user input and compares it to 100 randomly generated numbers. Once they click the guess button the result is shown. To aid the user I am supposed to give them a hint when they hover the mouse over a label, the hint should be either 3 higher or 3 lower than the actual number. I cannot figure out how to get the random number generated when the user hits the guess button to equal the number as the hover event. Sorry for all the code, any help would be appreciated.
Here is how I am creating my random number:
public partial class Form1 : Form
{
int[] rndArray = new int[100];
public void getNumbers()
{
Random random = new Random();
for (int x = 0; x < rndArray.Length; x++)
{
rndArray[x] = random.Next(1, 100);
}
}
Here is the guss button event:
private void Guess_Click(object sender, EventArgs e)
{
getNumbers();
for (int x = 0; x < rndArray.Length; x++)
{
if (Convert.ToInt32(textBox1.Text) == rndArray[x])
{
result.Text = "You Win!";
correct.Text = "Correct: ";
}
else
{
result.Text = "Sorry - you loose; the number is: " + rndArray[x];
incorrect.Text = "Incorrect: ";
}
}
And the mouse hover event:
private void mouseHere_MouseHover(object sender, EventArgs e)
{
getNumbers();
for (int x = 0; x < rndArray.Length; x++)
hint.Text = "It's not " + (rndArray[x] +- 3);
}
I see three possible issues.
First, at the beginning of your mouse hover and guess click functions, you call GetNumbers, which generates 100 numbers and assigns them to the array. You should only generate them once per game. I would recommend calling it once at the beginning of each game (perhaps in the FormShown or FormLoad event handlers), and not calling it again until the next game begins. Otherwise, the numbers will keep changing.
Second, inside your mouse hover function, you have a for loop that assigns the text to "hint" 100 times. The first 99 hints will probably not be accurate, as the end of your mouse hover event will display the hint for the very last number. You will need to identify which array element to give a hint for, and assign it to the appropriate hint display.
Third, the +- operator is not an actual operator in C#. If this is actually compiling and running, it's probably interpreting it in a manner such as hint.Text = "It's not " + (rndArray[x] + (-3); I would recommend using a Random object to generate a number, then using whether it's odd or even to determine whether to add or subtract. Just make sure you don't reassign the array.
EDIT: With regards to figuring out whether to add or subtract from the hint, make sure you don't randomly generate a hint each time you hover; do it once for that number and store the hint. Otherwise, hovering over it a few times will show both possible hints.
I have a method that is gobbling up 25% of my cpu time. I call this method about 27,000 times per second. (Yup, lots of calls since it's updating frequently). I am wondering if anybody knows a faster way to detect if 2 polygons overlap. Basically, I have to check the moving objects on the screen against stationary objects on the screen. I am using PathGeometry and the two calls below are using up 25% of the cpu time used by my program. The PointCollection objects I am passing just contain 4 points representing 4 corners of a polygon. They may not create a rectangular area, but all the points are connected. I guess a trapazoid would be the shape.
These methods are short and were very easy to implement, but I think I might want to opt for a more complicated solution if I can have it run more quickly than the code below. Any ideas?
public static bool PointCollectionsOverlap(PointCollection area1, PointCollection area2)
{
PathGeometry pathGeometry1 = GetPathGeometry(area1);
PathGeometry pathGeometry2 = GetPathGeometry(area2);
return pathGeometry1.FillContainsWithDetail(pathGeometry2) != IntersectionDetail.Empty;
}
public static PathGeometry GetPathGeometry(PointCollection polygonCorners)
{
List<PathSegment> pathSegments = new List<PathSegment>
{ new PolyLineSegment(polygonCorners, true) };
PathGeometry pathGeometry = new PathGeometry();
pathGeometry.Figures.Add(new PathFigure(polygonCorners[0], pathSegments, true));
return pathGeometry;
}
Ok, after lots of research and finding many partial answers, but none that fully answered the question, I have found a faster way and it is actually about 4.6 times faster than the old way.
I created a special test app to test the speed this. You can find the test app here. If you download it, you can see a checkbox at the top of the app. Check and uncheck it to switch back and forth between the old way and the new way. The app generates a bunch of random polygons and the borders of the polygons change to white when they intersect another polygon. The numbers to the left of the 'Redraw' button are to allow you to enter the Number of Polygons, Max Length of a side, and Max offset from square (to make them less square and more odd shaped). Push 'Refresh' to clear and regenerate new polygons with the settings you've entered.
Anyway, here is the code for the two different implementations. You pass in a collection of the points that make up each polygon. The old way uses less code, but is 4.6 times slower than the new way.
Oh, one quick note. The new way has a couple calls to 'PointIsInsidePolygon'. These were necessary because without it, the method returned false when one polygon was entirely contained within a different polygon. But the PointIsInsidePolygon method fixes that problem.
Hope this all helps somebody else out with polygon intercepts and overlaps.
Old Way (4.6 times slower. YES REALLY 4.6 TIMES slower):
public static bool PointCollectionsOverlap_Slow(PointCollection area1, PointCollection area2)
{
PathGeometry pathGeometry1 = GetPathGeometry(area1);
PathGeometry pathGeometry2 = GetPathGeometry(area2);
bool result = pathGeometry1.FillContainsWithDetail(pathGeometry2) != IntersectionDetail.Empty;
return result;
}
public static PathGeometry GetPathGeometry(PointCollection polygonCorners)
{
List<PathSegment> pathSegments = new List<PathSegment> { new PolyLineSegment(polygonCorners, true) };
PathGeometry pathGeometry = new PathGeometry();
pathGeometry.Figures.Add(new PathFigure(polygonCorners[0], pathSegments, true));
return pathGeometry;
}
New Way (4.6 times faster. YES REALLY 4.6 TIMES faster):
public static bool PointCollectionsOverlap_Fast(PointCollection area1, PointCollection area2)
{
for (int i = 0; i < area1.Count; i++)
{
for (int j = 0; j < area2.Count; j++)
{
if (lineSegmentsIntersect(area1[i], area1[(i + 1) % area1.Count], area2[j], area2[(j + 1) % area2.Count]))
{
return true;
}
}
}
if (PointCollectionContainsPoint(area1, area2[0]) ||
PointCollectionContainsPoint(area2, area1[0]))
{
return true;
}
return false;
}
public static bool PointCollectionContainsPoint(PointCollection area, Point point)
{
Point start = new Point(-100, -100);
int intersections = 0;
for (int i = 0; i < area.Count; i++)
{
if (lineSegmentsIntersect(area[i], area[(i + 1) % area.Count], start, point))
{
intersections++;
}
}
return (intersections % 2) == 1;
}
private static double determinant(Vector vector1, Vector vector2)
{
return vector1.X * vector2.Y - vector1.Y * vector2.X;
}
private static bool lineSegmentsIntersect(Point _segment1_Start, Point _segment1_End, Point _segment2_Start, Point _segment2_End)
{
double det = determinant(_segment1_End - _segment1_Start, _segment2_Start - _segment2_End);
double t = determinant(_segment2_Start - _segment1_Start, _segment2_Start - _segment2_End) / det;
double u = determinant(_segment1_End - _segment1_Start, _segment2_Start - _segment1_Start) / det;
return (t >= 0) && (u >= 0) && (t <= 1) && (u <= 1);
}
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.
I am investigating a GDI resource leak in a large application. In order to further my understanding of how these problems occur, I have created a very small application which I have deliberately made 'leaky'. Here is a simple user control which should result in the creation of 100 Pen objects:
public partial class TestControl : UserControl
{
private List pens = new List();
public TestControl()
{
InitializeComponent();
for (int i = 0; i < 100; i++)
{
pens.Add(new Pen(new SolidBrush(Color.FromArgb(255, i * 2, i * 2, 255 - i * 2))));
}
this.Paint += new PaintEventHandler(TestControl_Paint);
}
void TestControl_Paint(object sender, PaintEventArgs e)
{
for (int i = 0; i < 100; i++)
{
e.Graphics.DrawLine(pens[i], 0, i, Width, i);
}
}
}
However, when I create an instance of my object and add it to a form, looking at my application with TaskManager I currently see ~37 GDI objects. If I repeatedly add new TestObject user controls to my form, I still only see ~37 GDI objects.
What is going on here! I thought that the constructor for System.Drawing.Pen would use the GDI+ API to create a new Pen, thus using a new GDI object.
I must be going nuts here. If I cannot write a simple test application that creates GDI objects, how can I create one which leaks them!
Any help would be much appreciated.
Best Regards, Colin E.
Does the GDI+ use GDI handles? I'm not sure, though I read somewhere that there is a .NET System.Drawing implementation that relies on bare GDI.
However, maybe you can try to find your leaks with a profiler like AQTime instead.
How are you sure your large app is leaking GDI handles? Is the count in Task Manager large? If so, are you always using GDI+, or also GDI? Does your test app GDI handle count increase if you create your control multiple times?
You are not really leaking resources in your sample. Remove this code from your Load event:
for (int i = 0; i < 100; i++)
{
pens.Add(new Pen(new SolidBrush(Color.FromArgb(255, i * 2, i * 2, 255 - i * 2))));
}
Your Paint event handler should look like this:
void TestControl_Paint(object sender, PaintEventArgs e)
{
for (int i = 0; i < 100; i++)
{
e.Graphics.DrawLine(new Pen(new SolidBrush(Color.FromArgb(255, i * 2, i * 2, 255 - i * 2))), 0, i, Width, i);
}
}
Now you will be leaking in every paint call. Start minimizing/restoring your Form and see GDI objects sky rocket...
Hope this helps.
If you want to leak a GDI object from .NET, then just create a GDI object and not release it:
[DllImport("gdi32.dll", EntryPoint="CreatePen", CharSet=CharSet.Auto, SetLastError=true, ExactSpelling=true)]
private static extern IntPtr CreatePen(int fnStyle, int nWidth, int crColor);
CreatePen(0, 0, 0); //(PS_SOLID, 0=1px wide, 0=black)
Blingo blango, you're leaking GDI pens.
i don't know why you want to create GDI leaks. But your question asked how to create GDI leaks from a WinForm - so there it is.
I think the compiler only use one handle.
If I in delphi create a lot of fonts I just take memory
but if I use the WinAPI CreateFont() I take GDI objects.
Create two buttons on a form. Inside each button, add the following code. In one button, comment out the Dispose method.
Form _test = null;
for (int i = 0; i < 20; i++)
{
_test = new Form();
_test.Visible = false;
_test.Show();
_test.Hide();
_test.Dispose();
}
The button with the Dispose commented out shows you the leak. The other shows that Dispose causes the User and GDI handles to stay the same.
This is probably the best page I've found that explains it.
I think the following blog may have answered this question:
Using GDI Objects the Right Way
The GDI objects that aren't explicitly disposed should be implicitly disposed by their finalizes.
(Bob Powell has also mentioned this issue in GDI+ FAQ )
But I doubt if the CLR garbage collector can remove GDI resources so quickly that we can't even see memory usage changes from TaskManager. Maybe current GDI+ implementation doesn't use GDI.
I've tried the following piece of code to generate more GDI objects. But I still couldn't see any changes of the number of GDI handles.
void Form1_Paint(object sender, PaintEventArgs e)
{
Random r = new Random();
while (true)
{
for (int i = 0; i < 100; i++)
{
e.Graphics.DrawLine(
new Pen(new SolidBrush(Color.FromArgb(r.Next()))), 0, i, Width, i);
}
}
}