cannot make a moving picturebox stop at a specific point - c#

i have to create a traffic simulator, i want to move a car (picturebox) while the traffic light is not red and have it stopped when it is red, at the point of the traffic light.
The traffic lights are 3 pannels changing color.
My problem is that my car does not stop when it meets the red traffic light. I have tried the "pictureBox.Location.X" and the "pictureBox.Left" but it just doesn't work, the pictureBox just goes on moving.
I have also tried throwing a messageBox when the car meets the traffic light just to see if the "pictureBox.Location.X" is working but still nothing. Seems like it does not recognize the function.
I have tried to make the traffic light both with panels and pictureboxes but still the same.
Bellow i send you my code so far:
private void timerCar1_Tick(object sender, EventArgs e)
{
//timerCar2.Enabled = true;
if(panelRed.BackColor == Color.Red)
{
car1.Left -= 5;
}
/* ---> */ else if (car1.Location.X == panelGreen.Location.X & panelRed.BackColor == Color.Red)
{
car1.Left -= 0;
}
else if (panelGreen.BackColor == Color.Green)
{
car1.Left -= 20;
}
else if (panelOrange.BackColor == Color.Orange)
{
car1.Left -= 10;
}
}

You use &.
else if (car1.Location.X == panelGreen.Location.X & panelRed.BackColor == Color.Red)
I've heard this can lead to unintended behavior. Did you mean to use the logical "AND" (&&)?
else if (car1.Location.X == panelGreen.Location.X && panelRed.BackColor == Color.Red)

I think that in c# for the logical "AND" ypu can use both & and &&. The problem was fixed by changing the pixel move from += 20 to += 3, so i think my picturebox would not meet the point i set as stopping point, due to the fact that it was moving 20 20 pixels.

Related

How to use update to use mouse in my game properly

