I have some problems with collision. I want to ge coords of a sprite that can be rotated scaled or whatever. It's similiar to Riemers guide, but he's getting a collision of two sprites and I only need those points where alpha is zero.
Better see source:
public Color[,] TextureTo2DArray(Texture2D texture) // to get color array
{
Color[] colors1D = new Color[texture.Width * texture.Height];
texture.GetData(colors1D);
Color[,] colors2D = new Color[texture.Width, texture.Height];
for (int x = 0; x < texture.Width; x++)
for (int y = 0; y < texture.Height; y++)
colors2D[x, y] = colors1D[x + y * texture.Width];
return colors2D;
}
With color is pretty easy, but here is the part where I get points:
public Vector2 TexturePos(Color[,] Color, Matrix matrix)
{
int width1 = Color.GetLength(0);
int height1 = Color.GetLength(1);
for (int x = 0; x < width1; x++)
{
for (int y = 0; y < height1; y++)
{
Vector2 pos1 = new Vector2(x, y);
if (Color[x, y].A > 0)
{
Vector2 screenPos = Vector2.Transform(pos1, matrix);
return screenPos;
}
}
}
return new Vector2(-1, -1);
}
And for matrix I'm using this:
Matrix matrix =
Matrix.CreateTranslation(new Vector3(origin, 0)) *
Matrix.CreateRotationZ(MathHelper.ToRadians(rotation))*
Matrix.CreateScale(scale) *
Matrix.CreateTranslation(new Vector3(pos, 0));
Sprite is rectangular but i get circular movement: I'm rotating it (rotation += 0,5), adding gravity and making it collide with some y value:
Pos.Y += 5;
if (Position.Y >= 200)
BoxPos.Y -= 5;
And I get that it rotates as a circle colliding a line, but not as a rectangle.
Is this normal? Maybe I need some fixes in source?
"That method is supposed to get a position of a pixel (in sprite) that is not transperent but is rotated, scaled (depending on sprite)."
You need to have a look at this:
http://create.msdn.com/en-US/education/catalog/tutorial/collision_2d_perpixel_transformed
This is a great article about 2D collisions in XNA and has an example method that performs 2D collision detection for a Scaled & Rotated set of sprites.
Related
I am using Unity 5 to create an isometric game. I have generated a grid of tiles and it works well. However, when I use two different tiles to fill in the grid (their image sizes are slightly different), I get gaps in between the tiles. The obvious solution would be to create the tiles so that they are all the same image size, but this would prevent me from creating anything on a tile that is larger than the size of a tile (eg. a tree).
Here are some images to demonstrate:
With only one type of tile:
With two types of tile:
This is the code I use to create the map:
private void CreateMap() {
float tileWidth;
float tileHeight;
int orderInLayer = 0;
SpriteRenderer r = floorTiles [0].GetComponent<SpriteRenderer> ();
tileWidth = r.bounds.max.x - r.bounds.min.x;
tileHeight = r.bounds.max.y - r.bounds.min.y;
for (int i = 0; i < map.GetLength(0); i++) {
orderInLayer += 1;
for (int j = 0; j < map.GetLength (1); j++) {
Vector2 position = new Vector2 ((j * tileWidth / 2) + (i * tileWidth / 2) + (tileWidth / 2), (j * tileHeight / 2) - (i * tileHeight / 2) + (tileHeight/ 2));
r = map[i,j].GetComponent<SpriteRenderer>();
r.sortingOrder = orderInLayer;
Instantiate(map[i, j], position, Quaternion.identity);
}
}
}
Any help would be greatly appreciated, I cannot seem to fix it!
You appear to be calculating a position for each of your tiles from scratch every time you create one. If you have 2 different sized tiles, then your calculation comes out different, hence the gaps in your tiles. This is because you're only using the width/height of the current tile, failing to take into account any previous tiles that may be a shorter/longer height/width.
Given you have varying heights AND widths you'll need a way to calculate the correct position for both to prevent gaps in the X and Y direction. I've mocked up something here, but it's untested. More of a concept(?) I guess.
float tileHeight = 0;
float tileWidth = 0;
Vector2 position = new Vector2(0,0);
Dictionary<int, float> HeightMap = new Dictionary<int, float>();
for (int iRow = 0; iRow < map.GetLength(0); iRow++)
{
position.x = 0;
orderInLayer += 1;
for (int jColumn = 0; jColumn < map.GetLength (1); jColumn++)
{
position.y = HeightMap[jColumn];
r = map[iRow, jColumn].GetComponent<SpriteRenderer>();
tileWidth = r.bounds.max.x - r.bounds.min.x;
tileHeight = r.bounds.max.y - r.bounds.min.y;
r.sortingOrder = orderInLayer;
position.x += tileWidth / 2;
position.y += tileHeight / 2;
Instantiate(map[iRow, jColumn], position, Quaternion.identity);
HeightMap[jColumn] = position.y;
}
}
I leave the best way of storing the height, or instantiating the contents of the HeightMap dictionary to however you see fit.
I wanted to know if writing points using a for loop in the begin end batch works or not, so I read up on a sphere algorithm and produced this based on my reading. There are some problems with it as you can see below in the output screen capture. My goal is to produce a sphere procedurally and then modify it at runtime.
but I would like to set my goal on the short-term and figure out why the faces are not correct. anyone have any ideas?
I've got this code:
private void openGLControl_OpenGLDraw(object sender, RenderEventArgs e)
{
// Get the OpenGL object.
OpenGL gl = openGLControl.OpenGL;
// Clear the color and depth buffer.
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
// Load the identity matrix.
gl.LoadIdentity();
// Rotate around the Y axis.
gl.Rotate(rotation, 0.0f, 1.0f, 0.0f);
//Draw a ball
//Drawing Mode
gl.PolygonMode(SharpGL.Enumerations.FaceMode.FrontAndBack, SharpGL.Enumerations.PolygonMode.Lines);
//ball fields
double radius = 4.0d;
const double DEGREE = Math.PI/11.25;
double x = 0;
double y = 0;
double z = 0;
// ball batch
gl.Begin(OpenGL.GL_TRIANGLE_STRIP_ADJACENCY);
for (double j = 0.0d; j < Math.PI; j = j +DEGREE)
{
for (double i = 0; i < 2 * Math.PI; i = i + DEGREE)
{
x = radius * Math.Cos(i) * Math.Sin(j);
y = radius * Math.Sin(j) * Math.Sin(i);
z = radius * Math.Cos(j);
gl.Color(Math.Abs(x + y), Math.Abs(y + z), Math.Abs(z + x));
gl.Vertex(x, y, z);
}
}
gl.End();
// Nudge the rotation.
rotation += 3.0f;
}
I have pixel-perfect collision down, but it only works with the texture rotated at 0 radians. Here is my code for determining the pixel-perfect collision-
public static bool IntersectPixels(Texture2D sprite, Rectangle rectangleA, Color[] dataA, Texture2D sprite2, Rectangle rectangleB, Color[] dataB)
{
sprite.GetData<Color>(dataA);
sprite2.GetData<Color>(dataB);
// Find the bounds of the rectangle intersection
int top = Math.Max(rectangleA.Top, rectangleB.Top);
int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
int left = Math.Max(rectangleA.Left, rectangleB.Left);
int right = Math.Min(rectangleA.Right, rectangleB.Right);
// Check every point within the intersection bounds
for (int y = top; y < bottom; y++)
{
for (int x = left; x < right; x++)
{
// Get the color of both pixels at this point
Color colorA = dataA[(x - rectangleA.Left) + (y - rectangleA.Top) * rectangleA.Width];
Color colorB = dataB[(x - rectangleB.Left) + (y - rectangleB.Top) * rectangleB.Width];
// If both pixels are not completely transparent,
if (colorA.A != 0 && colorB.A != 0)
{
// then an intersection has been found
return true;
}
}
}
// No intersection found
return false;
}
I am having trouble with my collision when it is rotated. How would I go about checking pixel collision with a rotated sprite? Thanks, any help is appreciated.
Ideally, you can exress all transformations with a matrix. That shouldn't be a problem with the helper methods. And if you use matrices, you can easily extend the program without having to change the collision code. Up to now, you can represent a translation with the position of the rectangle.
Let's assume object A has the transformation transA and object B has transB. Then you would iterate over all pixels of object A. If the pixel is not transparent, check which pixel of object B is at this very position and check if this pixel is transparent.
The tricky part is determining which pixel of object B is at a given position. This can be achieved with some matrix math.
You know the position in the space of object A. Firstly, we want to transform this local position to a global position on the screen. This is exactly what transA does. After that, we want to transform the global location to a local location in the space of object B. This is the inverse of transB. So, we have to transform the local position in A with the following matrix:
var fromAToB = transA * Matrix.Invert(transB);
//now iterate over each pixel of A
for(int x = 0; x < ...; ++x)
for(int y = 0; y < ...; ++y)
{
//if the pixel is not transparent, then
//calculate the position in B
var posInA = new Vector2(x, y);
var posInB = Vector2.Transform(posInA, fromAToB);
//round posInB.X and posInB.Y to integer values
//check if the position is within the range of texture B
//check if the pixel is transparent
}
I've been trying to combine a couple of riemers tutorials to make a terrain that is textured and lit. I'm almost there but I can't get the application of the texture right. I believe the problem is in SetUpVertices() with the setting of the texture coordinates. I know currently the code reads that they're all set to (0, 0) and I need to have it so that they are set to the corners of the texture but I can't seem to get the code right. Anybody out there able to assist?
private void SetUpVertices()
{
vertices = new VertexPositionNormalTexture[terrainWidth * terrainHeight];
for (int x = 0; x < terrainWidth; x++)
{
for (int y = 0; y < terrainHeight; y++)
{
vertices[x + y * terrainWidth].Position = new Vector3(x, -y, heightData[x, y]);
vertices[x + y * terrainWidth].TextureCoordinate.X = 0;
vertices[x + y * terrainWidth].TextureCoordinate.Y = 0;
}
}
}
I've added the full code of Game1.cs to this pastie http://pastebin.com/REd8QDZA
You can stretch the texture across the surface by interpolating from 0 to 1:
vertices[x + y * terrainWidth].TextureCoordinate.X = x / (terrainWidth - 1.0);
vertices[x + y * terrainWidth].TextureCoordinate.Y = y / (terrainHeight - 1.0);
Okay, I have a 2d Tile Map editor I'm working on in xna c#.
In the Draw method I loop through (with a 'for' loop) my 2 dimensional array of tiles so that
my map updates and draws all the tiles every frame.
My question is, how do you draw only the tiles that are seen on screen.
Also is there a better way to draw the tile map (Rather than updating every frame).
In the platformer demo I played around with the visible tiles were calculated and then only those tiles were drawn. I believe you will have to include them in the draw method to be drawn in each time.
Here is a snippet (this only had left to right scrolling so no vertical range was calculated). This kept track of the camera position to calculate it.
Edit:: Added the second method shows how it updated camera position based on the player position stored in a player object.
private void DrawTiles(SpriteBatch spriteBatch)
{
// Calculate the visible range of tiles.
int left = (int)Math.Floor(cameraPosition / Tile.Width);
int right = left + spriteBatch.GraphicsDevice.Viewport.Width / Tile.Width;
right = Math.Min(right, Width - 1);
// For each tile position
for (int y = 0; y < Height; ++y)
{
for (int x = left; x <= right; ++x)
{
// If there is a visible tile in that position
Texture2D texture = tiles[x, y].Texture;
if (texture != null)
{
// Draw it in screen space.
Vector2 position = new Vector2(x, y) * Tile.Size;
spriteBatch.Draw(texture, position, Color.White);
}
}
}
}`
private void ScrollCamera(Viewport viewport)
{
const float ViewMargin = 0.35f;
// Calculate the edges of the screen.
float marginWidth = viewport.Width * ViewMargin;
float marginLeft = cameraPosition + marginWidth;
float marginRight = cameraPosition + viewport.Width - marginWidth;
// Calculate how far to scroll when the player is near the edges of the screen.
float cameraMovement = 0.0f;
if (Player.Position.X < marginLeft)
cameraMovement = Player.Position.X - marginLeft;
else if (Player.Position.X > marginRight)
cameraMovement = Player.Position.X - marginRight;
// Update the camera position, but prevent scrolling off the ends of the level.
float maxCameraPosition = Tile.Width * Width - viewport.Width;
cameraPosition = MathHelper.Clamp(cameraPosition + cameraMovement, 0.0f, maxCameraPosition);
}
int MapSizeX = 20;
int MapSizeY = 20;
int LeftCornerX = 0; //the position of the Tile in the 2Darray that is going
int LeftCornerY = 0; //to be drawn in the left corner of the screen.
int ScreenSizeX = 10;
int ScreenSizeY = 10;
public Tiles[,] tiles = new Tile[MapSizeX, MapSizeY]; //list of all Tiles
//then you can draw it like this....
int counterX = 0; //represents the position on screen
int counterY = 0;
// y and x inside the for loops represents the position in tiles
for(int y = LeftCornerY; y < MapSizeY < y++)
{
for(int x = LeftCornerX; y < MapSizeX < x++)
{
if(counterX < ScreenSizeX && counterY < ScreenSizeY)
{
tiles[x, y].draw(tiles[counterX , counterY]);
}
counterX ++;
//when you do like this you draw the tiles you want
//at the position you want. In the draw method you just
// drawn the tile you want at the position of the tile you
// send as in parameter to the draw method.
}
counterY++;
counterX = 0;
}
then you just have to increase the LeftCorner variables to draw another part of the map