I'm currently working on a Snake game that can solve itself, but when I activate it, usually after 30~ successful hits, my application crashes with the aforementioned exception either in System.drawing.dll or in System.Windows.Forms.dll.
The problem usually occurs in the command "Application.DoEvents()", but it has occured in several other places too.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Threading;
using System.IO;
namespace Snake
{
enum Directions
{
Right = 1,
Left = -1,
Up = 2,
Down = -2,
NoDirection = 0
}
public partial class GameForm : Form
{
#region Data Members
SnakeGame gmGame;
Point pCurrFood;
Directions dirFirstDirection;
Directions dirSecondDirection;
Directions dirHelpDirection;
Color DEFAULT_COLOUR = Color.White;
const int SEGMENT_HEIGHT = 10;
const int SEGMENT_WIDTH = 10;
#endregion
#region Ctor
public GameForm()
{
InitializeComponent();
this.gmGame = new SnakeGame();
this.dirFirstDirection = Directions.NoDirection;
this.dirSecondDirection = Directions.NoDirection;
}
#endregion
#region Other Methods
private void PaintSegment(Graphics gGraphics, Point pnPoint, Color cColour)
{
Pen Pen = new Pen(cColour);
Rectangle Rectangle = new Rectangle(pnPoint.X,
pnPoint.Y,
SEGMENT_HEIGHT,
SEGMENT_WIDTH);
gGraphics.DrawRectangle(Pen, Rectangle);
Brush Brush = new SolidBrush(cColour);
gGraphics.FillRectangle(Brush, Rectangle);
}
private void PlaceNewFood()
{
Random rRand = new Random();
int nHeight = rRand.Next(this.panel1.Size.Height);
int nWidth = rRand.Next(this.panel1.Size.Width);
while ((nHeight % 10 != 0) || (nWidth % 10 != 0))
{
nHeight = rRand.Next(this.panel1.Size.Height - 10);
nWidth = rRand.Next(this.panel1.Size.Width - 10);
while (this.gmGame.SnakeQueue.Contains(new Point(nWidth, nHeight)))
{
nHeight = rRand.Next(this.panel1.Size.Height);
nWidth = rRand.Next(this.panel1.Size.Width);
}
}
this.pCurrFood = new Point(nWidth, nHeight);
this.PaintSegment(this.panel1.CreateGraphics(), this.pCurrFood, Color.Red);
}
private void SelfSolve()
{
this.dirFirstDirection = (Directions)(Math.Sign(this.gmGame.SnakeHead.Y -
this.pCurrFood.Y) * 2);
this.dirSecondDirection = (Directions)Math.Sign(this.pCurrFood.X -
this.gmGame.SnakeHead.X);
this.ManageSnake(this.dirFirstDirection, this.dirSecondDirection);
}
private bool WillCollide(Point pnPointToCheck)
{
return ((pnPointToCheck.X > this.panel1.Size.Width) ||
(pnPointToCheck.Y > this.panel1.Size.Height) ||
(pnPointToCheck.X * pnPointToCheck.Y < 0) ||
(this.gmGame.SnakeQueue.Contains(pnPointToCheck)));
}
private void ManageSnake(Directions dirFirstSnakeDirection,
Directions dirSecondSnakeDirection)
{
Point pnNewHead = this.gmGame.SnakeHead;
switch (dirFirstSnakeDirection)
{
case (Directions.Down):
{
if (this.WillCollide(new Point(pnNewHead.X, pnNewHead.Y + SEGMENT_HEIGHT)))
{
this.ManageSnake(Directions.NoDirection, dirSecondSnakeDirection);
}
else
{
pnNewHead.Y += SEGMENT_HEIGHT;
dirHelpDirection = Directions.Down;
}
break;
}
case (Directions.Up):
{
if (this.WillCollide(new Point(pnNewHead.X, pnNewHead.Y - SEGMENT_HEIGHT)))
{
this.ManageSnake(Directions.NoDirection, dirSecondSnakeDirection);
}
else
{
pnNewHead.Y -= SEGMENT_HEIGHT;
dirHelpDirection = Directions.Up;
}
break;
}
case (Directions.NoDirection):
{
switch (dirSecondSnakeDirection)
{
case (Directions.Right):
{
if (this.WillCollide(new Point(pnNewHead.X + SEGMENT_WIDTH, pnNewHead.Y)))
{
this.ManageSnake(this.dirHelpDirection, dirSecondSnakeDirection);
}
else
{
pnNewHead.X += SEGMENT_WIDTH;
}
break;
}
case (Directions.Left):
{
if (this.WillCollide(new Point(pnNewHead.X - SEGMENT_WIDTH, pnNewHead.Y)))
{
this.ManageSnake(this.dirHelpDirection, dirSecondSnakeDirection);
}
else
{
pnNewHead.X -= SEGMENT_WIDTH;
}
break;
}
}
break;
}
}
this.gmGame.AddSegment(pnNewHead);
if (this.gmGame.SnakeHead.Equals(this.pCurrFood))
{
this.lblScoreNum.Text = (int.Parse(this.lblScoreNum.Text) + 1).ToString();
this.PlaceNewFood();
}
else
{
this.PaintSegment(this.panel1.CreateGraphics(),
(Point)this.gmGame.SnakeQueue.Peek(),
DEFAULT_COLOUR);
this.gmGame.RemoveSegment();
}
this.PaintSegment(this.panel1.CreateGraphics(),
this.gmGame.SnakeHead,
Color.Green);
Thread.Sleep(5);
Application.DoEvents();
this.SelfSolve();
}
#endregion
#region Events
private void GameForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
this.PlaceNewFood();
this.SelfSolve();
}
else if (e.KeyCode == Keys.Escape)
{
this.Close();
}
else if (e.KeyCode == Keys.Space)
{
MessageBox.Show("Frozen, press OK to continue");
}
}
private void GameForm_ClientSizeChanged(object sender, EventArgs e)
{
this.PaintSegment(this.panel1.CreateGraphics(), new Point(210, 250), Color.Green);
this.PaintSegment(this.panel1.CreateGraphics(), new Point(220, 250), Color.Green);
this.PaintSegment(this.panel1.CreateGraphics(), new Point(230, 250), Color.Green);
this.PaintSegment(this.panel1.CreateGraphics(), new Point(240, 250), Color.Green);
this.PaintSegment(this.panel1.CreateGraphics(), new Point(250, 250), Color.Green);
}
#endregion
}
}
I know it's a lot of code, but since I'm not sure where's the root of the problem, I had to copy all of it.
I'd greatly appreciate it if you could point me in the right direction.
Thanks in advance :)
P.S. I know that the algorithm has flaws, I'll get to that later. Right now my main concern is solving the crash.
This is because you keep on going recursive in your method. e.g.:
Thread.Sleep(5);
Application.DoEvents();
this.SelfSolve();
Your method will basically never end.
You should use a timer and within that timer, call SelfSolve() This should solve your problem.
When using a timer you dont have to call DoEvents yourself since a winforms timer anyways posts a call to your method as a message and the message loop will handle the invocation and other messages.
SelfSolve should not call ManageSnake directly, but rather schedule its run for some later moment. Otherwise you get infinite recursion SelfSolve -> ManageSnake -> SelfSolve etc.
Related
In paint event because i want to be able to control the dots size colors and more properties.
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
public partial class LoadingLabel : UserControl
{
public LoadingLabel()
{
InitializeComponent();
}
private void LoadingLabel_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.FillEllipse(Brushes.Red, 1, 1, 20, 20);
Thread.Sleep(1);
e.Graphics.FillEllipse(Brushes.Red, 1, 1, 0, 0);
Thread.Sleep(1);
}
}
I tried first to make a simple dot that is disappearing after some time and then show again but it's not working i see a red still dot(point).
later when this will work i want to make 3 dots animating like a loading animation.
This is what I've tried:
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
public partial class LoadingLabel : UserControl
{
private bool animate = false;
public LoadingLabel()
{
InitializeComponent();
timer1.Enabled = true;
}
private void LoadingLabel_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
if (animate == false)
{
e.Graphics.FillEllipse(Brushes.Red, 1, 1, 20, 20);
}
else
{
e.Graphics.FillEllipse(Brushes.Red, 5, 1, 20, 20);
}
}
int count = 0;
private void timer1_Tick(object sender, EventArgs e)
{
count++;
if(count == 10 && animate == false)
{
animate = true;
}
if(count == 20 && animate)
{
animate = false;
count = 0;
}
this.Invalidate();
}
}
the result is the first point draw then the second point draw but the first one is gone:
it looks like the point is moving to the right and back to the left.
but i want a loading effect with 3 points. and not moving point.
This is working with 3 points but it looks too complicated for 3 points. and if i want 100 points?
maybe i should use a loop inside the paint event ?
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
public partial class LoadingLabel : UserControl
{
private int numofpoints = 0;
public LoadingLabel()
{
InitializeComponent();
timer1.Enabled = true;
}
private void LoadingLabel_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
if(numofpoints == 0)
{
e.Graphics.FillEllipse(Brushes.Red, 1, 1, 20, 20);
}
if(numofpoints == 1)
{
e.Graphics.FillEllipse(Brushes.Red, 5, 1, 20, 20);
}
if(numofpoints == 2)
{
e.Graphics.FillEllipse(Brushes.Red, 10, 1, 20, 20);
}
}
int count = 0;
private void timer1_Tick(object sender, EventArgs e)
{
count++;
if(count == 10)
{
numofpoints = 0;
}
if(count == 20)
{
numofpoints = 1;
}
if(count == 30)
{
numofpoints = 2;
count = 0;
}
this.Invalidate();
}
}
Another update of what I've tried:
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
public partial class LoadingLabel : UserControl
{
private List<PointF> points = new List<PointF>();
public LoadingLabel()
{
InitializeComponent();
points.Add(new PointF(0, 0));
timer1.Enabled = true;
}
private void LoadingLabel_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
for (int i = 0; i < points.Count; i++)
{
e.Graphics.FillEllipse(Brushes.Red, points[i].X, points[i].Y, 20, 20);
}
}
int count = 0;
private void timer1_Tick(object sender, EventArgs e)
{
count++;
if (count < 3)
{
points.Add(new PointF(count * 20, 0));
//points = new List<PointF>();
}
//this.Invalidate();
}
}
If i will make the instance in the tick event it will not draw anything. if i will use the Invalidate line it will make the points to be like blinking.
what i want is to create a loading effect animation.
the result as the code now is still 3 points, and i want to animate them like in the link.
Something like this:
Since, based on the image you have posted, you want to animate a series of Dots, where only the active one changes color, your UserControl can define Properties that allow to specify the number of Dots, the Color of a Dot and the Color of the active Dot.
A Timer can be used to change the current active Dot, so the paint procedure knows when to change the color of one of the Dots.
The UserControl is automatically resized when the number of Dots specified changes.
Also when the UserControl is first created, it sets its MinimumSize, so the Dots are always visible.
You can expand on this template, adding more features.
Note these lines in the Constructor of the UserControl:
components = new Container();
dotsTimer = new Timer(components) { ... };
This instructs the Timer Component to add itself to the Components of the Parent container, so when the Parent is disposed, the Timer is also disposed and its event handler(s) removed.
Setting DoubleBuffered = true; avoids flickering when the Dots are drawn.
Call the Start() method to start the animation and the Stop() method to, well, stop it.
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
public partial class LoadingLabel : UserControl {
private int m_NumberOfDots = 5;
private Color m_DotColor = Color.Cyan;
private Color m_DotActiveColor = Color.Blue;
private float dotSize = 20.0f;
private float dotSpacing = 20.0f;
private int currentDot = 0;
private Timer dotsTimer = null;
public LoadingLabel()
{
InitializeComponent();
components = new Container();
dotsTimer = new Timer(components) { Interval = 200 };
dotsTimer.Tick += DotsTimer_Tick;
DoubleBuffered = true;
Padding = new Padding(5);
}
[DefaultValue(5)]
public int NumberOfDots {
get => m_NumberOfDots;
set {
value = Math.Max(3, Math.Min(value, 7));
if (m_NumberOfDots != value) {
m_NumberOfDots = value;
bool running = dotsTimer.Enabled;
Stop();
SetMinSize();
if (running) Start();
}
}
}
[DefaultValue(typeof(Color), "Cyan")]
public Color DotColor {
get => m_DotColor;
set {
m_DotColor = value;
Invalidate();
}
}
[DefaultValue(typeof(Color), "Blue")]
public Color DotActiveColor {
get => m_DotActiveColor;
set {
m_DotActiveColor = value;
Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e) {
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
for (int dot = 0; dot < m_NumberOfDots; dot++) {
var color = dot == currentDot ? DotActiveColor : DotColor;
var pos = Padding.Left + (dotSize + dotSpacing) * dot;
using (var brush = new SolidBrush(color)) {
e.Graphics.FillEllipse(brush, pos, Padding.Top, dotSize, dotSize);
}
}
base.OnPaint(e);
}
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
SetMinSize();
}
protected override void OnHandleDestroyed(EventArgs e) {
Stop();
base.OnHandleDestroyed(e);
}
private void DotsTimer_Tick(object sender, EventArgs e) {
currentDot += 1;
currentDot %= m_NumberOfDots;
Invalidate();
}
public void Start() => dotsTimer.Start();
public void Stop() {
dotsTimer.Stop();
currentDot = 0;
Invalidate();
}
private void SetMinSize() {
var width = Padding.Left + Padding.Right +
(dotSize * m_NumberOfDots) + (dotSpacing * (m_NumberOfDots - 1)) + 1;
var height = Padding.Top + Padding.Bottom + dotSize + 1;
MinimumSize = new Size((int)width, (int)height);
Size = MinimumSize;
}
}
This is how it works:
On demand, this is the PasteBin of the custom ComboBox Control used to select a Color.
A single call to the Paint method/event should draw the control as it is supposed to look at that instant. If you wish to add animation, you should make the control redraw itself repeatedly and use some internal state to keep track of the animation.
I am studying C# Programming and Kinect sensors programming (I am quite a
newbie in both C# language and Kinect). I am trying to use Microsoft Visual C# 2010 Express to write applications using sensors of Xtion Pro Live to control robots. In my main form, there are 2 picturebox objects, 2 button object, 3 label and 3 textbox objects. One of the two picturebox objects (pictureBox1) is to display the RGB camera. The other one pictureBox2) is to simulate the hand positions in 2D (x and y coordinates) graphics. One of the two buttons (button1) is to initialize Xtion Pro Live and to show RGB camera on picturebox1, and to simulate hand positions on picturebox2. The other one (button2) is to exit the program. The three labels, label1, label2, label3, and the three textboxes, textbox1, textbox2, textbox3 are used to show 3 coordinates of the hand.
This is my code in Form1.cs:
using OpenNI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace HandTracking
{
public partial class Form1 : Form
{
public const string path = #"C:/Vu/Kinect/Data/SamplesConfig.xml";
public bool run;
public Thread thread;
public Bitmap bitmap;
public Context context;
public ScriptNode node;
public ImageGenerator image;
public DepthGenerator depth;
public GestureGenerator gesture;
public HandsGenerator hand;
public Queue<Point3D> handpoint = new Queue<Point3D>();
public const int maxpoint = 30;
enum GestureStatus
{
Unrecognized, Progress, Recognized
}
private GestureStatus gesstatus = GestureStatus.Unrecognized;
enum HandsStatus
{
Untracked, Create, Update
}
private HandsStatus handstatus = HandsStatus.Untracked;
public Pen pen = new Pen(Color.Red, 5);
public Brush brush = new SolidBrush(Color.Magenta);
public Font font = new Font("Times New Roman", 20);
public PointF point = new PointF(0, 0);
public Form1()
{
InitializeComponent();
this.pictureBox1.BackColor = Color.Black;
this.pictureBox2.BackColor = Color.White;
this.button1.Enabled = true;
}
public void button1_Click(object sender, EventArgs e)
{
this.button1.Enabled = false;
try
{
context = Context.CreateFromXmlFile(path, out node);
image = context.FindExistingNode(NodeType.Image) as ImageGenerator;
if (image == null)
throw new Exception(context.GlobalErrorState);
depth = context.FindExistingNode(NodeType.Depth) as DepthGenerator;
if (depth == null)
throw new Exception(context.GlobalErrorState);
depth.AlternativeViewpointCapability.SetViewpoint(image);
gesture = context.FindExistingNode(NodeType.Gesture) as GestureGenerator;
if (gesture == null)
throw new Exception(context.GlobalErrorState);
gesture.AddGesture("RaiseHand");
gesture.GestureRecognized += new EventHandler<GestureRecognizedEventArgs>(GestureRecognized);
gesture.GestureProgress += new EventHandler<GestureProgressEventArgs> (GestureProgress);
hand = context.FindExistingNode(NodeType.Hands) as HandsGenerator;
if (hand == null)
throw new Exception(context.GlobalErrorState);
hand.HandCreate += new EventHandler<HandCreateEventArgs>(HandCreate);
hand.HandUpdate += new EventHandler<HandUpdateEventArgs>(HandUpdate);
context.StartGeneratingAll();
MapOutputMode map = image.MapOutputMode;
bitmap = new Bitmap((int)map.XRes, (int)map.YRes, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
run = true;
thread = new Thread(CallThread);
thread.Start();
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
public void GestureRecognized(object sender, GestureRecognizedEventArgs e)
{
gesstatus = GestureStatus.Recognized;
hand.StartTracking(e.EndPosition);
}
public void GestureProgress(object sender, GestureProgressEventArgs e)
{
gesstatus = GestureStatus.Progress;
}
public void HandCreate(object sender, HandCreateEventArgs e)
{
handstatus = HandsStatus.Create;
}
public void HandUpdate(object sender, HandUpdateEventArgs e)
{
handstatus = HandsStatus.Update;
handpoint.Enqueue(e.Position);
}
public void button2_Click(object sender, EventArgs e)
{
DialogResult result = MessageBox.Show("Do you want to quit?", "Confirm", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
if (result == DialogResult.OK)
{
try
{
run = false;
if (thread != null)
thread.Join();
this.Close();
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
}
public void CallThread()
{
try
{
while (run)
{
Data();
pictureBox1.Invalidate();
pictureBox2.Invalidate();
}
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
public unsafe void Data()
{
context.WaitAndUpdateAll();
ImageMetaData imd = image.GetMetaData();
lock (this)
{
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
BitmapData data = bitmap.LockBits(rect, ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
byte* dstp = (byte*)data.Scan0.ToPointer();
byte* imstp = (byte*)image.ImageMapPtr.ToPointer();
for (int i = 0; i < imd.DataSize; i += 3, dstp += 3, imstp += 3)
{
dstp[0] = imstp[2];
dstp[1] = imstp[1];
dstp[2] = imstp[0];
}
bitmap.UnlockBits(data);
if (handpoint.Count != 0)
{
Point3D start = depth.ConvertRealWorldToProjective(handpoint.Peek());
foreach (Point3D hpoint in handpoint)
{
Point3D pt = depth.ConvertRealWorldToProjective(hpoint);
HandPosition(start);
start = pt;
}
}
string mess = "Gesture: RaiseHand" + " ,Status:" + gesstatus.ToString() + "\n" + "Hand: " + handstatus.ToString();
PicDraw(bitmap, mess);
}
}
public void HandPosition(Point3D pt)
{
try
{
float a,b,c;
string handx, handy, handz;
a=pt.X;
b=pt.Y;
c=pt.Z;
handx = a.ToString();
handy = b.ToString();
handz = c.ToString();
Graphics g = pictureBox2.CreateGraphics();
g.FillEllipse(brush, a - 5, b - 5, 20, 20);
textBox1.Text = handx;
textBox2.Text = handy;
textBox3.Text = handz;
g.Dispose();
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
public void PicDraw(Bitmap bmap, string me)
{
try
{
Graphics g;
pictureBox1.Image = bmap;
g = Graphics.FromImage(pictureBox1.Image);
g.DrawString(me, font, brush, point);
g.Dispose();
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
}
}
And this is my code in Program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace HandTracking
{
static class Program
{
........
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 f1 = new Form1();
f1.Text = "Hand Tracking";
f1.StartPosition = FormStartPosition.CenterScreen;
Application.Run(f1);
}
}
}
When I compile the program many times, each time different errors are thrown: InvalidOperationException not handled; Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on; Object is currently in use elsewhere.
I don't know whether the way I pass parameters at: HandPosition(start) and PicDraw(bitmap, mess) were correct. Any problem will come out if I use HandPosition(start) to control a robot? Can anybody show me my mistakes and help me correct the progam?
The problem is that you are trying to access a WinForms control on a thread other than the UI thread. It is being done from the thread you are creating with Thread.Start.
A much better technique for Windows Forms is to use the BackgroundWorker approach (if you are using .NET 4, Task Parallel Library is very nice). With BackgroundWorker, you send the thread off to do some work, and it gives the UI thread updates, sending back any objects of your choice. Since you are newer to C#, BackgroundWorker is the right choice because it is simple to use, and there is tons of documentation on it if you get stuck.
On the UI thread, you just take those updates, and then update your WinForms controls from the UI thread. Problem fixed.
To learn more about BackgroundWorker, Google it, or you can start here:
http://www.codeproject.com/Articles/99143/BackgroundWorker-Class-Sample-for-Beginners
I have a flag in the Form1 top level: addFrame wich is set to false in the constructor.
Then in the picnt event i check if its false let me draw if its true also let me draw. The problem here is that i want to be able to draw when im running the program first time !
But when im moving the trackBar to the right i dont want it to draw anything .
private void pictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
moveCounter++;
label6.Text = moveCounter.ToString();
if (addFrame == false)
{
WireObjectGraphics.Draw(wireObject1, g);
}
else
{
addFrame = false;
WireObjectGraphics.Draw(wireObject1, g);
}
}
This is the button click event where im clicking to set the addFrame to true:
private void button16_Click(object sender, EventArgs e)
{
wireObjectAnimation1.AddFrame();
addFrame = true;
trackBar1.Select();
}
And the scroll bar event in this case i want to make that if i move the trackBar to the right and there are no any draws already then just show the image in the pictureBox dont draw anything ! But if i move it to the right and there are already draws then do show them.
If i move it to the left allways show the previous draws.
private void trackBar1_Scroll(object sender, EventArgs e)
{
if (addFrame == false)
{
}
else
{
currentFrameIndex = trackBar1.Value - 1;
textBox1.Text = "Frame Number : " + trackBar1.Value;
wireObject1.woc.Set(wireObjectAnimation1.GetFrame(currentFrameIndex));
trackBar1.Minimum = 0;
trackBar1.Maximum = fi.Length - 1;
if (checkBox1.Checked)
{
setpicture(trackBar1.Value);
Graphics g = Graphics.FromImage(pictureBox1.Image);
g.Clear(SystemColors.Control);
pictureBox1.Invalidate();
}
else
{
setpicture(trackBar1.Value);
}
pictureBox1.Refresh();
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;
button4.Enabled = false;
button8.Enabled = false;
SaveFormPicutreBoxToBitMapIncludingDrawings(currentFrameIndex);
return;
}
}
This is the draw function in the WireObjectGraphics class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace AnimationEditor
{
class WireObjectGraphics
{
static Point connectionPointStart;
static Point connectionPointEnd;
static SolidBrush brush;
static Pen p = null;
public WireObjectGraphics()
{
}
public static void Draw(WireObject wo, Graphics graphics)
{
brush = new SolidBrush(Color.Red);
p = new Pen(brush);
Graphics g = graphics;
WireObject wireObject1 = wo;
if (wireObject1 != null)
{
for (int idx = 0; idx < wireObject1.woc.Point_X.Count; ++idx)
{
Point dPoint = new Point((int)wireObject1.woc.Point_X[idx], (int)wireObject1.woc.Point_Y[idx]);
dPoint.X = dPoint.X - 5; // was - 2
dPoint.Y = dPoint.Y - 5; // was - 2
Rectangle rect = new Rectangle(dPoint, new Size(10, 10));
g.FillEllipse(brush, rect);
// bitmapGraphics.FillEllipse(brush, rect);
// g.FillEllipse(brush, rect);
}
for (int i = 0; i < wireObject1._connectionstart.Count; i++)
{
int startIndex = wireObject1._connectionstart[i];
int endIndex = wireObject1._connectionend[i];
connectionPointStart = new Point((int)wireObject1.woc.Point_X[startIndex], (int)wireObject1.woc.Point_Y[startIndex]);
connectionPointEnd = new Point((int)wireObject1.woc.Point_X[endIndex], (int)wireObject1.woc.Point_Y[endIndex]);
p.Width = 2;
g.DrawLine(p, connectionPointStart, connectionPointEnd);
// bitmapGraphics.DrawLine(p, connectionPointStart, connectionPointEnd);
}
}
}
}
}
What i need is that first time running the program to be able to draw !
Then when moving the trackBar to the righ to check if draws already exists show them if not exist show only the image and only when i click the button it will add the draws on the frame im on.
If i move to the left allways show the draws i did in the other frames.
WireObject class:
Constructor:
class WireObject
{
private string an;
private bool fnExt;
public string lockObject;
private int idx;
public WireObjectCoordinates woc;
private List<int> connectionStart = new List<int>();
private List<int> connectionEnd = new List<int>();
private const string version = "01.00";
string wo_name;
public WireObject( string name )
{
wo_name = name;
woc = new WireObjectCoordinates();
fnExt = false;
}
In the wireobject class i have some function like connecting points(pixels) like delete pixels like save and load...
WireObjectCoordinates class is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AnimationEditor
{
class WireObjectCoordinates
{
public List<float> Point_X = new List<float>();
public List<float> Point_Y = new List<float>();
public WireObjectCoordinates()
{
}
public WireObjectCoordinates(WireObjectCoordinates w)
{
Point_X.AddRange(w.Point_X);
Point_Y.AddRange(w.Point_Y);
}
public void Set(WireObjectCoordinates w)
{
if (w == null)
{
}
else
{
for (int i = 0; i < Point_X.Count; i++)
{
Point_X[i] = w.Point_X[i];
Point_Y[i] = w.Point_Y[i];
}
}
}
}
}
The problem is still in Form1 with the flag when to show the pixels i mean when and how to call the paint event like pictureBox1.Refresh(); but oncei t will use the Draw function inside and once it will not. When i run the program let me use the draw function once i moved the trackBar to the right dont use the draw function.
For a windows form control OnPaint is only called when a.) a window overlapping the current control is moved out of the way OR b.) you manually invalidate the control : http://msdn.microsoft.com/en-us/library/1e430ef4.aspx
So OnPaint should be getting called too often.
I have made a bouncing screensaver in C#. When there is only a single monitor to display it works perfectly. However, when I have a dual monitor display the bounds do not work properly. The position of secondary monitor seems to have an effect and there does not seem to be a right bound (secondary screen is on the right side).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace LIUScreensaver
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (args.Length > 0)
{
string firstArg = args[0].ToLower().Trim();
string secondArg = null;
//handle cases where arguments are separated by colon
if (firstArg.Length > 2)
{
secondArg = firstArg.Substring(3).Trim();
firstArg = firstArg.Substring(0, 2);
}
else if (args.Length > 1)
{
secondArg = args[1];
}
if (firstArg == "/c")
{
MessageBox.Show("This screensaver does not allow configuration changes");
}
else if (firstArg == "/p")
{
if (secondArg == null)
{
MessageBox.Show("Sorry, but there was an error.", "Screensaver", MessageBoxButtons.OK,
MessageBoxIcon.Error);
return;
}
IntPtr preview = new IntPtr(long.Parse(secondArg));
Application.Run(new ScreensaverForm(preview));
}
else if (firstArg == "/s")
{
ShowScreenSaver();
Application.Run();
}
else
{
MessageBox.Show("Invalid command line argument. \"" + firstArg + "\" is not a valid ", "Screensaver",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
else
{
MessageBox.Show("There has been an error displaying the screensaver. Please report this issue.");
}
}
public static void ShowScreenSaver()
{
//creates form on each display
int i = 0;
Screen[] screen = Screen.AllScreens;
for (i = 0; i < screen.Length; i++)
{
ScreensaverForm screensaver = new ScreensaverForm(screen[i].Bounds);
screensaver.Show();
}
}
}
}
//Screensaver form
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace LIUScreensaver
{
public partial class ScreensaverForm : Form
{
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern bool GetClientRect(IntPtr hWnd, out Rectangle lpRect);
private Boolean previewMode = false;
private int mouseX = 0, mouseY = 0;
private int imgX = 0, imgY = 0;
private Boolean bot = true, left = true, right = false, top = false;
Point p;
//constructor with no arguments
public ScreensaverForm()
{
InitializeComponent();
}
//constructor with bound arguments
public ScreensaverForm(Rectangle Bounds)
{
InitializeComponent();
this.Bounds = Bounds;
}
//preview constructor
public ScreensaverForm(IntPtr preview)
{
InitializeComponent();
SetParent(this.Handle, preview);
SetWindowLong(this.Handle, -16, new IntPtr(GetWindowLong(this.Handle, -16) | 0x40000000));
Rectangle parentRec;
GetClientRect(preview, out parentRec);
Size = parentRec.Size;
Location = new Point(0, 0);
txtLabel.Font = new System.Drawing.Font("Arial", 6);
previewMode = true;
}
//form load
private void ScreensaverForm_Load(object sender, EventArgs e)
{
Cursor.Hide();
TopMost = true;
System.Drawing.Color background = System.Drawing.ColorTranslator.FromHtml("#002668");
this.BackColor = background;
moveTimer.Interval = 1;
moveTimer.Tick += new EventHandler(moveTimer_Tick);
moveTimer.Start();
}
//
//-----------------------------------------------------------------------------------------------------
//The following code ends the application and exits the screensaver
private void ScreensaverForm_KeyPress(object sender, KeyPressEventArgs e)
{
if (!previewMode)
{
Application.Exit();
}
}
private void ScreensaverForm_MouseMove(object sender, MouseEventArgs e)
{
if (!previewMode)
{
if (mouseX == 0)
{
mouseX = e.X;
mouseY = e.Y;
}
if ((mouseX - e.X) > 5 || (mouseY - e.Y) > 5)
{
Application.Exit();
}
}
}
private void ScreensaverForm_MouseClick(object sender, MouseEventArgs e)
{
if (!previewMode)
{
Application.Exit();
}
}
//
//
//timer to bounce the image across the screen
private void moveTimer_Tick(object sender, System.EventArgs e)
{
// Move text to new location
bounce();
}
//function that moves the image
private void bounce()
{
//Checks boundaries
if (txtLabel.Location.Y + txtLabel.Image.Height - this.Bounds.Bottom>= 0)
{
top = true;
bot = false;
}
if (txtLabel.Location.X + txtLabel.Image.Width - this.Bounds.Right >= 0)
{
right = false;
left = true;
}
if (txtLabel.Location.X <= this.Bounds.Left)
{
right = true;
left = false;
}
if (txtLabel.Location.Y <= this.Bounds.Top)
{
top = false;
bot = true;
}
//moves image
if (bot == true)
{
if (right == true)
{
++imgX;
++imgY;
p.X = imgX;
p.Y = imgY;
txtLabel.Location = p;
}
else if (left == true)
{
--imgX;
++imgY;
p.X = imgX;
p.Y = imgY;
txtLabel.Location = p;
}
}
if (top == true)
{
if (right == true)
{
++imgX;
--imgY;
p.X = imgX;
p.Y = imgY;
txtLabel.Location = p;
}
else if (left == true)
{
--imgX;
--imgY;
p.X = imgX;
p.Y = imgY;
txtLabel.Location = p;
}
}
Invalidate();
}
}
}
The problem is the label's Location is its position relative to the monitor that it's on while the bounds you are comparing it too are an absolute position across all monitors.
So if the bounds of the primary monitor are Top: 0, Bottom: 900, Left: 0, Right: 1600
the bounds of the secondary monitor might be something like Top: 0, Bottom: 900, Left: 1600, Right: 3200. While the Location of the label on the secondary monitor will returning its position relative to the secondary monitor so for example Location.X: 200, Location.Y: 300.
You need to change the bounce Method to make the comparsion use either only absolute coordinates or only relative coordinates.
Here is the comparison code modified to use relative position of the label on the monitor;
if (txtLabel.Location.Y + txtLabel.Image.Height - (this.Bounds.Bottom - this.Bounds.Top) >= 0)
{
top = true;
bot = false;
}
if (txtLabel.Location.X + txtLabel.Image.Width - (this.Bounds.Right - this.Bounds.Left) >= 0)
{
right = false;
left = true;
}
// in relative coordinates left is always 0
if (txtLabel.Location.X <= 0)
{
right = true;
left = false;
}
// in relative coordinates top is always 0
if (txtLabel.Location.Y <= 0)
{
top = false;
bot = true;
}
I created a modified Pacman, but I want to add a firebolt shooting out from the mouth of the Pacman. My code is:
namespace TestingPacman
{
class Firebolt
{
Bitmap firebolt0 = null;
Bitmap firebolt1 = null;
public Point fireboltposition;
int fireboltwidth = 0;
int fireboltheight = 0;
public Firebolt(int x, int y)
{
fireboltposition.X = x;
fireboltposition.Y = y;
if (firebolt0 == null)
firebolt0 = new Bitmap("firebolt0.gif");
if (firebolt1 == null)
firebolt1 = new Bitmap("firebolt1.gif");
int fireboltwidth = firebolt0.Width;
int fireboltheight = firebolt0.Height;
}
public Rectangle GetFrame()
{
Rectangle Labelrec = new Rectangle(fireboltposition.X, fireboltposition.Y, fireboltwidth, fireboltheight);
return Labelrec;
}
public void Draw(Graphics g)
{
Rectangle fireboltdecR = new Rectangle(fireboltposition.X, fireboltposition.Y, fireboltwidth, fireboltheight);
Rectangle fireboltsecR = new Rectangle(0, 0, fireboltwidth, fireboltheight);
g.DrawImage(firebolt0, fireboltdecR, fireboltsecR, GraphicsUnit.Pixel);
}
}
How can I make a firebolt move in the direction the pacman is facing?
I have a form1 that when I press "F" it will fire a firebolt
but it cant seem to produce the firebolt image. Why is that?
namespace TestingPacman
{
public partial class Form1 : Form
{
// int inc = 0;
Eater TheEater = new Eater(100,100);
TimeDisplay time = new TimeDisplay();
int sec = 0;
Score score = new Score();
int countofeaten=0;
Random r = new Random();
private List<Label> redlabels = new List<Label>();
private List<Label> bluelabels = new List<Label>();
Firebolt firebolt;
List<Firebolt> listfirebolt = new List<Firebolt>();
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.FillRectangle(Brushes.White, 0, 0, this.ClientRectangle.Width, ClientRectangle.Height);
TheEater.Draw(g);
foreach(Firebolt f in listfirebolt)
f.Draw(g);
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
timer1.Enabled = true;
string result = e.KeyData.ToString();
Invalidate(TheEater.GetFrame());
switch (result)
{
case "D1":
if (TheEater.eaterwidth >= 9 && TheEater.eaterheight >= 9)
{
TheEater.eaterwidth++;
TheEater.eaterheight++;
}
break;
case "F":
listfirebolt.Add(firebolt = new Firebolt(TheEater.Position.X, TheEater.Position.Y));
Invalidate(firebolt.GetFrame());
break;
case "D2":
if (TheEater.eaterwidth > 10 && TheEater.eaterheight > 10)
{
TheEater.eaterwidth--;
TheEater.eaterheight--;
}
break;
case "D9": TheEater.inc=TheEater.inc+2;
break;
case "D0": TheEater.inc=TheEater.inc-2;
break;
case "Left":
TheEater.MoveLeft(ClientRectangle);
Invalidate(TheEater.GetFrame());
break;
case "Right":
TheEater.MoveRight(ClientRectangle);
Invalidate(TheEater.GetFrame());
break;
case "Up":
TheEater.MoveUp(ClientRectangle);
Invalidate(TheEater.GetFrame());
break;
case "Down":
TheEater.MoveDown(ClientRectangle);
Invalidate(TheEater.GetFrame());
break;
default:
break;
}
RemoveifIntersected();
}
label2.Text = score.Iskore.ToString();
}
private void timer1_Tick(object sender, EventArgs e)
{
label1.Text = time.FormatTime(sec++);
}
}
}
Jeo, what you are missing in your code is the concept of "Time" as far as I can tell your game only reacts when you press keys. What you really need is a mechanism to pass time in your game. This is almost always done in games with repetitive calls to something called "A Game Loop". Here's a quick example of a game loop that might work for you
class Mob
{
float XPos;
float YPos;
float XVel;
float YVel;
}
List<Mob> EveryThingMovable = new List<Mob>();
void GameLoop() //This loop is called 30 times every second... use a timer or whatever, there are far more sophisticated models, but for a first attaempt at a game it's easiest.
{
MoveEverybody(); //make a function that moves everything that can move
//Later you will have to add collision detection to stop pacman from moving through walls
CollideFireballs(); //Check if a fireball hits the bad guys
//More game stuff...
}
void MoveEverybody()
{
foreach(Mob dude in EverythingMovable)
{
ifDoesntHitWall(dude)
{
dude.XPos += dude.XVel;
dude.YPos += dude.YVel;
}
}
}
anyways, read up on the idea of a Game Loop, I think it's the biggest hurtle you haven't passed in order to move ahead.