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);
}
}
Related
I am trying to simulate a LED display board with c# . I need a control which contains 1536 clickable controls to simulate LEDs (96 in width and 16 in Height). I used a panel named pnlContainer for this and user will add 1536 tiny customized panels at runtime. These customized panels should change their color by click event at runtime. Everything works . But adding this number of tiny panels to the container takes long time ( about 10 secs). What is your suggestion to solve this issue? Any tips are appreciated.
this is my custome panel:
public partial class LedPanel : Panel
{
public LedPanel()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (this.BackColor == Color.Black)
{
this.BackColor = Color.Red;
}
else
{
this.BackColor = Color.Black;
}
}
}
}
and this is piece of code which adds tiny panels to the pnlContainer :
private void getPixels(Bitmap img2)
{
pnlContainer.Controls.Clear();
for (int i = 0; i < 96; i++)
{
for (int j = 0; j < 16; j++)
{
Custom_Controls.LedPanel led = new Custom_Controls.LedPanel();
led.Name = i.ToString() + j.ToString();
int lWidth = (int)(pnlContainer.Width / 96);
led.Left = i * lWidth;
led.Top = j * lWidth;
led.Width = led.Height = lWidth;
if (img2.GetPixel(i, j).R>numClear.Value)
{
led.BackColor = Color.Red;
}
else
{
led.BackColor = Color.Black;
}
led.BorderStyle = BorderStyle.FixedSingle;
pnlContainer.Controls.Add(led);
}
}
}
Is there any better approach or better control instead of panelto do this?
I agree with what #TaW recommends. Don't put 1000+ controls on a form. Use some sort of data structure, like an array to keep track of which LEDs need to be lit and then draw them in the Paint event of a Panel.
Here's an example. Put a Panel on a form and name it ledPanel. Then use code similar to the following. I just randomly set the values of the boolean array. You would need to set them appropriately in response to a click of the mouse. I didn't include that code, but basically you need to take the location of the mouse click, determine which array entry needs to be set (or unset) and then invalidate the panel so it will redraw itself.
public partial class Form1 : Form
{
//set these variables appropriately
int matrixWidth = 96;
int matrixHeight = 16;
//An array to hold which LEDs must be lit
bool[,] ledMatrix = null;
//Used to randomly populate the LED array
Random rnd = new Random();
public Form1()
{
InitializeComponent();
ledPanel.BackColor = Color.Black;
ledPanel.Resize += LedPanel_Resize;
//clear the array by initializing a new one
ledMatrix = new bool[matrixWidth, matrixHeight];
//Force the panel to repaint itself
ledPanel.Invalidate();
}
private void LedPanel_Resize(object sender, EventArgs e)
{
//If the panel resizes, then repaint.
ledPanel.Invalidate();
}
private void button1_Click(object sender, EventArgs e)
{
//clear the array by initializing a new one
ledMatrix = new bool[matrixWidth, matrixHeight];
//Randomly set 250 of the 'LEDs';
for (int i = 0; i < 250; i++)
{
ledMatrix[rnd.Next(0, matrixWidth), rnd.Next(0, matrixHeight)] = true;
}
//Make the panel repaint itself
ledPanel.Invalidate();
}
private void ledPanel_Paint(object sender, PaintEventArgs e)
{
//Calculate the width and height of each LED based on the panel width
//and height and allowing for a line between each LED
int cellWidth = (ledPanel.Width - 1) / (matrixWidth + 1);
int cellHeight = (ledPanel.Height - 1) / (matrixHeight + 1);
//Loop through the boolean array and draw a filled rectangle
//for each one that is set to true
for (int i = 0; i < matrixWidth; i++)
{
for (int j = 0; j < matrixHeight; j++)
{
if (ledMatrix != null)
{
//I created a custom brush here for the 'off' LEDs because none
//of the built in colors were dark enough for me. I created it
//in a using block because custom brushes need to be disposed.
using (var b = new SolidBrush(Color.FromArgb(64, 0, 0)))
{
//Determine which brush to use depending on if the LED is lit
Brush ledBrush = ledMatrix[i, j] ? Brushes.Red : b;
//Calculate the top left corner of the rectangle to draw
var x = (i * (cellWidth + 1)) + 1;
var y = (j * (cellHeight + 1) + 1);
//Draw a filled rectangle
e.Graphics.FillRectangle(ledBrush, x, y, cellWidth, cellHeight);
}
}
}
}
}
private void ledPanel_MouseUp(object sender, MouseEventArgs e)
{
//Get the cell width and height
int cellWidth = (ledPanel.Width - 1) / (matrixWidth + 1);
int cellHeight = (ledPanel.Height - 1) / (matrixHeight + 1);
//Calculate which LED needs to be turned on or off
int x = e.Location.X / (cellWidth + 1);
int y = e.Location.Y / (cellHeight + 1);
//Toggle that LED. If it's off, then turn it on and if it's on,
//turn it off
ledMatrix[x, y] = !ledMatrix[x, y];
//Force the panel to update itself.
ledPanel.Invalidate();
}
}
I'm sure there can be many improvements to this code, but it should give you an idea on how to do it.
#Chris and #user10112654 are right.
here is a code similar to #Chris but isolates the displaying logic in a separate class. (#Chris answered your question when I was writing the code :))))
just create a 2D array to initialize the class and pass it to the Initialize method.
public class LedDisplayer
{
public LedDisplayer(Control control)
{
_control = control;
_control.MouseDown += MouseDown;
_control.Paint += Control_Paint;
// width and height of your tiny boxes
_width = 5;
_height = 5;
// margin between tiny boxes
_margin = 1;
}
private readonly Control _control;
private readonly int _width;
private readonly int _height;
private readonly int _margin;
private bool[,] _values;
// call this method first of all to initialize the Displayer
public void Initialize(bool[,] values)
{
_values = values;
_control.Invalidate();
}
private void MouseDown(object sender, MouseEventArgs e)
{
var firstIndex = e.X / OuterWidth();
var secondIndex = e.Y / OuterHeight();
_values[firstIndex, secondIndex] = !_values[firstIndex, secondIndex];
_control.Invalidate(); // you can use other overloads of Invalidate method for the blink problem
}
private void Control_Paint(object sender, PaintEventArgs e)
{
if (_values == null)
return;
e.Graphics.Clear(_control.BackColor);
for (int i = 0; i < _values.GetLength(0); i++)
for (int j = 0; j < _values.GetLength(1); j++)
Rectangle(i, j).Paint(e.Graphics);
}
private RectangleInfo Rectangle(int firstIndex, int secondIndex)
{
var x = firstIndex * OuterWidth();
var y = secondIndex * OuterHeight();
var rectangle = new Rectangle(x, y, _width, _height);
if (_values[firstIndex, secondIndex])
return new RectangleInfo(rectangle, Brushes.Red);
return new RectangleInfo(rectangle, Brushes.Black);
}
private int OuterWidth()
{
return _width + _margin;
}
private int OuterHeight()
{
return _height + _margin;
}
}
public class RectangleInfo
{
public RectangleInfo(Rectangle rectangle, Brush brush)
{
Rectangle = rectangle;
Brush = brush;
}
public Rectangle Rectangle { get; }
public Brush Brush { get; }
public void Paint(Graphics graphics)
{
graphics.FillRectangle(Brush, Rectangle);
}
}
this is how it's used in the form:
private void button2_Click(object sender, EventArgs e)
{
// define the displayer class
var displayer = new LedDisplayer(panel1);
// define the array to initilize the displayer
var display = new bool[,]
{
{true, false, false, true },
{false, true, false, false },
{false, false, true, false },
{true, false, false, false }
};
// and finally
displayer.Initialize(display);
}
I have 2 picture objects.
I want both of them to move from right to left.
If one go out of the visible panel, I replace its position to the start point.
So there are always 2 pictures moving on the screen.
If I don't use timer, 2 pictures are painted. But if I use a timer with tick event updating their positions to make them move, there is only 1 picture is shown and it's keep flashing, lagging...
Below is my code so far. I'm not familiar with C#. Appreciate any help. Thank you.
Timer interval = 30;
Form 1:
public partial class Form1 : Form
{
Background bg1 = new Background();
Background bg2 = new Background(800);
public Form1()
{
InitializeComponent();
}
private void flowLayoutPanel1_Paint(object sender, PaintEventArgs e)
{
bg1.paint(e);
bg2.paint(e);
}
private void Timer_Tick(object sender, EventArgs e)
{
bg1.updatePosition();
bg2.updatePosition();
this.Refresh();
}
}
Background:
class Background
{
int bg_width = 800;
int bg_height = 500;
Image bg;
Rectangle wb;
private static int x = 0;
public Background()
{
bg = Properties.Resources.bg;
wb = new Rectangle(x, 0, bg_width, bg_height);
}
public Background(int custom_x)
{
x = custom_x;
bg = Properties.Resources.bg;
wb = new Rectangle(x, 0, bg_width, bg_height);
}
public void paint(PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawImage(bg, wb);
}
public void updatePosition()
{
x--;
if (x == -800)
{
x = 801;
}
wb.Location = new Point(x, 0);
}
}
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();
I'm fairly new to OOP and am not sure how I would go about implementing something in my program. My program is pretty much similar to whack a mole and has an array of picture boxes with an image in and an image of a monster moves randomly between the picture boxes with a time interval applied or will move to a new random picture box whenever the user clicks on the monster in time. I have created an monster and a player sub class to try and add some OOP concepts to the program but am not sure how to implement what I want. Basically I have a label for score on my main form and a score variable in my animal class with a value. I want to be able to add the value of score from the label on my form when the user clicks on the picture box with the mole in and take away the value of score from the label when they don't click on it in time.
Here is my code:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
PictureBox[] boxes;
int initialscore = 0;
int time = 0;
int randPos;
public Form1()
{
InitializeComponent();
}
private void boxes_MouseClick(object sender, MouseEventArgs e)
{
PictureBox pb2 = new PictureBox() { Image = Image.FromFile("sword2.png") };
this.Cursor = new Cursor(((Bitmap)pb2.Image).GetHicon());
for (int x = 0; x < 27; x++)
{
if (sender.Equals(boxes[x]))
{
Image grass = Image.FromFile("swamp.png");
PictureBox temp = (PictureBox)sender;
temp.Image = grass;
}
if (sender.Equals(boxes[x]))
{
PictureBox pb = (PictureBox)sender;
if (pb.Tag == "skeleton.png")
initialscore++;
}
}
label1.Text = " Score: " +initialscore.ToString();
}
public void timer1_Tick(object sender, EventArgs e)
{
boxes[randPos].Image = Image.FromFile("swamp.png");
boxes[randPos].Tag = "swamp.png";
Random r = new Random();
randPos=r.Next(0, 27);
boxes[randPos].Image = Image.FromFile("skeleton.png");
boxes[randPos].Tag = "skeleton.png";
}
private void Form1_Load(object sender, EventArgs e)
{
boxes = new PictureBox[27];
int top = 100;
int left = 100;
for (int x = 0; x < 27; x++)
{
boxes[x] = new PictureBox();
boxes[x].Image = Image.FromFile("swamp.png");
boxes[x].Height = 100;
boxes[x].Width = 100;
if (x % 9 == 0)
{
top += 120;
left = 120;
}
else
left += 120;
boxes[x].Top = top;
boxes[x].Left = (50 + left);
Controls.Add(boxes[x]);
this.boxes[x].MouseClick += new
System.Windows.Forms.MouseEventHandler(this.boxes_MouseClick);
label1.Text = " Score: " + initialscore.ToString();
label2.Text = " Time: " + time.ToString();
}
}
}
namespace WindowsFormsApplication1
{
class Monster
{
protected int score;
public Monster()
{
score = 10;
}
}
}
namespace WindowsFormsApplication1
{
class Player:Monster
{
}
}
Nothing has been added in the player class yet.
What do I need to add or change to be able to get the initial score to change by the value of the score in the monster class when clicking on the moving image?
To unify the updating/incrementing and visualization of the score you should extract that to a method:
public void incrementScore(int increment)
{
initialscore += increment;
label1.Text = " Score: " + initialscore.ToString();
}
in the Form1_Load you call this like:
incrementScore(0);
for the click on the monster you have different possibilities:
if all the monsters have the same points you can make it a static variable in the Monster class.
protected static int Score = 10;
which allows you to use it in the boxes_MouseClick event handler:
incrementScore(Monster.Score);
in case all monsters have another value you have to hold the score variable as an instance variable, identify somehow the instance of the monster class you clicked on and increment with this value
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