Removing Elements Programmatically in Silverlight - c#

I am starting to learn silverlight and to practice I am doing a simple space invaders type videogame.
My issue is I am creating custom controls (bullets) programmatically like so:
if(shooting)
{
if(currBulletRate == bulletRate)
{
Bullet aBullet = new Bullet();
aBullet.X = mouse.X - 5;
aBullet.Y = mouse.Y - Ship.Height;
aBullet.Width = 10;
aBullet.Height = 40;
aBullet.Tag = "Bullet";
LayoutRoot.Children.Add(aBullet);
currBulletRate = 0;
}
else
currBulletRate++;
}
However I am having trouble removing them once they go off bounds (leave the LayoutRoot).
I tried looping throught the LayoutRoot.Children and removing but I can't seem to get it right.

UIElement[] tmp = new UIElement[LayoutRoot.Children.Count];
LayoutRoot.Children.CopyTo(tmp, 0);
foreach (UIElement aElement in tmp)
{
Shape aShape = aElement as Shape;
if (aShape != null && aShape.Tag != null)
{
if (aShape.Tag.ToString().Contains("Bullet"))
{
if (Canvas.GetTop(aShape) + aShape.ActualHeight < 0) // This checks if it leaves the top
{
LayoutRoot.Children.Remove(aElement);
}
else if(Canvas.GetTop(aShape) > Canvas.ActualHeight) // This condition checks if it leaves the bottom
{
LayoutRoot.Children.Remove(aElement);
}
}
}
}
The code you pasted was only checking if the bullet left the top of the canvas.

Related

Take the full path waypoints of a railway

I'm developing a Train Valley game, just like 2D. The construction of the railway is different. I have a grid and I can take a rail and put it somewhere in the grid and so the railway is built. The main problem I am facing is that I do not know how to create the way for the train to follow .... each sine has a point, this point I add in a Vector3 type list, but if I jump over a cell and put there sine , then go back to the skipped cell and put the rail there, then the list will no longer be sorted.
I'm attaching code, but it's a lot. In general, if anyone has any idea how to build this path, the train will run correctly by all means.
void Start()
{
foreach (TrainCell cell in Grid)
cell.gameObject.AddComponent<TrainCellMouseEvent>().MouseEvent += OnCellClickEvent;
MouseEventProccessor.Instance.captureMouseMouveEvents = true;
StartCoroutine(SpawnStations());
}
private void OnCellClickEvent(TrainCell target, MouseEventType type)
{
if (type == MouseEventType.CLICK)
{
if (canDestroy)
{
if ((int)target.CurrentChildIndex != 0)
{
target.CurrentChild.GetComponent<PolygonCollider2D>().enabled = false;
target.setCurrentChildIndex(0);
Instantiate(BoomFX, target.transform.position, Quaternion.identity);
target.used = false;
WayPoints.Remove(target.transform.position);
if (BuildDone != null)
BuildDone(price, false);
}
foreach (TrainCell cell in Grid)
{
if (!cell.underBuilding)
{
if (cell.CurrentChildIndex == 0 && cell.used)
cell.used = false;
}
}
return;
}
if (rail.SelectedRail == null || target.used || outOfGridBounds)
return;
int railIndex = (int)rail.SelectedRail.GetComponent<ObjectSequence>().CurrentChildIndex;
target.setCurrentChildIndex(railIndex + 1);
target.CurrentChild.GetComponent<PolygonCollider2D>().enabled = true;
MouseEventProccessor.Instance.captureMouseMouveEvents = true;
SpriteRenderer render = target.CurrentChild.GetComponent<SpriteRenderer>();
render.color = Vector4.one;
target.used = true;
if (BuildDone != null)
BuildDone(price, true);
if (target.CurrentChild.transform.childCount == 0)
WayPoints.Add(target.transform.position);
else
{
for (int i = 0; i < target.CurrentChild.transform.childCount; i++)
WayPoints.Add(target.CurrentChild.transform.GetChild(i).transform.position);
}
}
else if (type == MouseEventType.OVER)
{
if (mainLevel.isHammer)
{
if (target.CurrentChildIndex != 0)
target.CurrentChild.GetComponent<SpriteRenderer>().color = Color.red;
return;
}
if (rail.SelectedRail == null || target.used)
return;
foreach (TrainCell cell in Grid)
{
if (cell.CurrentChildIndex != 0)
{
if (cell != target)
{
if (cell.CurrentChild.GetComponent<SpriteRenderer>().color != Color.white && !cell.used && !cell.underBuilding)
{
if (cell.GetComponentInChildren<ObjectSequenceNumberDisplay>() != null)
Destroy(GetComponentInChildren<ObjectSequenceNumberDisplay>().gameObject);
cell.setCurrentChildIndex(0);
}
}
}
}
int railIndex = (int)rail.SelectedRail.GetComponent<ObjectSequence>().CurrentChildIndex;
target.setCurrentChildIndex(railIndex + 1);
RenderColor(target);
}
else if (type == MouseEventType.EXIT)
{
if (target.CurrentChildIndex != 0)
target.CurrentChild.GetComponent<SpriteRenderer>().color = Color.white;
if (shapePrice != null)
Destroy(shapePrice.gameObject);
if (target.used)
return;
target.setCurrentChildIndex(0);
}
}
As far as I suppose based on your code I'll try to answer your question based on the following statements:
You have a station where you generate the train
You define a direction for the train to follow from the station (left, right, up, down) depending on the railway design
Having that statements I propose the following solution:
Create a method that takes the station point as the origin and the starting direction from that point. Having that you start following the railway, first on that direction and after that you search in 4 directions for more rails, adding all of them to the Vector3 array. This way you will have the array sorted.
Example:
private void SortedRailway(Vector2 origin, Vector2? direction = null, Vector2? lastDirection = null){
if(direction.HasValue){
if(origin + direction is TrainCell){
WayPoints.add(origin + direction);
SortedRailway(origin + direction, null, direction);
}
//(else will be used if direction (just used for the initial one) is wrong, so error there)
}else{
if(origin + Vector2.up is TrainCell && Vector2.up != lastDirection){
WayPoints.add(origin + Vector2.up);
SortedRailway(origin + Vector2.up, null, Vector2.down); //lastDirection is always the opposite to the matching one
}
//... (Repeat for all 4 directions. If none fits, then we asume is the end of the railway)
}
}
Hope this helps you!

