Right now, I'm working on a little Jump'n'Run game in XNA. I decided to load textures from a tileset,
and designed a method for getting the source rectangles of a bigger rectangle. Within the method, the calculated rectangles are being added to a list, and the list is returned at the end of the method. However, the method doesn't seem to work properly. When trying to get a rectangle from a given index out of the list, I'm getting a index out of range exception. I tried this with several numbers, it still wont work. here is my method for getting the rectangles:
public static List<Rectangle> getSourceRectangles(Rectangle original, int partWidth, int partHeight)
{
List<Rectangle> rlist = new List<Rectangle>();
int ix, iy;
ix = original.Width / partWidth;
iy = original.Height / partHeight;
for (int x = 0; x < ix; x++)
{
for (int y = 0; y < iy; y++)
{
Rectangle r = new Rectangle(x * partWidth, y * partHeight, partWidth, partHeight);
rlist.Add(r);
}
}
return rlist;
}
I save the return value in a global Container class.
this is were I get the error: (ist just the constructor of the NormalTile class!)
public NormalTile(int _TextureIndex,Rectangle _rect)
{
this.rect = _rect;
this.TileTextureIndex = _TextureIndex - 1;
this.tex_rect = Global.TileTextures[TileTextureIndex];//HERE
}
Why is this even Happening?
Related
I have an image (attached) which I'm using as a test. I'm trying to get and store all the colours of each pixel in an array.
I use the below code to do this;
Texture2D tex = mapImage.mainTexture as Texture2D;
int w = tex.width;
int h = tex.height;
Vector4[,] vals = new Vector4[w, h];
Color[] cols = tex.GetPixels();
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
if(cols[y+x] != Color.black)
{
Debug.Break();
}
vals[x, y] = cols[(y + x)];
}
}
Where mapImage is a public Material variable which I drag in into the scene on the prefab. As you can see, I've added a debug test there to pause the editor if a non-black colour is reached. This NEVER gets hit ever.
Interestingly, I've got another script which runs and tells me the colour values (GetPixel()) at the click position using the same image. It works fine (different methods, but both ultimately use the same material)
I'm at a loss as to why GetPixels() is always coming out black?
I've also been considering just loading the image data into a byte array, then parsing the values into a Vector4, but hoping this will work eventually.
You aren't indexing into the Color array properly. With the indices you are using, y+x, you keep checking the same values on the lowest rows of the texture, never getting past a certain point.
Instead, when calculating the index, you need to multiply the row that you are on by the row length and add that to the column you are on:
Texture2D tex = mapImage.mainTexture as Texture2D;
int w = tex.width;
int h = tex.height;
Vector4[,] vals = new Vector4[w, h];
Color[] cols = tex.GetPixels();
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
int index = y * w + x;
vals[x, y] = cols[index];
}
}
From the documentation on GetPixels:
The returned array is a flattened 2D array, where pixels are laid out left to right, bottom to top (i.e. row after row). Array size is width by height of the mip level used. The default mip level is zero (the base texture) in which case the size is just the size of the texture. In general case, mip level size is mipWidth=max(1,width>>miplevel) and similarly for height.
I want to highlight overlapped text from PDF. Got all words coordinates using "PDFExchangeviewer.exe" and then converted to dot.net rectangle. In dotnet rectangle found intersection of rectangle and highlighted the intersected words using itextsharp. But it highlighting unwanted words in PDF rather than overlapped text. Please post solution to this. Below shown is my part of the code in c#
foreach (var pdfrect in WordpageCoordinates)
{
float X = (float)pdfrect.Item1;
float Y = reader.GetPageSize(pdfPg).Top - (float)pdfrect.Item4;
float Width = (float)pdfrect.Item3 - X;
float Height = (float)(pdfrect.Item4) - (float)(pdfrect.Item2);
DotNetRect.Add(new System.Drawing.RectangleF(X, Y, Width, Height));
}
for(int j = 0; j < DotNetRect.Count; j++)
{
System.Drawing.RectangleF MasterRect = DotNetRect[j];
System.Drawing.RectangleF ChildRect = new System.Drawing.RectangleF();
if (j == DotNetRect.Count - 1)
{
break;
}
for (int k = j + 1; k < DotNetRect.Count; k++)
{
ChildRect = DotNetRect[k];
System.Drawing.RectangleF NewRect = new System.Drawing.RectangleF(ChildRect.X, ChildRect.Y , ChildRect.Width, ChildRect.Height);
if (MasterRect.IntersectsWith(NewRect))
{
{
iTextSharp.text.Rectangle Annotrect = new iTextSharp.text.Rectangle((float)WordpageCoordinates[k].Item1, (float)WordpageCoordinates[k].Item2, (float)WordpageCoordinates[k].Item3, (float)WordpageCoordinates[k].Item4);
//iTextSharp.text.Rectangle Annotrect = new iTextSharp.text.Rectangle((float)ClsGlobal.TextCoordinatesList[k].Item1, (float)ClsGlobal.TextCoordinatesList[k].Item2, (float)ClsGlobal.TextCoordinatesList[k].Item3, (float)ClsGlobal.TextCoordinatesList[k].Item4);
//float[] quad = { Annotrect.Left, Annotrect.Bottom, Annotrect.Right, Annotrect.Bottom, Annotrect.Left, Annotrect.Top, Annotrect.Right, Annotrect.Top };
float[] quad = { Annotrect.Left, Annotrect.Top, Annotrect.Right, Annotrect.Top, Annotrect.Left, Annotrect.Bottom, Annotrect.Right, Annotrect.Bottom };
PdfAnnotation HighlightAnnotation = PdfAnnotation.CreateMarkup(pdfstamper.Writer, Annotrect, "Text Overlap", PdfAnnotation.MARKUP_HIGHLIGHT, quad);
HighlightAnnotation.Title = "Overlap Text Highlighter\n" + System.DateTime.Now.ToString();
HighlightAnnotation.Color = iTextSharp.text.BaseColor.GREEN;
pdfstamper.AddAnnotation(HighlightAnnotation, pdfPg);
}
}
}
}
You are testing whether 2 Rectangles intersect, but you are not working with the intersection. Take the intersection for the annotation. The intersection is the overlapping part.
RectangleF intersection = RectangleF.Intersect(MasterRect, NewRect);
With this static method RectangleF.Intersect Method (RectangleF, RectangleF):
public static RectangleF Intersect(
RectangleF a,
RectangleF b
)
There is no need to create a copy of ChildRect. IntersectsWith only tests for an intersection but does not create one and does not change the rectangle. Since RectangleF is a struct and therefore a value type, a copy of it is passed to the method anyway. If it was a class, i.e. a reference type, the method could theoretically change its fields and properties.
Intersect returns an empty rectangle if there is no intersection. Therefore, you could also first create the intersection and then test if it is not empty instead of using IntersectsWith.
RectangleF intersection = RectangleF.Intersect(MasterRect, ChildRect);
if (!intersection.IsEmpty)
{
// create the annotation with `intersection`
}
Instead of writing
if (j == DotNetRect.Count - 1)
{
break;
}
change the loop condition to (added - 1):
for(int j = 0; j < DotNetRect.Count - 1; j++)
I am generating rectangles with given random numbers in this class.
class Rect
{
double x;
double y;
public Rect(double _x, double _y)
{
x = _x;
y = _y;
}
public void Draw()
{
Gl.glBegin(Gl.GL_QUADS);
Gl.glVertex2d(x + (-0.05d), y + (-0.05d));
Gl.glVertex2d(x + (-0.05d), y + (0.05d));
Gl.glVertex2d(x + (0.05d), y + (0.05d));
Gl.glVertex2d(x + (0.05d), y + (-0.05d));
Gl.glEnd();
}
}
I call it in Paint function.
private void simpleOpenGlControl1_Paint(object sender, PaintEventArgs e)
{
Gl.glClearColor(0, 1, 0, 0);
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);
for (int i = 0; i < 4; i++)
{
rand = new Random();
double x = 2 * rand.NextDouble() - 1;
double y = 2 * rand.NextDouble() - 1;
rect= new Rect(x,y);
rect.Draw();
}
}
Everything looks fine but there is something wrong. I cant see the all rectangles. Some of them are missing. But if I toggle breakpoint somewhere or put the MessageBox.Show(x+" "+y); code works fine and shows me the number of rectangles what i want. I think my code is true but something wrong about OpenGL. I am using Tao Framework.
My guess is the problem is with this bit of code:
for (int i = 0; i < 4; i++)
{
rand = new Random();
double x = 2 * rand.NextDouble() - 1;
double y = 2 * rand.NextDouble() - 1;
rect= new Rect(x,y);
rect.Draw();
}
You are creating a new Random instance in every iteration of your loop and then use that instance to generate two random values. The sequence of values generated by Random depends on the seed that was used to initialize the Random. According to the documentation of the constructor used here:
The default seed value is derived from the system clock and has finite
resolution.
That is, if your loop runs fast enough, the different instances of Random in your loop will be initialized with the same seed, causing them to generate the same x and y values: the rectangles then overlap and appear to be missing. This also explains why your code is working if you interrupt it using breakpoints or messages boxes.
Edit: the best solution to this problem is to create a single Random instance outside of your loop, by initializing rand before your for statement or (as a class member) in the constructor of your class for example.
So, I'm trying to make a small program that generates chunks, as in 2 Texture2Ds'. I Made another class called Terrain_Plains.
Constructor (you can guess I already made the variables):
public Terrain_Plains(Texture2D chunkSprite, int y)
{
chunks = chunkSprite;
this.y = y;
//Load drawRectangle
drawRectangle = new Rectangle(0, y, 50, 50);
}
Then I made a draw method:
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(chunks, drawRectangle, Color.White);
}
I made an array with the Terrain_Plains in the Game1 method:
Terrain_Plains[] terrain = new Terrain_Plains[2];
And then initialized it using a for loop.
Everything went as expected except one thing: It wasn't showing the 2nd Terrain_Plains.
How can I make them both side-by-side, without having to make another Rectangle? Reason I want to only use one Rectangle is because I want to add more than just 2 Terrain_Plains
EDIT FOR Preston Guillot:
for loop used to initialize array:
for (int i = 0; i < 2; i++)
{
terrain[i] = new Terrain_Plains(sprite, WINDOW_HEIGHT - 50);
}
for loop to draw the array:
for (int i = 0; i < 2; i++)
{
terrain[i].Draw(spriteBatch);
}
So what I'm trying to do is create like a random image from panels of different colors. The user can choose how many panels (i.e. pixels) he wants to have and the number of different colors and then the program automatically generates that image. I'd really like to use panels for this because I will need this picture later on and need to modify every single pixel. As I'm comfortable with panels, I'd like to keep them and not use anything else.
So here's the code I'm using to create this panels:
//Creates two lists of panels
//Add items to list so that these places in the list can be used later.
//nudSizeX.Value is the user-chosen number of panels in x-direction
for (int a = 0; a < nudSizeX.Value; a++)
{
horizontalRows.Add(null);
}
//nudSizeY.Value is the user-chosen number of panels in y-direction
for (int b = 0; b < nudSizeY.Value; b++)
{
allRows.Add(null);
}
for (int i = 0; i < nudSizeY.Value; i++)
{
for (int j = 0; j < nudSizeX.Value; j++)
{
// new panel is created, random values for background color are assigned, position and size is calculated
//pnlBack is a panel used as a canvas on whoch the other panels are shown
Panel pnl = new Panel();
pnl.Size = new System.Drawing.Size((Convert.ToInt32(pnlBack.Size.Width)) / Convert.ToInt32(nudSizeX.Value), (Convert.ToInt32(pnlBack.Size.Height) / Convert.ToInt32(nudSizeY.Value)));
pnl.Location = new Point(Convert.ToInt32((j * pnl.Size.Width)), (Convert.ToInt32((i * pnl.Size.Height))));
//There are different types of panels that vary in color. nudTypesNumber iis the user-chosen value for howmany types there should be.
int z = r.Next(0, Convert.ToInt32(nudTypesNumber.Value));
//A user given percentage of the panels shall be free, i.e. white.
int w = r.Next(0, 100);
if (w < nudPercentFree.Value)
{
pnl.BackColor = Color.White;
}
//If a panel is not free/white, another rendom color is assigned to it. The random number determinig the Color is storede in int z.
else
{
switch (z)
{
case 0:
pnl.BackColor = Color.Red;
break;
case 1:
pnl.BackColor = Color.Blue;
break;
case 2:
pnl.BackColor = Color.Lime;
break;
case 3:
pnl.BackColor = Color.Yellow;
break;
}
}
//Every panel has to be added to a list called horizontal rows. This list is later added to a List<List<Panel>> calles allRows.
horizontalRows[j] = (pnl);
//The panel has also to be added to the "canvas-panel" pnl back. The advantage of using the canvas panel is that it is easier to determine the coordinates on this panel then on the whole form.
pnlBack.Controls.Add(pnl);
}
allRows[i] = horizontalRows;
}
As you might imagine, this is very slow when creating a checkerboard of 99x99 because the program has to loop through the process nearly 10000 times.
What would you to to improve performance? I said I'd like to keep doing it with panels because I'm comfortable with them, but if using panels is even more dumb than I thought, I'm open to other options. The program gets slower and slower the more panels it has already created. I guess that's because of the adding to the list that grows larger and larger?
This is how the output looks right now:
This is what I want to do with my "picture" later: I basically want to do Schellings model. That model shows how different groups of people (i.e. different colors) segregate when they want to have a certain percentage of people around them that belong to their group. That means that later on I have to be able to check for each of the panels/pixels what the neighbours are and have to be able to be able to change color of each pixel individually.
I don't want a ready solution, I'm just hoping for tips how to improve the speed of the picture-creating process.
Thank you very much
Instead of using Panels use a matrix to store your colors and other information you need.
In OnPaint event, use this matrix to draw the rectangles using GDI+.
Here is an example on how to draw 10x10 "pixels" if you have a matrix that contains colors:
private void myPanel_Paint(object sender, PaintEventArgs e)
{
for (var y=0; y < matrix.GetUpperBound(0); y++)
for (var x=0; x < matrix.GetUpperBound(1); x++)
{
var Brush = new SolidBrush(matrix[y,x]);
e.Graphics.FillRectangle(Brush, new Rectangle(x*10, y*10, 10, 10));
}
}
Use a picturebox to do your drawing. You've already got the code to see where each panel should be, just change it to draw a rectangle at each position. This way, you'll just be drawing a few rectangles on a board instead of working with 10.000 GUI objects.
Oh, keep your model/logic and view separated. Keep one matrix with all your information and just use a "Paint method" to draw it.
Your model could look something like this:
MyPanel[,] panels;
class MyPanel
{
Color color;
}
This way it's easy to check all neighbours of a panel, just check in the panels matrix.
And your view should just do something like this:
class View
{
Paint(MyPanel[,] panels)
{
//Draw
}
}
I think your best approach here is to write a custom Control class to draw the squares, and a custom collection class to hold the squares.
Your square collection class could look like this:
public sealed class ColouredSquareCollection
{
readonly int _width;
readonly int _height;
readonly Color[,] _colours;
public ColouredSquareCollection(int width, int height)
{
_width = width;
_height = height;
_colours = new Color[_width, _height];
intialiseColours();
}
public Color this[int x, int y]
{
get { return _colours[x, y]; }
set { _colours[x, y] = value; }
}
public int Width
{
get { return _width; }
}
public int Height
{
get { return _height; }
}
void intialiseColours()
{
for (int y = 0; y < _height; ++y)
for (int x = 0; x < _width; ++x)
_colours[x, y] = Color.White;
}
}
Then you write a custom control. To do so, add a new Custom control via Add new item -> Windows Forms -> Custom Control, and call it ColouredSquareHolder.
Then change the code to look like this. Notice how it is responsible for drawing all the squares:
public sealed partial class ColouredSquareHolder: Control
{
ColouredSquareCollection _squares;
public ColouredSquareHolder()
{
ResizeRedraw = true;
DoubleBuffered = true;
InitializeComponent();
}
public ColouredSquareCollection Squares
{
get
{
return _squares;
}
set
{
_squares = value;
Invalidate(); // Redraw after squares change.
}
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
if (_squares == null)
return;
int w = Width;
int h = Height;
int nx = _squares.Width;
int ny = _squares.Height;
var canvas = pe.Graphics;
for (int yi = 0; yi < ny; ++yi)
{
for (int xi = 0; xi < nx; ++xi)
{
int x1 = (xi*w)/nx;
int dx = ((xi + 1)*w)/nx - x1;
int y1 = (yi*h)/ny;
int dy = ((yi+1)*h)/ny - y1;
using (var brush = new SolidBrush(_squares[xi, yi]))
canvas.FillRectangle(brush, x1, y1, dx, dy);
}
}
}
}
Now you'll need to set up the square collection, add it to a ColouredSquareHolder and then add that to a form.
Firstly, add the ColouredSquareHolder to your test program and compile it so that it will show up in the Toolbox for the Windows Forms Editor.
Then create a new default Form called Form1, and from the Toolbox add a ColouredSquareHolder to it, and set the ColouredSquareHolder to Dock->Fill. Leave it called the default colouredSquareHolder1 for this demonstration.
Then change your Form1 class to look like this:
public partial class Form1: Form
{
readonly ColouredSquareCollection _squares;
readonly Random _rng = new Random();
public Form1()
{
InitializeComponent();
_squares = new ColouredSquareCollection(100, 100);
for (int x = 0; x < _squares.Width; ++x)
for (int y = 0; y < _squares.Height; ++y)
_squares[x, y] = randomColour();
colouredSquareHolder1.Squares = _squares;
}
Color randomColour()
{
return Color.FromArgb(_rng.Next(256), _rng.Next(256), _rng.Next(256));
}
}
Run your program and see how much faster it is at drawing the squares.
Hopefully this will give you the basis for something that you can build on.
Note: If you change the colours in the square collection, you will need to call .Invalidate() on the control in the form to make it redraw with the new colours.
well I suggest you using GDI+ instead , you can store your colors in a 2 dimensional array so you can draw the desired image based on that and also you can loop through them for further process , take a look at this code and also the demo project :
as you mentioned that you're not familiar with gdi+ , there is a demo project included so you can check it yourself and see how It's done in gdi+ :
demo project : ColorsTableDemoProject
Color[,] colorsTable;
Bitmap b;
Graphics g;
int size = 80; // size of table
int pixelWidth = 5; // size of each pixel
Random r = new Random();
int rand;
// CMDDraw is my Form button which draws the image
private void CMDDraw_Click(object sender, EventArgs e)
{
colorsTable = new Color[size, size];
pictureBox1.Size = new Size(size * pixelWidth, size * pixelWidth);
b = new Bitmap(size * pixelWidth, size * pixelWidth);
g = Graphics.FromImage(b);
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
rand = r.Next(0, 4);
switch (rand)
{
case 0: colorsTable[x, y] = Color.White; break;
case 1: colorsTable[x, y] = Color.Red; break;
case 2: colorsTable[x, y] = Color.Blue; break;
case 3: colorsTable[x, y] = Color.Lime; break;
default: break;
}
g.FillRectangle(new SolidBrush(colorsTable[x, y]), x * pixelWidth, y * pixelWidth, pixelWidth, pixelWidth);
}
}
pictureBox1.Image = b;
}