Interchange two PictureBoxes - c#

I'm trying to make the game 2048 in C#, but I have a problem when I move the tiles.
Here is where I keep the tiles:
picture = new PictureBox[4, 4] {
{pic1,pic2,pic3,pic4},
{pic5,pic6,pic7,pic8},
{pic9,pic10,pic11,pic12},
{pic13,pic14,pic15,pic16} };
And when I press 'W' I move it up :
public void Up()
{
for (int i = 1; i < picture.GetLength(0); i++)
for (int j = 0; j < picture.GetLength(1); j++)
if(picture[i,j].Image!=null && picture[i-1,j].Image==null)
{
picture[i - 1, j].Image = picture[i, j].Image;
picture[i, j].Image = null;
Up();
}
}
but that code only interchanges images from picturebox not the picturebox itself. How can I interchange the picturebox with image and all its property ?

There is no switching functionality in C#, so you will need a temporary helper variable.
It is up to you to decide what you want to switch:
the pictureBoxes referenced in your array
just their locations
their images
or any combination..
Here is an example of a simple helper function that exchanges the references and their Locations:
void SwitchControls(PictureBox pb1, PictureBox pb2)
{
PictureBox temp = pb1;
Point tempLoc = pb1.Location;
pb1 = pb2;
pb2 = temp;
pb1.Location = pb2.Location;
pb2.Location = tempLoc ;
}
You would call it for example like this:
SwitchControls(picture[i - 1, j], picture[i, j]);
To exchange the Images you would write the function as
void SwitchImages(PictureBox pb1, PictureBox pb2)
{
Image temp = pb1.Image;
pb1.Image = pb2.Image;
pb2.Image = temp.Image;
}
etc..

Related