Get rectangles from the Canvas

I am working on a windows phone project. I would like to use a function for my collision.
this is the code I use:
foreach (Rectangle mrec in mCanvas.Children)
{
if (my_ellipse.Margin.Top + my_ellipse.Height > mrec.Margin.Top && my_ellipse.Margin.Top <= mrec.Margin.Top + mrec.Height && my_ellipse.Margin.Left + my_ellipse.Width >= mrec.Margin.Left && my_ellipse.Margin.Left <= mrec.Margin.Left + mrec.Width)
{
my_ellipse.Fill = new SolidColorBrush(Colors.Green);
}
else
{
my_ellipse.Fill = new SolidColorBrush(Colors.White);
}
}
But when I use this, the foreach loop does not only grabs the Rectangle elements. It also grabs the TextBlock and the Ellipse.
I hope somebody can help me with this problem.
The problem here is that Children contains objects that are not of type Rectangle your foreach is attempting to cast each item in Children to Rectangle. Instead you need to test if each item is a Rectangle first.
foreach (var child in mCanvas.Children)
{
Rectangle mrec = child as Rectangle;
if(mrec != null)
{
// Your logic here
}
}
Alternatively you can use Enumerable.OfType to do the filtering.
foreach (Rectangle mrec in mCanvas.Children.OfType<Rectangle>())
{
// Your logic here
}

Check if Picturebox touches any object on screen C#