I'm building a chess game now, and I have a problem.
I have this update function for the pawn:
public void update(GameTime gameTime)
{
MouseState ms = Mouse.GetState();
if (ms.LeftButton == ButtonState.Pressed)
{
if ((float)ms.X / 50 >= location.x && (float)ms.X / 50 <= location.x + 1 && (float)ms.Y / 50 >= location.y && (float)ms.Y / 50 <= location.y + 1)
{
if (!draw_spots)
{
draw_spots = true;
}
else
{
draw_spots = false;
}
}
else
{
spot sp = new spot(ms.X / 50, ms.Y / 50);
if (draw_spots)
{
draw_spots = false;
}
}
}
what it is supposed to do is to put draw_spots to true (meaning that the possible moving locations and eating location should be drawn) when pressing the left mouse click. change it to false when i press again so it should stop drawing those. the function work, but sometimes the squares that should turn to blue just flicker and turn off. My guess is that I press the left mouse button for an even number of update sequences (which makes it turn on and then off). any idea on how to solve it?
Thanks!
a video of the problem: https://www.youtube.com/watch?v=Awb4V1giV2Y&feature=youtu.be
you can see some presses that make the blue line appear and then disappear even though i pressed once
When you write code in an Update method you need to think about it as if it was inside an infinite loop like this:
while(true)
{
if (!draw_spots)
{
draw_spots = true;
}
else
{
draw_spots = false;
}
}
When you look at the logic in that simplistic manner it should be easy to see why you're getting the flickering behaviour. It's literally toggling the draw_spots variable on and off over and over again.
To keep with the infinite loop analogy lets take a look at what the code should be doing instead. There's essentially two things that should both be true when you want to "draw spots".
The left mouse button is pressed
The mouse cursor is within the square
Now, lets translate this logic into code.
while(true)
{
var ms = Mouse.GetState();
var leftButtonPressed = ms.LeftButton == ButtonState.Pressed;
var mouseInsideSquare = (float)ms.X / 50 >= location.x &&
(float)ms.X / 50 <= location.x + 1 &&
(float)ms.Y / 50 >= location.y &&
(float)ms.Y / 50 <= location.y + 1;
if (leftButtonPressed && mouseInsideSquare)
draw_spots = true;
else
draw_spots = false;
}
By keeping things as simple as possible and naming your bits of logic with extra variables the code gets a lot easier to read and understand.
I would even go as far as pulling out even more bits of logic into variables and simply set the value of draw_spots to the result like this:
var ms = Mouse.GetState();
var leftButtonPressed = ms.LeftButton == ButtonState.Pressed;
var mx = ms.X / 50f;
var my = ms.Y / 50f;
var mouseInsideSquare = mx >= location.x &&
mx <= location.x + 1 &&
my >= location.y &&
my <= location.y + 1;
draw_spots = leftButtonPressed && mouseInsideSquare;
It's a matter of taste which version of the above code you prefer. The point is to break your code up in a way that makes it easier to understand. I hope that helps.
The only other weird bit of your code is this line:
spot sp = new spot(ms.X / 50, ms.Y / 50);
but since the sp variable goes out of scope before it's used I'm going to assume you left it there while debugging something and it can be safely deleted.
I was able to fix this myself, what i did was as follows.
add a variable called oldms that saves the mouse state from the last update.
then in the if statement I asked if the mouse left key is not pressed, and also if mouse left key was pressed last update. which means, i pressed the mouse and i want it to draw now.

C# How do I move a picturebox that changes images depending on the direction hes facing?

Using visual studio 2015 I use a picture box as a player and have it move up, down, left and right. When the picture box moves it shrinks and then looks like it teleports. That is not what it is supposed to do. How do I properly get the picture box to change whenever I press the wasd keys?
if (e.KeyCode == Keys.D)
{
x += 6;
playerBox.Image = Properties.Resources.playerRight;
}
//moves player right and changes the image
Just add to / subtract, the picturebox Top and Left:
if (e.KeyCode == Keys.D)
{
playerBox.Left += 6;
playerBox.Image = Properties.Resources.playerRight;
}
also to avoid changing photo everytime if the direction has not changed you may do something like this:
if (e.KeyCode == Keys.D)
{
playerBox.Left += 6;
if((Keys)playerBox.Tag!=e.KeyCode)
playerBox.Image = Properties.Resources.playerRight;
}
You must of course set some inital value for playerBox.Tag or you will get an error as it cant be cast to Keys

Managing multi-touch events in WPF

I am writing a program using the Surface SDK and .NET 4.0. I have to distinguish between multi-touch events and I'm having trouble distinguishing between gestures.
With two fingers I want to be able to zoom and rotate, but because generally the fingers are not moving in straight lines or perfect circles on the screen, the result is a combination of zoom and rotate. Could someone point out how this problem can be overcome? I am using some thresholds for ignoring small deviations, but these thresholds need to be manually tweaked and I couldn't find a good value for them.
I was thinking I could detect which kind of a gesture it is in the onManipulationStarting method and ignore the rest, but sometimes the gesture can start with just one finger on the screen and I'm identifying the wrong gesture.
I am including some code below:
private void OnManipulationDeltaHandler(object sender, ManipulationDeltaEventArgs mdea)
{
var zoomAmount = Math.Abs(mdea.DeltaManipulation.Scale.Length - Math.Sqrt(2));
// ZOOM ACTION: 2 fingers and scaling bigger than a threshold
if ((TouchesOver.Count() == 2) && (zoomAmount > scaleThreshold))
{
if (ZoomCommand != null)
{
if (Math.Abs(zoomAmount - 0) > 0.1)
{
ZoomCommand.Execute((-zoomAmount).ToString());
}
}
}
else
{
var rotateAmount = -mdea.DeltaManipulation.Rotation;
if ((TouchesOver.Count() == 2))
{
headValue += rotateAmount;
if (HeadRotationCommand != null)
{
HeadRotationCommand.Execute(new Orientation(pitchValue, headValue, rotateAmount));
}
}
}
mdea.Handled = true;
base.OnManipulationDelta(mdea);
}
Can someone help? Thanks!

How do I move a game piece(control) during runtime?

I am doing a simple C# program of the game Knights Tour in C# the hard way to learn all I can of C#. I have a board and a knight piece and the knight is a custom panel with the picture of the knight.
What I am attempting to do is allow the user to click and drag the knight piece control during run time (exactly the way you can move the control in design time to place it), but for whatever reason I have getting some very undesired results.
private void KTmain_Load(object sender, EventArgs e)
{
boolKnightmoves = false;
}
private void kpcKnight_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
switch (e.Button)
{
case MouseButtons.Left:
boolKnightmoves = true;
intCurMouseX = e.X;
intCurMouseY = e.Y;
break;
case MouseButtons.Right:
case MouseButtons.Middle:
case MouseButtons.XButton1:
case MouseButtons.XButton2:
case MouseButtons.None:
default:
boolKnightmoves = false;
break;
}
}
private void kpcKnight_MouseUp(object sender, MouseEventArgs e)
{
switch (e.Button)
{
case MouseButtons.Left:
boolKnightmoves = false;
break;
case MouseButtons.Right:
case MouseButtons.Middle:
case MouseButtons.XButton1:
case MouseButtons.XButton2:
case MouseButtons.None:
default:
boolKnightmoves = false;
break;
}
}
private void kpcKnight_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (boolKnightmoves)
{
txtTest.Text = e.X + ", " + e.Y;
txtTest.Text += Environment.NewLine + kpcKnight.Location;
int i = e.X == intCurMouseX ? 0 : e.X > intCurMouseX ? 1 : -1;
int j = e.Y == intCurMouseY ? 0 : e.Y > intCurMouseY ? 1 : -1;
txtTest.Text += Environment.NewLine + i.ToString() + ", " + j.ToString();
kpcKnight.Location = new Point(
kpcKnight.Location.X + i,
kpcKnight.Location.Y + j);//e.Y == intCurMouseY ? 0 : e.Y > intCurMouseY ? 1 : -1);
//e.X == intCurMouseX ? 0 : e.X > intCurMouseX ? 1 : -1,
intCurMouseX = e.X;
intCurMouseY = e.Y;
}
}
private void kpcKnight_MouseLeave(object sender, EventArgs e)
{
boolKnightmoves = false;
}
private void kpcKnight_LocationChanged(object sender, EventArgs e)
{
kpcKnight.Refresh();
}
I see no real reason why this code would not do the same thing, but I am obviously missing something. When I click on the knight and move it, it does not move at the same speed as the mouse, it moves much slower. It also fades while moving it where you cant see it.
How do i make the knight piece move the same way it does in the form designer in a way that makes sense moving a chess piece across a chess board?
Any assistance will be appreciated.
I updated the code a bit and it does seem to help, but the animation aspect of it is still quite choppy and the panel picks up a bit of the background as it moves and placed.
how does it do it in the form designer so smoothly?
private void kpcKnight_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (boolKnightmoves)
{
txtTest.Text = e.X + ", " + e.Y;
txtTest.Text += Environment.NewLine + kpcKnight.Location;
int x = kpcKnight.Location.X + e.X - intCurMouseX;
int y = kpcKnight.Location.Y + e.Y - intCurMouseY;
kpcKnight.Location = new Point(x, y);
kpcKnight.Refresh();
/*
int i = e.X == intCurMouseX ? 0 : e.X > intCurMouseX ? 1 : -1;
int j = e.Y == intCurMouseY ? 0 : e.Y > intCurMouseY ? 1 : -1;
txtTest.Text += Environment.NewLine + i.ToString() + ", " + j.ToString();
kpcKnight.Location = new Point(
kpcKnight.Location.X + i,
kpcKnight.Location.Y + j);//e.Y == intCurMouseY ? 0 : e.Y > intCurMouseY ? 1 : -1);
//e.X == intCurMouseX ? 0 : e.X > intCurMouseX ? 1 : -1,
intCurMouseX = e.X;
intCurMouseY = e.Y;*/
}
}
Why don't you just set the Knights position the same as the mouse position in the Mouse_Move method?
Something like:
kpcKnight.Location = new Point(e.X, e.Y)
Obviously you can make it move nicer by knowing where the Knight got initially clicked and move smoothly according to that delta without having the initial jitter.
It's drawing so slowly because you're moving a panel with every mouse motion. That means the form needs to redraw itself several times, and a complete form redraw is expensive.
The basic solution is - don't change the panel's position that often.
I see two ways of doing it.
The first way is simple, but may look jerky. Don't draw every mouse movement. Draw every 5th one, or some arbitrary number you set. Basically keep a counter that you set to 0 on mouse down, and every time you get a mouse move, check if ++counter % n == 0. If so, do the actual drawing. Just make sure to draw on mouse up, as well. Or, just as effectively, only draw when one mouse movement is a certain number of points in x or y away from the previous position.
The second idea is more complicated, but should be the fastest, least jerky thing you can do. Don't move the panel at all while the mouse is moving. Instead, make the panel disappear, and set the cursor to a custom cursor showing the knight. On mouse up, reset the cursor, move the panel and make it visible. This should be about as fast as you can get.
Edit
I'm going to go into the realm of metaphor here, just to get a few things across. Animation is an aspect of C#, but it's not one of the features of it. (i.e., you can accomplish it, but it doesn't have much to make these things easy on you, and it's not a simple key feature.) So... metaphor.
Think of the controls you've placed on your screen to make your board and knight as a bunch of cars packed tight into a parking lot. All you're doing is looking at the parking lot from a helicopter high up. What you're telling the runtime to do, every time you move a component, is completely bulldoze the cars off the parking lot, then place them with a crane in new positions. That's the scope that I'm talking about when I say "a complete form redraw is expensive."
Instead, what you want to do from your helicopter is percieve that the cars are magically changing position. Rather than have a bulldozer and a crane, just blank out your helicopter view, take a snapshot of what you want to see, and change the snapshot little by little, until it looks the way you want. That's what the second suggestion is - don't consantly force the form to recalculate each component's look. Instead, put the animation above the form, and only change the form when you're done.
The keywords you want to search for are "gdi+" (the .NET graphics package), and animation. MouseMove wouldn't hurt, and Paint is the event where you may need to do the animations. There are plenty of places you can find, though How to draw rectangle on MouseDown/Move c# could be a good start.
Edit #2
One last suggestion I have. You can use this in addition to any animation you make. Functionally, it satisfies your requirements on its own, but it's probably not what you're looking for. Track the mouse, and modify the background image of whatever panel the mouse is hovering over. In that case, you'll want to be looking at ImageList, and simple properties like your control BackgroundImage. This could be nice even if you do have a better animation working. You can easily use this to show "the knight can't move here" or "the knight has already moved here." Since it's changing your component instead of moving your component, it's really inexpensive to do, and can easily keep up with your mouse movement. It may be sufficient to imply the movement you want, and it will teach you aspects of winforms that are more important and frequently used than animation and GDI+ rendering.
All you need is:
private int intCurMouseX, intCurMouseY;
private void kpcKnight_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
intCurMouseX = e.X;
intCurMouseY = e.Y;
}
}
private void kpcKnight_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
kpcKnight.Location = new Point(
kpcKnight.Location.X + (e.X - intCurMouseX),
kpcKnight.Location.Y + (e.Y - intCurMouseY));
}
}
Transparency in .Net is a bit of a misnomer. The background simply becomes the color of the parent container. When your controls overlap with each, as will likely be the case when the pieces are dragged across the board, then you'll see the "background" of the piece because controls are rectangular. One option would be to actually CLIP the PictureBox so it is an irregular shape. This can be accomplished by creating a Region() from a GraphicsPath() and then assigning that to the Region() property of the PictureBox. A simplistic approach is to use whatever color is in the top left of the Image and use that as the "mask" color. Next walk the entire image and only add locations where pixels are not the mask color to the GraphicsPath(). This only needs to be done once with the PictureBox after the Image() has been assigned. Again, this approach requires that the "background" of your image (the parts you do NOT want to keep) are all the same color, AND also that this color is not present anywhere as part of the image you want to keep. Here's an example:
private void Form1_Load(object sender, EventArgs e)
{
// perform this for all your PictureBox pieces:
this.ClipPictureBoxPiece(this.kpcKnight);
// ...
// ...
}
private void ClipPictureBoxPiece(PictureBox pb)
{
if (pb != null && pb.Image != null)
{
System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();
using (Bitmap bmp = new Bitmap(pb.Image))
{
Color mask = bmp.GetPixel(0, 0);
for (int x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
if (!bmp.GetPixel(x, y).Equals(mask))
{
gp.AddRectangle(new Rectangle(x, y, 1, 1));
}
}
}
}
pb.Region = new Region(gp);
}
}