When I make a matrix of points in form_load it works, but when i make it in a separate class, and make an object of it in form_load it doesn`t work

So I need to make a matrix of points to spread buttons over an area, I wanted to make a class that has the matrix itself because the buttons wont appear on screen all the time and they will move in the grid etc.
anyway, here`s what the constructor for that class does:
public Table()
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
_Grid[i, j] = new Point(i * 90, j * 90);
}
}
}
90 is the width of the buttons
then I have a property that allows getting the grid:
public Point[,] Grid
{
get;
}
then i do the form_load like this:
private void Form1_Load(object sender, EventArgs e)
{
Table tab = new Table();
Point[,] grid = tab.Grid;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
Button btn = new Button();
btn.Width = 88;
btn.Height = 88;
btn.Location = grid[i, j]; // it returns a NullReferernceException here
panel1.Controls.Add(btn);
}
}
}
adding the location gives me a nullreference, but if i copy the code from the constructor and make the grid matrix in form_load get it, it works.(button width and height is 88 so there`s a nice little space between the buttons)
im obviously still learning, and you can see im stuck in the very beginning of this project because i cant even make all the buttons appear where they should.
It's quite a guess, but I suspect you've done something like this in Table
private Point[,] _Grid = new blahblahblah
public Point[,] Grid
{
get;
}
These two things are not referring to the same thing in memory - you've filled _Grid and it's valid object, but the property Grid is referencing some invisible backing store variable created by the compiler; having a name that is similar is not enough to wire them together
Change Table to be like:
public Point[,] Grid { get; } = new blahblahblah
Delete any mention of _Grid in favor of Grid
Change the constructor so it sets up the array via the property (thus writing values into the invisible backing field created by the compiler):
Grid[i, j] = new Point(i * 90, j * 90);
And then retrieving tab.Grid will retrieve a populated thing that is not null
Footnote, we name private members like _camelCase, not _PascalCase and if you want to explicitly declare a read only property that gets a class member field, it would look like:
private Point[,] _grid = blahblahblah;
public Point[,] Grid { get { return _grid; }}
Or:
private Point[,] _grid = blahblahblah;
public Point[,] Grid { get => _grid; }
i.e. you have to concretely wire them together by having the prop go and get that field by name, and return it
We can get into "properties should not return arrays" another time :D

How to delete image created with code and how to interact with it at all

I am working on a game. For this game i create around 200 images in a box 20x10.
My problem is that pressing 1 button creates them a lot of times which garbages the Memory, which i want to avoid. So i created a little if/else function which is supposed to check wether the images were created or not. In case they weren't, code creates them, but if they were, the code should delete them, and i have no idea how to delete code generated images or how to interract with them at all.
public void GameStart(bool load = false)
{
Random rnd = new Random();
Pause.IsEnabled = true;
Save.IsEnabled = true;
Shuffle.IsEnabled = true;
byte datasave = 0;
int[,] TileID = new int[20,10];
for(int i = 0; i < 20; i++)
{
for(int j = 0; j < 10; j++)
{
if(TileID[i,j] != 0)
{
datasave = 1;
}
TileID[i, j] = rnd.Next(1,9);
CreateImage(i, j, TileID[i,j], datasave);
}
}
}
public void CreateImage(int a, int b, int TileID, byte datainfo)
{
if(datainfo != 0)
{
Image image = new Image();
image.Width = 40;
image.Height = 40;
image.Name = $"Tile{a}{b}";
image.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
image.VerticalAlignment = System.Windows.VerticalAlignment.Center;
image.Margin = new Thickness(-1000 + 80 * a, -200 + 80 * b, 0, 0);
string way = #"C:\Users\ignat\Desktop\Игра\Images\";
image.Source = new BitmapImage(new Uri(way + $"icon{TileID}.jpg", UriKind.Absolute));
Grid.Children.Add(image);
}
else
{
CreateImage(a, b, TileID, datainfo);
}

Change picture in grid on click in c#

I've filled grid with Images in code and I'm tryig to add mouse events to them
public FilesWindow()
{
InitializeComponent();
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
Image image = new Image();
image.MouseRightButtonDown += new MouseButtonEventHandler(setPicture);
myGrid.Children.Add(image);
image.Source = new BitmapImage(randomPic());
Grid.SetRow(image, i);
Grid.SetColumn(image, j);
}
}
}
private void setPicture(object sender, MouseButtonEventArgs e)
{
}
but I don't know how to access this specyfic Image (the one I click). Clicking itself (ex. with writing on console) is working but how to change picture in a cell that was clicked?
You can cast sender (which is type object) to Image:
Image image = (Image)sender;

C# WPF - Not all images show up on grid

I can't load all grid spots with images at once. I have a 5x5 grid and it is intended to load 25 random images in random spots. With 25 images it should fill out the entire grid.
I can't figure out why there are empty spots when I load 25 or when I load less. I'm having one image repeat itself throughout the entire grid in order to avoid image format related issues. I think the problem might be related to the Random class.
Here is the code:
private readonly Random _r = new Random();
public void LoadPictures(int numberOfPictures)
{
// Create a 2d array of specified dimensions
var picArr = new bool[5, 5];
for (int j = 0; j < numberOfPictures; j++)
{
// Get the images from the specified folder
string[] imagePaths = Directory.GetFiles(
Environment.CurrentDirectory + "/images");
bool invalidPlacement = true; // default is true
while (invalidPlacement)
{
var i = new Image();
try
{
// Load the image with a random Picture
var uri = new Uri(imagePaths[_r.Next(0, imagePaths.Length)]);
i.Source = new BitmapImage(uri);
Debug.WriteLine(uri.AbsolutePath);
i.Width = ImageWidth;
i.Height = ImageHeight;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
// Put it somewhere
int row = _r.Next(5);
Thread.Sleep(TimeSpan.FromMilliseconds(50));
int col = _r.Next(5);
// Check to see if there is something there
if (picArr[col, row] == false)
{
picArr[col, row] = true;
Grid.SetColumn(i, col);
Grid.SetRow(i, row);
Background2.Children.Add(i);
AnimateControl(i, 100, 100, 0, 0);
invalidPlacement = false;
}
}
}
}

Multiply images boxes

I have a simple form with 10 picture boxes like: pictureBox1, pictureBox2, pictureBox3...
And I have a folder with 10 images like: image1, image2, image3...
Now I am smart enough to know that I don't want to hard code pictureBox1.ImageLocation = image1, pictureBox2.ImageLocation = image2... Rather, I need to create some kind of loop or array that will populate my picture boxes with their respective images, but I am not smart enough to figure out how.
Something like:
for (int i = 0; i < 10; i++)
{
pictureBox[i].ImageLocation = image[i];
}
Eventually, I was hoping this project would scale dynamically, if I have a file with say 12 images, the program will simply create 12 picture boxes and load the images. A little help would be great.
What you have there would roughty work though I would suggest a list.
List<PictureBox> pictureBoxes = new List<PictureBox>();
List<Image> images = new List<Image>();
//code to populate your lists
for (int i = 0; i < pictureBoxes.Count; i++)
{
pictureBoxes[i].Image = images[i];
}
If you want to make sure you have enough images for your PictureBox list you could check ahead of time:
if (images.Count >= pictureBoxes.Count)
{
for (int i = 0; i < pictureBoxes.Count; i++)
{
pictureBoxes[i].Image = images[i];
}
}
...or fill out as many as you can before running out of images.
for (int i = 0; i < pictureBoxes.Count && i < images.Count; i++)
{
pictureBoxes[i].Image = images[i];
}
EDIT:
So if you want to use strings to set the location of the images instead you can do that. Check this out:
List<PictureBox> pictureBoxes = new List<PictureBox>();
List<string> imageLocations = new List<string>();
private void Form1_Load(object sender, EventArgs e)
{
PictureBox PB1 = new PictureBox();
PB1.Location = new Point(0, 0);
PB1.Size = new Size(144, 197);
Controls.Add(PB1);
PictureBox PB2 = new PictureBox();
PB2.Location = new Point(145, 0);
PB2.Size = new Size(327, 250);
Controls.Add(PB2);
pictureBoxes.Add(PB1);
pictureBoxes.Add(PB2);
imageLocations.Add(#"C:\PicExample\image1.jpg");
imageLocations.Add(#"C:\PicExample\image2.jpg");
for (int i = 0; i < pictureBoxes.Count && i < imageLocations.Count; i++)
{
pictureBoxes[i].ImageLocation = imageLocations[i];
}
}
EDIT for Iteratively Creating PictureBoxe List:
If you want to not have to worry about hard-coding your list (and your picture boxes will be the same size) you could do something like this:
for (int i = 0; i < HoweverManyPictureBoxesYouWant; i++)
{
PictureBox PB = new PictureBox();
PB.Name = "PB" + i.ToString();
PB.Location = new Point(250 * i, 0); //Edit this as you see fit for location, i'm just putting them in a row
PB.Size = new Size(250, 250);
PB.ImageLocation = #"C:\PicExample\image" + i.ToString() + ".jpg";
Controls.Add(PB);
pictureBoxes.Add(PB); //You only need to do this if you want the PB's in a list for other reasons than setting the image location
}

Categories