I have a problem with my game that is coded on C#. I've tried searching all over the forums for this problem but none has worked for this case :/
I'm trying to check if Picturebox hits ANY other Picturebox in screen.
I've tried this, but this might be too slow when I add more objects.
if (!square.Bounds.IntersectsWith(grass.Bounds) && !square.Bounds.IntersectsWith(grMiddle.Bounds) && !square.Bounds.IntersectsWith(grRight.Bounds) && !square.Bounds.IntersectsWith(middle.Bounds) && !square.Bounds.IntersectsWith(sideRight.Bounds) && !square.Bounds.IntersectsWith(topPanel.Bounds))
This method doesn't work since player movement increases 100x and I die instantly, somehow...
foreach (PictureBox pic in this.Controls.OfType<PictureBox>())
{
if (pic != square) // exclude square PictureBox from the test
{
if (!square.Bounds.IntersectsWith(pic.Bounds))
{
if (!square.Bounds.IntersectsWith(rightGoal.Bounds))
{
if (Right) { square.Left += 5; }
if (Left) { square.Left -= 5; }
if (Up) { square.Top -= 5; }
if (Down) { square.Top += 5; }
}
else
{
pally.points++;
rightPoints.Text = pally.points.ToString();
square.Location = new Point(690, 533);
}
}
else
{
square.Location = new Point(690, 533);
}
}
}
I'm out of ideas, some help would be nice :)
if (Right) { square.Left += 5; }
if (Left) { square.Left -= 5; }
if (Up) { square.Top -= 5; }
if (Down) { square.Top += 5; }
Are these testing keyboard inputs or something? You're moving your square with this code. And you're doing it for each picturebox on your form. That's why your square moves too far. Separating your position updating code from your intersection code should solve your problem.

Remove controls of flowlayoutpanel and recreating it in C#

I had been experimenting on writing a code to generate images inside a FlowLayoutPanel.
This is what i had done so far, when i click on a button for the first time (by using a checkboxes - read in number of images to open), it will generate the images, when i click on the button on second try, it will not update the flowlayoutpanel.
Even though i tried to remove the controls inside the FlowLayoutPanel, it still doesn't show the second try of the images.
This is the code snippet of the method:
FlowLayoutPanel fwPanel = null;
private void btnOpenFile_Click(object sender, EventArgs e)
{
//if there is content inside the flowpanel, dump it
if (fwPanel != null)
{
listOfFile.Clear();
}
//create a new FLP
fwPanel = new FlowLayoutPanel();
int panelWidth = width * 4 + 50;
int panelHeight = height * 4 + 50;
fwPanel.Size = new Size(panelWidth, panelHeight);
fwPanel.Location = new Point(0, 0);
this.Controls.Add(fwPanel);
//each checked item would be stored into an arraylist
foreach(object itemChecked in clbFile.CheckedItems)
{
listOfFile.Add((clbFile.Items.IndexOf(itemChecked)+1).ToString());
}
int noOfCheckedFile = listOfFile.Count;
PictureBox[] listOfPicture = new PictureBox[noOfCheckedFile];
int positionX = 0, positionY = 0;
int maxPaddingX = (width * MATRIX_SIZE) - 1;
int maxPaddingY = (height * MATRIX_SIZE) - 1;
//dynamically create images.
for (int i = 0; i < noOfCheckedFile; i++)
{
listOfPicture[i] = new PictureBox();
listOfPicture[i].Image = resizeImage((Image)show_picture(Convert.ToInt32(listOfFile[i])), new Size(width, height));
listOfPicture[i].Size = new Size(width, height);
if (positionX > maxPaddingX)
{
positionX = 0;
positionY += height;
}
if (positionY > maxPaddingY)
{
positionY = 0;
}
listOfPicture[i].Location = new Point(positionX,positionY);
listOfPicture[i].Visible = true;
fwPanel.Controls.Add(listOfPicture[i]);
positionX += width;
}
}
show_picture is a method that takes in and integer and returns a bitmap image.
listOfFile is to trace which file to return.
listOfPicture is to store each images.
i tried replacing this lines
//if there is content inside the flowpanel, dump it
if (fwPanel != null)
{
listOfFile.Clear();
}
i have added this line into it, when i do a second click, everything just gone missing, but this is not what i want, because it does not re-populating the FlowLayoutPanel.
if (fwPanel != null)
{
fwPanel.SuspendLayout();
if (fwPanel.Controls.Count > 0)
{
for (int i = (fwPanel.Controls.Count - 1); i >= 0; i--)
{
Control c = fwPanel.Controls[i];
c.Dispose();
}
GC.Collect();
}
fwPanel.ResumeLayout();
listOfFile.Clear();
}
I also tried this, but on second click, nothing will happen.
if (fwPanel != null)
{
List<Control> listControls = fwPanel.Controls.Cast<Control>().ToList();
foreach (Control control in listControls)
{
fwPanel.Controls.Remove(control);
control.Dispose();
}
listOfFile.Clear();
}
I wonder if i miss out anything, can someone enlighten me on what did i miss out ? Or guide me for the best practice of doing this.
as Suggested, i shifted the creation outside (credit to Sinatr for spotting it)
FlowLayoutPanel fwPanel = new FlowLayoutPanel();
private void createFLP()
{
int panelWidth = width * 4 + 50;
int panelHeight = height * 4 + 50;
fwPanel.Size = new Size(panelWidth, panelHeight);
fwPanel.Location = new Point(0, 0);
this.Controls.Add(fwPanel);
}
that solves the nothing happen part. Followed by using this to remove controls
if (fwPanel != null)
{
List<Control> listControls = fwPanel.Controls.Cast<Control>().ToList();
foreach (Control control in listControls)
{
fwPanel.Controls.Remove(control);
control.Dispose();
}
listOfFile.Clear();
}
and everything works like a charm, hope that this answer will be able to help others who are facing the same problem too.

