I'm trying to make a little game in C# using WPF. In one of my Modelclasses I have a Map, which is a 2D-array filled with Enumeration objects. Each of these objects represents a type of tile.
In my View these Tiles need to be converted to an Image and the image needs to be set to the right coordinates in the Grid.
How do I bind the array to the Grid or the Images in the view so that it will auto-update when the array changes?
This how it works now:
Enumeration that's used to fill the array:
public enum Tile { FLOOR, WALL, DESTINATION, EMPTY }
Method to create and position all the Images (this is in the code-behind):
public void LoadMap(Map mapModel)
{
Tile[,] tiles = mapModel.TileMap;
int nRows = tiles.GetLength(1);
int nCols = tiles.GetLength(0);
for (int i = 0; i < nCols; i++)
{
ColumnDefinition col = new ColumnDefinition();
map.ColumnDefinitions.Add(col);
}
for (int i = 0; i < nRows; i++)
{
RowDefinition row = new RowDefinition();
map.RowDefinitions.Add(row);
}
for (int y = 0; y < nCols; y++)
{
for (int x = 0; x < nRows; x++)
{
Image img = new Image();
switch (tiles[y, x])
{
case Tile.FLOOR:
img.Source = _srcFloor;
break;
case Tile.WALL:
img.Source = _srcWall;
break;
case Tile.DESTINATION:
img.Source = _srcDestination;
break;
case Tile.EMPTY:
img.Source = _srcEmpty;
break;
}
img.SetValue(Grid.ColumnProperty, x);
img.SetValue(Grid.RowProperty, y);
map.Children.Add(img);
}
}
}
XAML:
<Grid Name="map">
</Grid>
And here is a screenshot of how it looks:
Related
I'm coming from Winforms trying to rewrite a program in WPF, and I want to display a certain portion of the whole image, depending on an Id I use for a list, that I load each portion of the whole image in. I was able to do it successfully in Winforms, but I want to perform the same task in WPF using Controls.Image. Heres what I did in Winforms.
PictureBox picBox;
List<Image> tileImageList;
Image FullImage;
public TileFrame(PictureBox pbox)
{
picBox = pbox;
FullImage = picBox.Image; //The source of the picBox is set to the full image on init
tileImageList = new List<Image>();
PopTileList();
}
void PopTileList()
{
const int SIZE = 32;
Bitmap bitFullImage = new Bitmap(FullImage);
for (int y = 0; y < 48; y++)
{
for (int x = 0; x < 64; x++)
{
var portion = bitFullImage.Clone(new Rectangle((x * SIZE), (y * SIZE), SIZE, SIZE), bitFullImage.PixelFormat);
tileImageList.Add(portion);
}
}
picBox.Image = tileImageList[10];//The first image that shows when this is done
}
public void ShowTilePic(int selectedId)
{
picBox.Image = tileImageList[--selectedId];
}
Since the image being displayed will change based on the selected item of a listbox, the tileImageList is crucial for relating the list box selected index and the tileImageList index. Other answers I've searched for seemed to make it much more complicated than what I've done here. Is there a simple way to do this in WPF and in code?
Nvm I figured it out.
List<CroppedBitmap> tileImageList;
Image imageBox;
public TileFrame(MainWindow mWindow)
{
tileImageList = new List<CroppedBitmap>();
imageBox = mWindow.ImageBox;
PopTileList();
}
void PopTileList()
{
const int SIZE = 32;
var bitmapImage = (BitmapSource)imageBox.Source;
for (int y = 0; y < 48; y++)
{
for (int x = 0; x < 64; x++)
{
var portion = new CroppedBitmap(bitmapImage, new Int32Rect((x * SIZE), (y * SIZE), SIZE, SIZE));
tileImageList.Add(portion);
}
}
}
public void ShowTilePic(int selectedId)
{
imageBox.Source = tileImageList[selectedId];
}
I have a 2D array that contains rectangles. They are stored in a dynamic UniformGrid. How do I find out which rectangle in the array was MouseDown?
I tried this but I keep getting [0,0]:
if (e.OriginalSource is Shape s)
{
cellRow = (int)s.GetValue(Grid.RowProperty);
cellColumn = (int)s.GetValue(Grid.ColumnProperty);
rectangle[cellRow,cellColumn].Fill = new SolidColorBrush(Colors.Black);
}
And this is how I generated the rectangles:
rectangle = new Rectangle[rowcol, rowcol];
for (int x = 0; x < rowcol; x++)
{
for (int y = 0; y < rowcol; y++)
{
rectangle[y, x] = new Rectangle { Stroke = Brushes.Black, StrokeThickness = 0.5, Fill = Brushes.White };
GameUniformGrid.Children.Add(rectangle[y, x]);
}
}
The MouseDown event in xaml:
<UniformGrid x:Name="GameUniformGrid" HorizontalAlignment="Left" Height="272" VerticalAlignment="Top" Width="272" Grid.Row="0" Grid.Column="0" Rectangle.MouseDown="ToggleGrid"/>
I think the problem is with initializing a rectangle,
When you work with multidimentional array you have some rows and column and what you are doing is using row only in both row,column.
What if rowcol =0 ? the loop will not run because this condition.
x < rowcol (0<0);
You should
rectangle = new Rectangle[row, col];
for (int x = 0; x < row; x++)
{
for (int y = 0; y < col; y++)
{
rectangle[y, x] = new Rectangle { Stroke = Brushes.Black, StrokeThickness = 0.5, Fill = Brushes.White };
GameUniformGrid.Children.Add(rectangle[y, x]);
}
}
(For example)
where row = 2 ,col =2
So I have a code that injects an image into my project through resources Image foodWorld = Resources.orange and I want to make a matrix out of this photo, so it can look like this:
I have this code but I don't know how to draw the matrix. Also, I don't know if this is the right way to draw it or not:
this.Width = 400;
this.Height = 300;
Bitmap b = new Bitmap(this.Width, this.Height);
for(int i = 0; i < this.Height; i++)
{
for(int j = 0; j < this.Width; j ++)
{
//fill the matrix
}
}
I am not too familiar with WinForms, but in WPF, I'd do it this way:
var columns = 15;
var rows = 10;
var imageWidth = 32;
var imageHeight = 32;
var grid = new Grid();
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
//Get the image in your project; I'm not sure how this is done in WinForms
var b = new Bitmap(imageWidth, imageHeight);
//Display it
var pictureBox = new PictureBox();
pictureBox.Image = b;
//Set the position
Grid.SetColumn(j, pictureBox);
Grid.SetRow(i, pictureBox);
//Insert into the "matrix"
grid.Children.Add(pictureBox);
}
}
For moving Pacman, repeat the above, but for only one image. Store a reference to the current position and when certain keys are pressed,
Animate it's margin until it appears to be in an adjacent cell (for instance, if each cell is 16 pixels wide and pacman should be in the center of any given cell, animate the right margin by 16 pixels to get it into the cell on the right and so forth).
Once it has moved to another cell, set the new row and column based on the direction in which it last moved.
If there is a fruit at the new position, get the fruit at that position and remove it from the Grid. You can get it by using myGrid.Children[currentRow * totalColumns + currentColumn] assuming currentRow and currentColumn are both zero-based.
Repeat for each cell it must move to.
This does mean the matrix will have a fixed size, but in WPF, there is a Viewbox, which is convenient for these types of scenarios. Also, set the z-index of pacman to be greater than the fruits so it's always on top.
In C#, I need to convert an image that I have already converted to Bitmap in to a matrix of the size of the image's width and height that consists of the uint8 of the Bitmap data. In another word placing the Bitmap data inside of a matrix and converting them to uint8, so I can do the calculations that I am intended to do on the matrix rows and column.
Try something like this:
public Color[][] GetBitMapColorMatrix(string bitmapFilePath)
{
bitmapFilePath = #"C:\9673780.jpg";
Bitmap b1 = new Bitmap(bitmapFilePath);
int hight = b1.Height;
int width = b1.Width;
Color[][] colorMatrix = new Color[width][];
for (int i = 0; i < width; i++)
{
colorMatrix[i] = new Color[hight];
for (int j = 0; j < hight; j++)
{
colorMatrix[i][j] = b1.GetPixel(i, j);
}
}
return colorMatrix;
}
What I am trying to do is check an image row or column, and if it contains all white pixels then trim that row or column.
I am not sure why, but when I run this code snippet, img.Width in TrimLeft is 1, before subtracting 1 from it.
The actual image width is 175. I end up with an ArgumentException. I have a similar method for trimming the right side, and that works fine.
class ImageHandler
{
public Bitmap img;
public List<int[]> pixels = new List<int[]>();
public ImageHandler(String path)
{
img = new Bitmap(path);
GetPixels();
}
public void TrimLeft()
{
while (CheckColIfWhite(0, 0))
{
Rectangle cropBox = new Rectangle(1, 0, (img.Width-1), img.Height);
Bitmap cropdImg = CropImage(img, cropBox);
img = cropdImg;
}
}
public bool CheckColIfWhite(int colx, int starty)
{
bool allPixelsWhite = false;
int whitePixels = 0;
for (int y = starty; y < img.Height; y++)
{
if (pixels[y][colx] >= 200) { whitePixels++; }
else { return false; }
if (whitePixels == img.Height) { allPixelsWhite = true; }
}
return allPixelsWhite;
}
public void GetPixels()
{
for (int y = 0; y < img.Height; y++)
{
int[] line = new int[img.Width];
for (int x = 0; x < img.Width; x++)
{
line[x] = (int) img.GetPixel(x, y).R;
}
pixels.Add(line);
}
}
public Bitmap CropImage(Bitmap tImg, Rectangle area)
{
Bitmap bmp = new Bitmap(tImg);
Bitmap bmpCrop = bmp.Clone(area, bmp.PixelFormat);
return bmpCrop;
}
}
Your method seems like it will be remarkably inefficient - if the image is 175 pixels wide, and entirely white, you're going to create 175 copies of it, before (probably) failing when trying to create a 0 pixel wide image.
Why not examine each column in turn until you find a non-white column, and then perform a single crop at that time. Untested code, and with other changes hopefully obvious:
public Bitmap CropImage (Bitmap image)
{
int top = 0;
int bottom = image.Height-1;
int left = 0;
int right = image.Width-1;
while(left < right && CheckColIfWhite(image,left))
left++;
if(left==right) return null; //Entirely white
while(CheckColIfWhite(image,right)) //Because left stopped, we know right will also
right--;
while(CheckRowIfWhite(image,top))
top++;
while(CheckRowIfWhite(image,bottom))
bottom--;
return CropImage(image,new Rectangle(left,top,right-left+1,bottom-top+1));
}
(E.g. I'm now passing the image around, I've modified CheckColIfWhite and CheckRowIfWhite to take the image also, and to assume that one parameter is always fixed at 0)
Also, not sure why you're extracting the pixel array beforehand, so I'm putting my re-written CheckColIfWhite too:
public bool CheckColIfWhite(Bitmap image,int colx)
{
for (int y = 0; y < image.Height; y++)
{
if (image.GetPixel(colx,y).R < 200)
return false;
}
return true;
}