Tilemap Index out of bounds collision - c#

I created my tile map and my player with movement.
I'm now trying to create the collision and I feel i'm on the right track.
Here is how I've created the map.
List<Texture2D> tileTextures = new List<Texture2D>();
int tileWidth = 60;
int tileHeight = 60;
public int[,] Map = new int[,]
{
{2,2,2,2,2,2,2,2,2,2},
{2,2,2,2,1,2,2,2,2,2},
{2,2,2,2,2,2,2,2,2,2},
{2,2,2,2,2,2,2,2,2,2},
};
public void Draw(SpriteBatch spriteBatch)
{
int tileMapWidth = Map.GetLength(1);
int tileMapHeight = Map.GetLength(0);
for (int x = 0; x < tileMapWidth; x++)
{
for (int y = 0; y < tileMapHeight; y++)
{
int textureIndex = Map[y, x];
Texture2D texture = tileTextures[textureIndex];
spriteBatch.Draw(
texture,
source = new Rectangle(x *myTile.Width,
y * myTile.Height,
tileWidth,
tileHeight),
Color.White);
}
}
}
I am checking the 2d array coords with this condition and checking to see if a specific tile is there, where I can then set my previous location if it is true.
I'm currently testing on 1 tile atm.
public void Update(GameTime gameTime)
{
prevPosition = position;
input(gameTime);
if(tiles.Map[(int)playerPosition.X/60,(int)playerPosition.Y/60] == 1)
{
position = prevPosition;
}
}
However my player position keeps going out of the index bounds of the 2D array and I believe I need to scale it down so that it stops this, I've tried dividing the play coords by the width of the tiles but that hasn't worked.
If anyone can help me with the correct scaling I would be very appreciative.

