I am trying to create a car game using pictureboxes and timers
Here is my code
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
PictureBox car = new PictureBox();
Timer t = new Timer();
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
//Right arrow key
if (e.KeyCode.Equals(Keys.Right) && carPlayer.Location.X < 300)
{
int x = carPlayer.Location.X + 5;
int y = carPlayer.Location.Y;
int width = carPlayer.Size.Width;
int height = carPlayer.Size.Height;
carPlayer.SetBounds(x, y, width, height);
}
//Left arrow key
if (e.KeyCode.Equals(Keys.Left) && carPlayer.Location.X > 35)
{
int x = carPlayer.Location.X - 5;
int y = carPlayer.Location.Y;
int width = carPlayer.Size.Width;
int height = carPlayer.Size.Height;
carPlayer.SetBounds(x, y, width, height);
}
if (e.KeyCode.Equals(Keys.Space))
{
spawnCar();
}
}
void spawnCar()
{
string[] cars = { "data/car_red.png", "data/car_blue.png", "data/car_green.png", "data/car_grey.png" };
Random rand = new Random();
car.SizeMode = PictureBoxSizeMode.StretchImage;
car.Image = Image.FromFile(cars[rand.Next(0, 4)]);
car.Visible = true;
if (rand.Next(0,2) == 0)
{
car.SetBounds(100, 10, 50, 85);
}
else
{
car.SetBounds(250, 10, 50, 85);
}
this.Controls.Add(car);
car.BringToFront();
t.Interval = 1;
t.Tick += new EventHandler(t_Tick);
t.Start();
}
private void t_Tick(object sender, EventArgs e)
{
if (car.Bounds.IntersectsWith(carPlayer.Bounds))
{
t.Stop();
car.Image = Image.FromFile("data/car_wreck.png");
carPlayer.Image = Image.FromFile("data/player_wreck.png");
}
if (car.Bounds.Y > 340)
{
t.Stop();
this.Controls.Remove(car);
}
else
{
car.Top++;
}
}
}
http://i.stack.imgur.com/NhCgY.png
Now when I press space once the car appears at the top and moves down slowly and disappears on reaching the bottom but when I press space multiple time the speed of the car gets faster and faster .
Anyone please help me make the car move at same speed everytime it is created.
Thanks
The problem is that you are registering a new Tick event handler with each car spawn, you only want to do this once. However, there isn't an easy way to check if a handler has been assigned yet so I would recommend using a global flag...
//at class level
bool eventSet = false;
//in spawn method
t.Interval = 1;
if(!eventSet)//check if no handler assigned yet
{
t.Tick += new EventHandler(t_Tick);
eventSet = true;
}
t.Start();
Alternatively, you could attempt to remove the handler before assigning...
//in spawn method
t.Interval = 1;
t.Tick -= new EventHandler(t_Tick);//remove previous one if it exists
t.Tick += new EventHandler(t_Tick);
t.Start();
Related
Me and my buddy have been working on this magnifier application and we cannot make it work the way we want it.
The way we would like it to work:
Open app.
Move mouse to area you want magnified.
Hit enter.
Magnifying window moves to (offset) location of mouse and keeps updating that window for that specific location.
Hit enter again to move window to new cursor location.
Right now once i hit enter, the window follows the mouse because it goes into a for loop where it grabs "Cursor.Position". I've tried to save the Cursor.Position value at the "OnkeyDown" event and use it inside the timer loop but that won't work since it "does not exist in current context".
Can anyone see how i can do this?
Thanks in advance!
/Morten
/* O-button zooms out
* I-button zooms in
* Esc-button exits app
* Enter moves magnifying window to new location (doesn't work)
*/
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Magnifier
{
public partial class Form1 : Form
{
Bitmap printscreen = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
PictureBox pictureBox1 = new PictureBox();
int zoom = 3; //zoom level
public bool NewZoomLocation = false;
public Form1()
{
{
InitializeComponent();
pictureBox1.Dock = DockStyle.Fill;
pictureBox1.BorderStyle = BorderStyle.FixedSingle;
Controls.Add(pictureBox1);
FormBorderStyle = FormBorderStyle.None;
Timer timer = new Timer();
timer.Interval = 100;
timer.Tick += timer_Tick;
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{ var position = Cursor.Position;
int xlocation = position.X;
int ylocation = position.Y;
{
try
{
var graphics = Graphics.FromImage(printscreen as Image);
graphics.CopyFromScreen(0, 0, 0, 0, printscreen.Size);
GC.Collect(); // Force the garbage collector (deals with memory leak)
if (NewZoomLocation == true)
{
var lensbmp = new Bitmap(50, 50); //Bitmap for Zoom window
var i = 0;
var j = 0;
for (int row = xlocation - 25; row < xlocation + 25; row++)
{
j = 0;
for (int column = ylocation - 25; column < ylocation + 25; column++)
{
lensbmp.SetPixel(i, j, printscreen.GetPixel(row, column));
j++;
}
i++;
}
this.pictureBox1.Image = new Bitmap(lensbmp, lensbmp.Width * zoom, lensbmp.Height * zoom);
Size = pictureBox1.Image.Size;
Left = xlocation - 45 * (zoom); //Horisontal position of final zoom window
Top = ylocation + 30; //Vertical position of final zoom window
TopMost = true;
}
}
catch //(Exception ex)
{
//MessageBox.Show(ex.Message);
}
}
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyValue == 73) // I-button to zoom in
zoom++;
else if (e.KeyValue == 79) // O-button to zoom in
zoom--;
else if (e.KeyValue == 27) // Esc-button to exit
{
Close();
Dispose();
}
else if (e.KeyValue == 13) // Enter-button to choose zoon area
{
NewZoomLocation = true;
}
base.OnKeyDown(e);
}
}
}
I'm not really sure what you want to achieve here, however this should get you in a better place.
First thing first. The use of GC.Collect its because you are trying to plug a memory leak, if you ever create an image, dispose of it.
Given some globals
private readonly PictureBox pictureBox1 = new PictureBox();
private Bitmap _lastBmp = new Bitmap(300, 300);
private Point _position;
public bool NewZoomLocation;
private int zoom = 3; //zoom level
Constructor
public Form1()
{
InitializeComponent();
pictureBox1.Dock = DockStyle.Fill;
pictureBox1.BorderStyle = BorderStyle.FixedSingle;
Controls.Add(pictureBox1);
FormBorderStyle = FormBorderStyle.None;
KeyPreview = true;
Size = _lastBmp.Size;
TopMost = true;
var timer = new Timer();
timer.Interval = 100;
timer.Tick += timer_Tick;
timer.Start();
}
Cleanup
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
_lastBmp.Dispose();
_lastBmp = null;
}
Keydown
protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
{
base.OnPreviewKeyDown(e);
switch (e.KeyCode)
{
case Keys.Enter:
NewZoomLocation = true;
_position = Cursor.Position;
break;
case Keys.Up:
zoom++;
break;
case Keys.Down:
zoom--;
break;
case Keys.Escape:
Close();
break;
}
}
Timer
private void timer_Tick(object sender, EventArgs e)
{
if (NewZoomLocation)
{
var w = _lastBmp.Size.Width / zoom;
var h = _lastBmp.Size.Height / zoom;
var x = _position.X - w / 2;
var y = _position.Y - h / 2;
var size = new Size(w, h);
using (var screen = new Bitmap(size.Width, size.Height))
{
using (var g = Graphics.FromImage(screen))
{
g.CopyFromScreen(new Point(x, y), Point.Empty, size);
}
// resize
using (var g = Graphics.FromImage(_lastBmp))
{
g.DrawImage(screen, new Rectangle(new Point(), _lastBmp.Size), new Rectangle(0, 0, w, h), GraphicsUnit.Pixel);
}
}
pictureBox1.Image = _lastBmp;
}
}
There is a lot more that can be done with this, however it should get you started. There is no memory leak anymore, it only grabs a screen shot of what it needs so will be faster.
Good luck
First of all I want to thank you for your time :) So there is my problem.. I am trying to make a little game where I spawn PictureBox and send it from right to left and my player which will be a PictureBox will try to avoid them jumping. So the first thing I did is , I created my PictureBox spawner with a class .. But the problem is , I can only spawn block[0] .. when I try to create block[1], nothing happens !! Please help me.. There is my code :
Form1.cs
namespace Game_0._1
{
public partial class Form1 : Form
{
Block[] block = new Block[50];
public Form1()
{
InitializeComponent();
int _Length = block.Length;
for(int i=0; i < 50; i++)
{
block[i] = new Block();
this.Controls.Add(block[i]._ScreenPanel());
block[i].Screen.Controls.Add(block[i].Box);
label1.Text = ("Generating block [" + i + "]");
}
}
private void button1_Click(object sender, EventArgs e)
{
block[0].SpawnBlock();
}
}
}
Block.cs
namespace Game_0._1
{
class Block
{
public Panel Screen;
public PictureBox Box;
Point x = new Point(50, 50);
Size s = new Size(150, 50);
Color c = Color.FromName("black");
public Block()
{
Screen = new Panel();
Screen.Dock = DockStyle.Fill;
Box = new PictureBox();
}
public Panel _ScreenPanel()
{
return Screen;
}
public PictureBox SpawnBlock()
{
Box.Name = "Obstacle";
Box.Location = x;
Box.Size = s;
Box.BorderStyle = BorderStyle.FixedSingle;
Box.BackColor = c;
return Box;
}
public void ChangeXLoc()
{
this.x.X += 50;
}
}
}
Here :
private void button1_Click(object sender, EventArgs e)
{
block[0].SpawnBlock();
}
this spawn a black box successfully , but if I type block[1], nothing ...
The issue is that your Panel (Screen) is overlapping the Panel that box[1] is positioned in, as a result it is not visible unless brought to front - which will in turn make the other box invisible instead.
A solution to this is to use a single panel, and size it accordingly, this allows you to place each box on the same panel and have their position relative to the Panel's 0,0.
Another solution would be to have a panel for each box which is the same size as the box and move the Panel and not the box which will have the same effect, but likely require less code to be edited.
I modified your code a little maybe it helps:
your form :
public partial class Form1 : Form
{
private Block[] _block = new Block[50];
private Point _x = new Point(0, 50);
private Timer _timer=new Timer();
private int _index = 0;
public Form1()
{
InitializeComponent();
_timer.Interval = 1000;
_timer.Tick += _timer_Tick;
for (int i = 0; i < 50; i++)
{
_block[i] = new Block(_x);
//Move the position of the block
ChangeXLoc();
Controls.Add(_block[i]._ScreenPanel());
label1.Text = #"Generating block [" + i + #"]";
}
}
//Timer to spawn the blocks
private void _timer_Tick(object sender, EventArgs e)
{
_block[_index].SpawnBlock();
if (_index < 49)
_index++;
}
private void button1_Click(object sender, EventArgs e)
{
_timer.Start();
}
private void ChangeXLoc()
{
_x.X += 50;
}
}
and your block class :
class Block
{
Panel Screen;
PictureBox Box;
Point _x;
Size s = new Size(50, 50);
Color c = Color.FromName("black");
//Pass the position x to the block
public Block(Point x)
{
_x = x;
Screen = new Panel
{
Size = s
};
}
public Panel _ScreenPanel()
{
Screen.Location = _x;
return Screen;
}
public void SpawnBlock()
{
Box = new PictureBox
{
Dock = DockStyle.Fill,
Name = "Obstacle" + _x,
BorderStyle = BorderStyle.FixedSingle,
BackColor = c
};
Screen.Controls.Add(Box);
}
}
This is a custom control I have made, a graphical timer, however, it is not working correctly. As the time left decreases a pie is filled to represent the amount of time left decreasing, but it is decreasing with unexpected angles (which are output to the listbox for debugging purposes). How do I get it to work correctly? Also I'm very new to making Custom Controls (this is my first) so any pointers on good coding guidelines, what not to do, etc, would be very helpful.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace TestCustomControl
{
class GraphicalTimer : Control
{
public Color Timer { get; set; }
public Color TimerEmpty { get; set; }
public Color BorderColor { get; set; }
private Timer t;
public int MaxTime { get; set; }
private int timeElapsed = 0;
public GraphicalTimer()
{
DoubleBuffered = true;
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
BackColor = Color.Transparent;
t = new Timer();
t.Interval = 1000;
t.Tick += t_Tick;
}
public void Start()
{
t.Start();
}
public void Stop()
{
t.Stop();
}
public void Reset()
{
timeElapsed = 0;
Invalidate();
}
void t_Tick(object sender, EventArgs e)
{
timeElapsed += 1;
if (timeElapsed == MaxTime)
{
t.Dispose();
}
Invalidate();
}
private float getAngleFromTime()
{
if (timeElapsed == 0)
{
return 0;
}
else
{
MainWindow.lb.Items.Add((360 / (MaxTime / timeElapsed)).ToString());
return (360 / (MaxTime / timeElapsed));
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
Rectangle rc = ClientRectangle;
g.FillEllipse(new SolidBrush(Timer), rc);
g.FillPie(new SolidBrush(TimerEmpty), rc, -90, getAngleFromTime());
g.DrawEllipse(new Pen(BorderColor, 4), rc);
Font font = new Font("Arial", (float)rc.Height * 0.4f, FontStyle.Bold, GraphicsUnit.Pixel);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
g.DrawString((MaxTime - timeElapsed).ToString("D2"), font, new SolidBrush(Color.Black), new RectangleF((rc.Width - rc.Width / 2) / 2, (rc.Height - rc.Height / 2) / 2, rc.Width * 0.7f, rc.Height * 0.7f));
}
}
class MainWindow : Form
{
GraphicalTimer gt;
Button startButton;
Button stopButton;
Button resetButton;
public static ListBox lb;
public MainWindow()
{
this.Text = "Test Application";
gt = new GraphicalTimer();
gt.MaxTime = 20;
gt.BorderColor = Color.BurlyWood;
gt.Timer = Color.Aqua;
gt.TimerEmpty = Color.White;
gt.Top = 10;
gt.Left = 10;
gt.Width = 50;
gt.Height = 50;
this.Controls.Add(gt);
startButton = new Button();
startButton.Top = 70;
startButton.Left = 30;
startButton.AutoSize = true;
startButton.Text = "Start Timer";
startButton.Click += startButton_Click;
this.Controls.Add(startButton);
stopButton = new Button();
stopButton.Top = 70;
stopButton.Left = startButton.Right + 10;
stopButton.AutoSize = true;
stopButton.Text = "Stop Timer";
stopButton.Click += stopButton_Click;
this.Controls.Add(stopButton);
resetButton = new Button();
resetButton.Top = 70;
resetButton.Left = stopButton.Right + 10;
resetButton.AutoSize = true;
resetButton.Text = "Reset Timer";
resetButton.Click += resetButton_Click;
this.Controls.Add(resetButton);
lb = new ListBox();
lb.Top = resetButton.Bottom + 10;
lb.Left = 10;
lb.Width = this.ClientSize.Width - 20;
lb.Height = this.ClientSize.Height - lb.Top - 10;
this.Controls.Add(lb);
}
void resetButton_Click(object sender, EventArgs e)
{
gt.Reset();
}
void stopButton_Click(object sender, EventArgs e)
{
gt.Stop();
}
void startButton_Click(object sender, EventArgs e)
{
gt.Start();
}
}
class StartClass
{
static void Main()
{
MainWindow form = new MainWindow();
Application.EnableVisualStyles();
Application.Run(form);
}
}
}
You are using integers to calculate the angle, and in a way that can cause quite some jitters.
360 / (MaxTime / timeElapsed) will first evaluate temp = MaxTime / timeElapsed in integer arithmetics, and then 360 / temp also using integer division.
Try using floating point numbers for the calculation and then converting the final result into an integer value if you need it that way. Even writing 360 * timeElapsed / MaxTime might reduce the artifacts as you then first multiply 360 * timeElapsed which is accurate (unless timeElapsed is very large).
The method of calculating AngleForTime is wrong. Just replace your method with below code and it should do your job.
;)
private float getAngleFromTime()
{
if (timeElapsed == 0)
{
return 0;
}
else
{
MainWindow.lb.Items.Add((360*timeElapsed) / MaxTime ).ToString();
return (360*timeElapsed) / MaxTime ;
}
}
How can i add a mouse click to this program that will increment a score by one each time the ball is clicked in C#?
namespace Ball_timer_2005
{
public class Form1 : System.Windows.Forms.Form
{
const int radius = 20;
const int velocity = 5;
int xC, yC, xDelta=10, yDelta=10, xSize, ySize; // class level variables
private System.Windows.Forms.Timer timer1;
private System.ComponentModel.IContainer components;
public Form1()
{
InitializeComponent();
// TODO: Add any constructor code after InitializeComponent call
this.ResizeRedraw = true; // Tell form to redraw itself when resized
timer1.Start();
Form1_Resize(this, EventArgs.Empty); // Force a Resize Event as pgm starts
//
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.timer1 = new System.Windows.Forms.Timer(this.components);
//
// timer1
//
this.timer1.Enabled = true;
this.timer1.Interval = 25;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Name = "Form1";
this.Text = "Bouncing Ball";
this.Resize += new System.EventHandler(this.Form1_Resize);
}
#endregion
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void Form1_Resize(object sender, System.EventArgs e)
{
xSize = this.ClientSize.Width; // Set current window size
ySize = this.ClientSize.Height;
xC = xSize/2; // Place ball in center of window
yC = ySize/2;
DrawBall(); // Draw the ball in the window
}
private void timer1_Tick(object sender, System.EventArgs e)
{
DrawBall(); // Draw ball in next frame of animation
}
private void DrawBall()
{
Graphics g = this.CreateGraphics();
Brush b = new SolidBrush(this.BackColor);
g.FillEllipse(b, xC-radius, yC-radius, 2*radius, 2*radius); //erase old ball
xC += xDelta; //move ball
yC += yDelta;
if ((xC+radius >= ClientSize.Width) || (xC - radius <= 0)) //check for wall hits
xDelta = -xDelta;
if ((yC+radius >= ClientSize.Height) || (yC - radius <= 0))
yDelta = -yDelta;
b = new SolidBrush(Color.GreenYellow); // draw new ball
g.FillEllipse(b, xC-radius, yC-radius, 2*radius, 2*radius);
b.Dispose();
g.Dispose();
}
}
}
1.this is the code i have so far can some one help ???
1.this is the code i have so far can some one help ???
1.this is the code i have so far can some one help ???
You can do this by Handling MouseClick event of the Form.
Step1: Store the Ellipse Co-ordinates into the Region to identify the position of the Mouse Click later.
//Declare it as class members
List<Region> regionList = new List<Region>();
int EclipseX = 10;
int EclipseY = 50;
int BallWidth = 100;
int BallHeight = 100;
//inside paint function
SolidBrush brush = new SolidBrush(Color.Blue);
e.Graphics.FillEllipse(brush, EclipseX,EclipseY, BallWidth, BallHeight);
regionList.Add(new Region(new Rectangle(EclipseX,EclipseY, BallWidth, BallHeight)));
Step2: now declare the MouseClick event of the Form
this.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseClick);
Step3: now handle the MouseClick event of the Form.
the MouseClick event provides MouseEventArgs parameter here e.
this MouseEventArgs has two properties.
first property is X gives you the X-axis Location of the
Mouse Click.
second property is Y gives you the Y-axis location of the Mouse Click.
you need to compare these X and Y values with existing Region values using IsVisible Property.
you need to get the each Region from the List (which was added while drawing
Ellipse) and use IsVisible Property of the Region class to
detect whether mouse clicked on the Ellipse or not.
//declare it as class member
int MouseClicksCount = 0;
bool isfound=false;
//event handler
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
isfound=false;
foreach(Region r in regionList)
{
if (r.IsVisible(e.X, e.Y))
{
isfound=true;
break;
}
}
if (isfound)
MouseClicksCount++;
}
Complete Solution(Sample code):
public partial class Form1 : Form
{
int MouseClicksCount = 0;
List<Region> regionList = new List<Region>();
int EclipseX = 10;
int EclipseY = 50;
int BallWidth = 100;
int BallHeight = 100;
bool isfound=false;
public Form1()
{
InitializeComponent();
this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint);
this.MouseClick += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseClick);
}
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
isfound=false;
foreach(Region r in regionList)
{
if (r.IsVisible(e.X, e.Y))
{
isfound=true;
break;
}
}
if (isfound)
MouseClicksCount++;
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
SolidBrush brush = new SolidBrush(Color.Blue);
e.Graphics.FillEllipse(brush, EclipseX,EclipseY, BallWidth, BallHeight);
regionList.Add(new Region(new Rectangle(EclipseX,EclipseY, BallWidth, BallHeight)));
}
}
Does this help at all
http://www.daniweb.com/software-development/csharp/threads/317766/mouse-coordinates-within-a-form
You may be able to us this to detect an overlap of mouse position/ ball width radius
I'm making a shooting game like Space Invaders. Every time I launched the missile, it's always on the same position. How will I change it depending on the place where the spaceship is.
Here's my codes for now.
class GraphicsApplication
{
private Form f;
private PictureBox pb;
private PictureBox pb1;
private PictureBox pb2;
private Boolean bMove;
Timer Clock = new Timer();
Timer Missile = new Timer();
int x = 0;
public GraphicsApplication()
{
f = new Form();
pb = new PictureBox();
pb1 = new PictureBox();
pb2 = new PictureBox();
bMove = false;
}
public void Launch()
{
f.Size = new Size(600, 600);
f.StartPosition = FormStartPosition.CenterScreen;
f.KeyDown += new KeyEventHandler(f_KeyDown);
f.KeyPress += new KeyPressEventHandler(f_KeyPress);
pb.SetBounds(300, 470, 70, 70);
pb.Image = new Bitmap("spaceship.png");
pb.SizeMode = PictureBoxSizeMode.StretchImage;
f.Controls.Add(pb);
pb1.Image = Image.FromFile("spacedisc.png");
pb1.SetBounds(20, 20, 130, 80);
pb1.SizeMode = PictureBoxSizeMode.StretchImage;
f.Controls.Add(pb1);
pb2.Image = Image.FromFile("missile.png");
pb2.SetBounds(pb.Location.X, pb.Location.Y, 25, 40); //pb2 missile //pb spaceship
pb2.SizeMode = PictureBoxSizeMode.StretchImage;
Clock = new Timer();
Clock.Interval = 40;
Clock.Start();
Clock.Tick += new EventHandler(Clock_Tick);
Missile = new Timer();
Missile.Interval = 40;
Missile.Tick += new EventHandler(Missile_Tick);
f.ShowDialog();
}
private void f_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Space)
{
Missile.Start();
}
}
public void Missile_Tick(object sender, EventArgs e)
{
if (bMove == true)
{
f.Controls.Add(pb2);
pb2.Top = pb2.Top -= 5;
}
}
private void f_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 'd')
{
pb.Left = pb.Left += 5;
}
if (e.KeyChar == 'a')
{
pb.Left = pb.Left -= 5;
}
}
public void Clock_Tick(object sender, EventArgs e)
{
if(x == 400)
{
bMove = true;
}
else if (x == 30)
{
bMove = false;
}
if (bMove == false)
{
x += 5;
pb1.Location = new Point(20 + x, 20);
}
else
{
x -= 5;
pb1.Location = new Point(x - 20, 20);
}
}
}
}
You probably want something like
pb2.Location.X = pb.Location.X;
pb2.Location.Y = pb.Location.Y;
in your f_KeyDown() function, so that the missile starts in the same location as the spaceship.
You have to position your bullets, rockets...etc. relative to your space ship's gun.
Imagine a gun that is mounted on the ship. You could represent this gun with an object.
For example:
public class Gun
{
private ISpaceshipDesign _spaceshipDesign;
public Gun(ISpaceshipDesign spaceshipDesign)
{
this._spaceshipDesign = spaceshipDesign;
}
public void Fire()
{
//...
}
}
Pass in a reference to your spaceship when creating the gun, so that you know onto which spaceship the gun is mounted.
The spaceship should always know where it is in the 2D-plane (X, Y coördinates). It should also know where on the spaceship the gun is mounted.
public interface ISpaceshipDesign
{
public Point GunLocation { get; }
}
The GunLocation property must return the gun's location relative to the ship's current position. For example:
public Point GunLocation
{
get
{
double x = (double) this.GetValue(Canvas.LeftProperty) + 21;
double y = (double) this.GetValue(Canvas.TopProperty) + 17;
return new Point(x, y);
}
}
You can then access this data in the Gun's Fire() method.
For example:
public void Fire()
{
Point gunLocation = _spaceshipDesign.GunLocation;
// Position your missle using the gun's current coördinates (X, Y).
}
About a year ago I wrote a 10-series part about creating a similar game (Asteroids) in Silverlight. One article discusses how to make the gun fire. You can find it here:
https://github.com/geersch/SilverlightAsteroids/blob/master/src/part-6/README.md
You can choose to mount several guns on the ship, one that fires regular bullets, another one for missles...etc. Each gun would have a different location on the ship. You can alter the Fire() method to be triggered by different keys (A = missle, space = bullets).
Hope this helps.