How to move object on the screen

how I can move any Object on screen in WinForm ?
When I press right -> the object will move right until i'll press any other arrow key
and when I press left <- the object will move left until i'll press any other arrow key
The object all the time will be in motion (like in the Snake game)
thank's in advance
You probably want to inherit from Form and override the OnPaint method. You'll probably also need to Invalidate() every time to force repaint. This will set up a simple game loop and allow you to update the screen pretty quickly.
In your OnPaint method you'll update the position of an object based on how much time has elapsed since the last time your OnPaint method was called and which key was pressed last. You'll probably do this by using a velocity as follows:
newPosition = oldPosition + (elapsedTime * velocity)
The value of velocity will change based on which key you press (i.e. negative for left, positive for right). You'll also need a variable and some code to keep track of whether it's moving horizontally or vertically.
This is a pretty low performance way to accomplish this (i.e. it's a hack). If you want to stick with Windows but get better performance without too much work, you might look into XNA. If you want much better performance and are willing to do significantly more work, look into Interop with DirectX and the Win32 API or just switch over all together.
You need a game loop to continue the direction of the movement you originally initiated with a single press of a button.
capture keys, adjust object coordinates.
Assuming you're doing this in 2D, you could setup an x and y change factor that you setup properly with each arrow key press. Then setup a timer to update position at the rate you want. And when the timer ticks, adjust the position of your object by the x/y change factors.
enum position
{
Left,Right,up,down
}
private int _x;
private int _y;
private position _objposition;
public Form1()
{
InitializeComponent();
_x = 50;
_y = 50;
_objposition = position.down;
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.FillRectangle(Brushes.DarkSlateBlue,_x,_y,100,100);
}
private void timertick_Tick(object sender, EventArgs e)
{
if (_objposition == position.Right)
{
_x += 10;
}
else if (_objposition == position.Left)
{
_x -= 10;
}
else if (_objposition == position.up)
{
_y -= 10;
}
else if (_objposition == position.down)
{
_y += 10;
}
Invalidate();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Left)
{
_objposition =position.Left;
}
else if (e.KeyCode == Keys.Right)
{
_objposition = position.Right;
}
else if (e.KeyCode == Keys.Up)
{
_objposition = position.up;
}
else if (e.KeyCode == Keys.Down)
{
_objposition = position.down;
}
}
}
This will create a rectangle of 50X50 size. By default i will set the position of that box downward.But when you press any key for eg:- if you press left key arrow then key event will fire and it will set the position of the box towards left and the box will start moving in left until another key is pressed

Categories

Resources