This will happen if your player's position is like -x,y or x,-y or maybe -x,-y. Yor approach might be better if you'd make a fuction like this one
public bool CollidesWithWall(int x, int y)
{
if(x < 0 || x > *matrix width* - 1) return false;
if(y < 0 || y > *matrix height* -1) return false;
if (Map[x,y] == 1) return true;
return false;
}
and use it insead of the line tiles.Map[(int)playerPosition.X/60,(int)playerPosition.Y/60]
Or, if you need the type of tile returned
public int CollidesWithWall(int x, int y)
{
if(x < 0 || x > *matrix width* - 1) return -1;
if(y < 0 || y > *matrix height* -1) return -1;
return Map[x,y];
}
By doing it this way, you'll know if you stumbled upon a health potion (just set it's ID to like 3) or a wall (with ID of 1 or something, that's tottaly up to you) and if it is 0, it's empty space (or maybe -1). Notice that the "-1" part is totaly up to you. Just write down a list of id's that youll have and which items they present.
Other suggestions
Try if(tiles.Map[(int)(playerPosition.X/60f),(int)(playerPosition.Y/60f)] == 1)

Related

How can I make a hole at a specific place using script (unity)

I am working on making a hole in the terrain in real-time with a mouse click. I found this script which allows the user to raise terrain at a circle shape with a mouse click and I tried to add the code to generate a hole to it like so :
void PaintCircle(Vector3 point )
{
int x ;
int z;
int heightX;
int heightZ;
float heightY;
Vector2 calc ;
var b = new bool[heightmapWidth-1, heightmapHeight-1];
for (z = -circleRadius; z <= circleRadius; z++)
{
for (x = -circleRadius; x <= circleRadius; x++)
{
// for a circle, calcualate a relative Vector2
calc = new Vector2(x, z);
// check if the magnitude is within the circle radius
if (calc.magnitude <= circleRadius)
{
// is within circle, paint height
heightX = (int)(point.x + x);
heightZ = (int)(point.z + z);
// check if heightX and Z is within the heightmapData array size
if (heightX >= 0 && heightX < heightmapWidth && heightZ >= 0 && heightZ < heightmapHeight)
{
// read current height
heightY = heightmapData[heightZ, heightX]; // note that in heightmapData, X and Z are reversed
// add paintWeight to the current height
heightY -= paintWeight;
// reach the bottom terrain.terrainData.GetHeight((int)heightmapPos.x, (int)heightmapPos.z)
// update heightmapData array
heightmapData[heightZ, heightX] = heightY;
b[heightZ, heightX] = (heightX < 20 && heightX > 80 && heightZ < 20 && heightZ > 80);
}
}
}
}
terrain.terrainData.SetHoles(0, 0, b);
// apply new heights to terrainData
terrainData.SetHeights(0, 0, heightmapData);
}
I added the raise terrain and the hole together because I need them to work together. Unfortunately, this did not work all of the terrains disappeared so I tried to invert the area where the hole should be like this :
b[heightZ, heightX] = !(heightX < 20 && heightX > 80 && heightZ < 20 && heightZ > 80);
but it gave me what I want in reverse, the area where the hole should remain and all the other terrain disappeared so I thought that the problem could be in this line
var b = new bool[heightmapWidth-1, heightmapHeight-1];
so I changed it to this :
bool[,] b = terrainData.GetHoles(0, 0, heightmapWidth, heightmapHeight);
but it gave me this error :
ArgumentException: Trying to access out-of-bounds terrain holes information.
UnityEngine.TerrainData.GetHoles (System.Int32 xBase, System.Int32 yBase, System.Int32 width, System.Int32 height)
I am out of ideas so I am hoping if someone can tell me what is the problem and how can I fix it
the solution was this :
bool[,] b = terrainData.GetHoles(0, 0, heightmapWidth-1, heightmapHeight-1);

Issue detecting textures in Unity C#

I am trying to program a Unity Minesweeper game, and I am almost done, but as part of it I have a boolean variable called "isCovered" that works out if the square has been clicked or not.
This variable is used to see if the player has won yet. I have a 2d array that stores all of my squares, and to see if you win yet, it checks the array for covered, non mine squares, and if it finds them, concludes that you have not won yet.
However, when I test it, the code does not seem to find any squares that are covered, even though I can see that there are some. I concluded this because it outputs the "you win" message every time I click a safe square, even when I am not finished.
My variable is declared using this code:
public class Square : MonoBehaviour {
//creates boolean variable
public bool IsCovered() {
//checks if the square still uses the default texture.
return GetComponent<SpriteRenderer>().sprite.texture.name == "Default";
}
}
and the code to determine if you win, which is within a different class (that is my array/grid) is:
public static bool gameWon()
{
// Checks all squares in the array
foreach (Square elem in elements)
// Tries to find a covered, safe square
if (elem.IsCovered() && !elem.dangerous)
// The player is not finished
return false;
// The player has won
return true;
}
The asset that is used for the default texture is called "Uncleared proposed", rather than "Default" so I don't know if that is an issue.
My entire "Square" code for each individual tile is:
using System.Collections;
using UnityEngine;
public class Square : MonoBehaviour
{
//is this dangerous?
public bool dangerous;
//creates boolean variable
public bool IsCovered()
{
//checks if the square still uses the default texture.
return GetComponent<SpriteRenderer>().sprite.texture.name == "Default";
}
//different textures
public Sprite[] emptyTextures;
public Sprite dangerTexture;
// Use this for initialization
void Start()
{
//game randomly decides if square is dangerous
//10% chance for initial testing
//Chance likely to be changed at some point
dangerous = Random.value < 0.1;
//registers square in grid
int x = (int)transform.position.x;
int y = (int)transform.position.y;
Grid.elements[x, y] = this;
}
void OnMouseUpAsButton()
{
// It's dangerous
if (dangerous)
{
//uncover all mines
//calls for procedure "uncoverDanger()" from class "Grid"
Grid.uncoverDanger();
//ToDo: display loss screen
// game over
print("Game Over");
}
// It's not a mine
else
{
// change to correct texture
int x = (int)transform.position.x;
int y = (int)transform.position.y;
loadTexture(Grid.adjacentCount(x, y));
//Flood Fill nearby area
Grid.FFuncover(x, y, new bool[Grid.w, Grid.h]);
// checks if the player has won
if (Grid.gameWon() == true)
//tells the player they have won
print("you win");
}
}
//Loads a different texture
public void loadTexture(int adjacentCount)
{
//checks to see if square is dangerous
if (dangerous)
//Changes to correct texture using Unity Component
GetComponent<SpriteRenderer>().sprite = dangerTexture;
//if not dangerous
else
//changes to correct texture using Unity Component
GetComponent<SpriteRenderer>().sprite = emptyTextures[adjacentCount];
}
}
and my Grid class code is:
using System.Collections;
using UnityEngine;
public class Grid {
public static int w = 10; // w is the width of the grid (10)
public static int h = 13; // h is the height of the grid (13)
public static Square[,] elements = new Square[w, h];
//Uncover all mines when losing
public static void uncoverDanger() {
foreach (Square elem in elements)
if (elem.dangerous)
elem.loadTexture(0);
}
// Determines if the square is dangerous
public static bool dangerAt(int x, int y)
{
// Makes sure the square is in the range
if (x >= 0 && y >= 0 && x < w && y < h)
// Checks if the square is dangerous
return elements[x, y].dangerous;
return false;
}
// Counts number of dangerous squares adjacent
public static int adjacentCount(int x, int y)
{
int count = 0;
//checks adjacent squares
//potentially adds to counter
if (dangerAt(x, y + 1)) ++count; // top
if (dangerAt(x + 1, y + 1)) ++count; // top-right
if (dangerAt(x + 1, y)) ++count; // right
if (dangerAt(x + 1, y - 1)) ++count; // bottom-right
if (dangerAt(x, y - 1)) ++count; // bottom
if (dangerAt(x - 1, y - 1)) ++count; // bottom-left
if (dangerAt(x - 1, y)) ++count; // left
if (dangerAt(x - 1, y + 1)) ++count; // top-left
//outputs value
return count;
}
// Flood Fill (FF) safe squares
public static void FFuncover(int x, int y, bool[,] visited)
{
// Checks if coordinates in range
if (x >= 0 && y >= 0 && x < w && y < h)
{
// Filled already?
if (visited[x, y])
return;
//uncovers a square
elements[x, y].loadTexture(adjacentCount(x, y));
//checks if adjacencyCount is not 0
if (adjacentCount(x, y) > 0)
//ends algorithm
return;
// set square as visited
visited[x, y] = true;
// repeates with all 4 adjacent squares (not using diagonal)
FFuncover(x - 1, y, visited);
FFuncover(x + 1, y, visited);
FFuncover(x, y - 1, visited);
FFuncover(x, y + 1, visited);
}
}
public static bool gameWon()
{
// Checks all squares in the array
foreach (Square elem in elements)
// Tries to find a covered, safe square
if (elem.IsCovered() && !elem.dangerous)
// The player is not finished
return false;
// The player has won
return true;
}
}
I am a real newbie to unity so it might be something stupid, any help would be greatly appreciated.
Turns out I am an idiot, I just had to change the name of the texture in the variable code to "Uncleared proposed", I don't know why it didn't work earlier.

Unity Rectangle Overlapping

So I got this piece of code that fills the given area of specific size with floor tiles.
while (roomsPlaced < roomCount.maximum)
{
Vector3 randomPosition = RandomPosition();
int roomHeight = GetRandomNumber(8, 15);
int roomWidth = GetRandomNumber(6, 15);
if (OutOfMap(randomPosition, roomHeight,roomWidth))
{
continue;
}
if (roomsPlaced > 0) {
if (Overlaps(new Rect(randomPosition.x, randomPosition.y, roomWidth, roomHeight), roomPositions[roomPositions.Count -1]))
continue;
}
roomPositions.Add(new Rect(randomPosition.x, randomPosition.y, roomWidth, roomHeight));
for (int x = (int)randomPosition.x; x <= (int)randomPosition.x + roomWidth; x++)
{
for (int y = (int)randomPosition.y; y <= (int)randomPosition.y + roomHeight; y++)
{
if (x == randomPosition.x || y == randomPosition.y)
toInstantiate = floorTiles[Random.Range(0, floorTiles.Length)];
GameObject instance = Instantiate(toInstantiate, new Vector3(x, y, 0f), Quaternion.identity) as GameObject;
instance.transform.SetParent(boardHolder);
}
}
roomsPlaced++;
}
And here is function that should check if current rectangle overlaps the last rectangle on the list.
bool Overlaps(Rect rA, Rect rB)
{
return (rA.x < rB.x + rB.width && rA.x + rA.width > rB.x && rA.y < rB.y + rB.height && rA.y + rA.height > rB.y);
}
But still I have problem when some of my rooms overlap.
What am I doing wrong and what should I do to fix this problem ?
This sounds like you need to use the Overlaps method instead...
Yeeah. I just solved the problem by going through the whole list instead of picking last element on the list.

OpenGL/SharpGL Faces Misbehaving

I am currently writing an OpenGL application using the SharpGL library and I am trying to simply create a 3x3x3 set of cubes arranged in a symmetric grid.
I am currently seeing some strange behaviour exhibited in the following picture:
This has me completely stumped as I can see no reason why the code is missing out the last 3 blocks. The method in charge of creating the cube looks like this:
private void CreateCube2(OpenGL gl, int cubeSize)
{
gl.PushMatrix();
const float spacing = 2.5f;
for (int z = 0; z < cubeSize; z++)
{
for (int y = 0; y < cubeSize; y++)
{
for (int x = 0; x < cubeSize; x++)
{
var cube = new Cube();
ColourCube(cube, cubeSize, x, y, z);
cube.Render(gl, RenderMode.Render);
gl.Translate(spacing, 0, 0);
}
gl.Translate(-spacing * cubeSize, spacing, 0);
}
gl.Translate(0, -spacing * cubeSize, spacing);
}
gl.PopMatrix();
}
where the definition of ColourCube is as follows:
private bool m_blackCubeMiddle = true;
private void ColourCube(Cube cube, int size, int x, int y, int z)
{
cube.Faces[0].Material = (!m_blackCubeMiddle || y == 0) ? WhiteMaterial : BlackMaterial; // Bottom
cube.Faces[1].Material = (!m_blackCubeMiddle || y == size - 1) ? YellowMaterial : BlackMaterial; // Top
cube.Faces[2].Material = (!m_blackCubeMiddle || x == size - 1) ? GreenMaterial : BlackMaterial; // Right
cube.Faces[3].Material = (!m_blackCubeMiddle || x == 0) ? BlueMaterial : BlackMaterial; // Left
cube.Faces[4].Material = (!m_blackCubeMiddle || z == 0) ? OrangeMaterial : BlackMaterial; // Front
cube.Faces[5].Material = (!m_blackCubeMiddle || z == size - 1) ? RedMaterial : BlackMaterial; // Back
}
The entire project can be downloaded from here.
The strange behaviour is caused by a bug in SharpGL 'Polygon.Render' method. It is not caused by your own code. When you call Triangulate on the cube, it already shows 27 cubes on screen in the correct positions. But even then, SharpGL incorrectly renders one of the cubes.
Having looked at the source code for ShapGL's Cube & Polygon classes I'ld suggest to write your own cube class. The implementation of the Cube class, that you are using now, is absolutely horible from several standpoints (GL_POLYGON (deprecated), immediate mode vertex submission (deprecated))

XNA - 2D collision failure without any obvious pattern

Alright, so I am pretty new to XNA programming and I am trying to code a platformer. I have implemented pixel-perfect collision but it seems to fail for no apparent reason sometimes (I couldn't figure out a pattern) and the hero sprite goes through platforms.
static bool IntersectsPixel(Rectangle rect1, Color[] data1, Rectangle rect2, Color[] data2)
{
int top = Math.Max (rect1.Top, rect2.Top);
int bottom = Math.Min(rect1.Bottom, rect2.Bottom);
int left = Math.Max (rect1.Left,rect2.Left);
int right = Math.Min(rect1.Right,rect2.Right);
//Top
for(int y = top; y<bottom;y++)
for (int x = left; x < right; x++)
{
Color color1 = data1[x-rect1.Left + (y-rect1.Top) * rect1.Width];
Color color2 = data2[x - rect2.Left + (y - rect2.Top) * rect2.Width];
if (color1.A != 0 && color2.A != 0)
return true;
}
return false;
}
And here's the Update Method
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
foreach(Platform platform in platformList)
{
Rectangle check = new Rectangle(hero.GetRectangle().X - 300, hero.GetRectangle().Y - 300, 600, 600);
if(check.Intersects(platform.rectangle))
if (IntersectsPixel(hero.GetRectangle(), hero.textureData, platform.rectangle, platform.platformTextureData))
{
int direction = CheckDirection(platform,hero);
if (hero.hasJumped == true && direction == 3 && hero.velocity.Y <= 0 )
{
hero.velocity.Y = 0f;
hero.SetPosition(new Vector2((float)hero.GetPosition().X, (float)platform.rectangle.Bottom));
break;
}
else
if (direction == 4 && hero.velocity.X >= 0)
{
hero.velocity.X = 1;
hero.SetPosition(new Vector2((float)platform.rectangle.Left - (float)hero.GetRectangle().Width, (float)hero.GetPosition().Y));
break;
}
else
if (direction == 2 && hero.velocity.X <= 0)
{
hero.velocity.X = -1;
hero.SetPosition(new Vector2((float)platform.rectangle.Right - 1, (float)hero.GetPosition().Y));
break;
}
else
if (direction == 1 && hero.velocity.Y >= 0)
{
hero.velocity.Y = 0;
hero.hasJumped = false;
hero.SetPosition(new Vector2((float)hero.GetRectangle().X, (float)platform.rectangle.Y - (float)hero.GetRectangle().Height + 1));
hero.SetRectangle(new Rectangle((int)hero.GetPosition().X, (int)hero.GetPosition().Y, (int)hero.GetSize().X, (int)hero.GetSize().Y));
break;
}
}
}
hero.Update(gameTime);
camera.Update(gameTime, hero, screenBounds);
base.Update(gameTime);
}
And here's the direction check:
private int CheckDirection(Platform platform,Hero hero)
{
int distance = Math.Abs(platform.rectangle.Top - hero.GetRectangle().Bottom);
int direction = 1; //Top
if (distance > Math.Abs(platform.rectangle.Right - hero.GetRectangle().Left))
{
distance = Math.Abs(platform.rectangle.Right - hero.GetRectangle().Left);
direction = 2;
}
if (distance > Math.Abs(platform.rectangle.Bottom - hero.GetRectangle().Top))
{
distance = Math.Abs(platform.rectangle.Bottom - hero.GetRectangle().Top);
direction = 3;
}
if (distance > Math.Abs(platform.rectangle.Left - hero.GetRectangle().Right))
{
direction = 4;
distance = Math.Abs(platform.rectangle.Left - hero.GetRectangle().Right);
}
return direction;
}
Those are all my functions related to collision detection. If you happen to have any ideea of what might cause this, please let me know.
Thank you very much !
One thing I see that might be a possible reason is that right in the beginning where you build a box around both objects:
int top = Math.Max (rect1.Top, rect2.Top);
int bottom = Math.Min(rect1.Bottom, rect2.Bottom);
int left = Math.Max (rect1.Left,rect2.Left);
int right = Math.Min(rect1.Right,rect2.Right);
Unless you flipped it, typically XNA's Y grows positive as you go down (not up). This means you would actually want to take the Max of Bottom, and the Min of Top, since Top will always be less than Bottom. It looks like you already knew that though by the look of this line:
for(int y = top; y<bottom;y++)
I'll keep looking (it's difficult to test without the actual project). Another recommendation I'd give you is to do some debug drawing. Draw where the intersection functions thinks that pixels are touching or not touching.
Because of lag, Your character could be moving more than the blocks height per frame, so the collision may think it is in between blocks, and cause it to fly through.
https://gamedev.stackexchange.com/questions/30458/platformer-starter-kit-collision-issues
Check that out, It solved the problem for me.
Either slowing down movement, or clamping the change in position to the size of a block should solve this.

Categories