checking a color of a button and changing it using a 2D array

I'm creating a small game just like the game Reversi/Othello I have managed to created a 2x3 board with buttons.
The buttons change colour ones you click on them but I'm having trouble to detect if there is a white colour in between 2 black colours and if so change that white colour into black.. I hope this make sense. the buttons are in a 2D array. Any suggestions that could help me do this would be much appreciated.
The image:
Here is my code:
![namespace reversitest
{
public partial class Form1 : Form
{
private Button\[,\] squares;
public Form1()
{
InitializeComponent();
squares = new Button\[3, 2\];
squares = new Button\[,\] {{button1, button2, button3},
{button4, button5, button6,}};
}
private void Form1_Load(object sender, EventArgs e)
{
foreach (Button sqrr in squares)
{
sqrr.Click += new System.EventHandler(this.DrawCharacter);
}
}
int _turn = 0;
private void DrawCharacter(object sender, EventArgs e)
{
Button sqrr = (Button)sender;
int col = 0;
if (sqrr.BackColor.Equals(Color.Black) || sqrr.BackColor.Equals(Color.White))
{
MessageBox.Show("Move Not Allowed!");
}
else
{
for ( int i = 0; i < squares.GetLongLength(1); ++i)
{
// check othere squares and change color
if (i < 2)
{
for (int f = 0; f < 3; ++f)
{
var ss = squares\[i, f\];
if (ss.BackColor.Equals(Color.Black))
{
MessageBox.Show("we have a black");
//ss = squares\[i, f+1\];
ss.BackColor = Color.Black;
}
else
{
MessageBox.Show("no black");
}
}
}
if (_turn == 0)
{
_turn = 1;
sqrr.BackColor = Color.Black;
}
else
{
_turn = 0;
sqrr.BackColor = Color.White;
}
}
}
}
}
}
First name your buttons with the array index. It will help you to find the button.
For example according to you picture button1 name would be btn_1_1.
Then inside your button click event first get the button name and then identify the button positioned.
Button b = sender as Button;
string[] btnData = b.Name.Split('_');
int x = int.Parse(btnData[1]);
int y = int.Parse(btnData[2]);
//check for possible combinations
int top = y - 2;
int botton = y + 2;
int left = x - 2;
int right = x + 2;
if (top >= 0 && squares[top, y].Background == Color.Black)
{
squares[top+1, y].Background = Color.Black;
}
...
...
Continue like that. If you need more detail please free to ask.
Final Answer
//check for possible combinations
int top = x - 2;
int botton = x + 2;
int left = y - 2;
int right = y + 2;
if (top >= 0 && squares[top, y].BackColor == Color.Black)
{
squares[top + 1, y].BackColor = Color.Black;
}
else if (left >= 0 && squares[x, left].BackColor == Color.Black)
{
squares[x, left + 1].BackColor = Color.Black;
}
else if (left >= 0 && squares[x, left].BackColor == Color.Black)
{
squares[x, left + 1].BackColor = Color.Black;
}
Will be extended for a 8x8 board later on
Do you need it to be elegant? A kind of brute force method: You could check for pieces in the 8 different directions it is possible for them to be aligned. So for example, you start with a black piece. Check the next piece over in one direction. If it's white, keep going and take a note of the position that was white so you can change it to black later. When you finally hit a black piece, change all the stored positions to black and move on to the next direction and repeat the process until you've done all 8 directions.

Categories