Physics2D.OverLapBox detects objects that should be ignored - unity3d

I'm using a script that looks at the tiles around my GameObject to see if it can detect a collider, through Physics2D.OverlapBox. My problem is that my Player should be ignored by the OverLapBox, as I've set it to look at layers it isn't in, but it is detected everytime.
My Player is in the "Default" layer.
private void SpawnBasicWalls()
{
int layersToScan = LayerMask.GetMask("Floor", "Wall");
//for each tile around this tile
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
Vector2 targetPos = new Vector2(transform.position.x + x, transform.position.y + y);
Collider2D hit = Physics2D.OverlapBox(targetPos, Vector2.one * 0.8f, layersToScan);
//if there isn't a tile around
if (!hit)
{
//Add a wall in that empty adjacent tile.
GameObject goWall = Instantiate(dungMan.wallPrefab, targetPos, Quaternion.identity) as GameObject;
goWall.name = dungMan.wallPrefab.name;
goWall.transform.SetParent(dungMan.transform);
}
else
{
Debug.Log(hit);
}
}
}
//Once it's done, the gameobject is useless and thus is destroyed
Destroy(gameObject);
}
If anyone can tell me what I'm doing wrong, I'd be very grateful.

Physics2D.OverlapBox(targetPos, Vector2.one * 0.8f, layersToScan) is basically calling Physics2D.OverlapBox(point, size, angle) - which means you are sending the layers (casted to int) as an angle.
You need to use one of the overloads that receive a layermask, and make sure you pass it in the right parameter.

Related

Bad usage of Physics.OverlapBox

I don't understand the usage of method Physics.OverlapBox.
I want to put ten walls on a 4x4 plane in my scene. The width and location of the walls is calculated randomly. In the odd number of cycles in the creation loop the wall is rotated 90 degrees.
The walls presented in the scene should not collide with other walls... but it's not working.
void Reset()
{
int walls = 10;
for (int w = 0; w < walls; w++)
{
for (int i = 0; i < 5; i++)
{
float x = Random.Range(-20f, 20f);
float z = Random.Range(-20f, 20f);
Vector3 center = new Vector3(x, 1.51f, z);
int scalex = Random.Range(4, 13);
Quaternion quaternion = Quaternion.identity;
if (w % 2 == 1)
quaternion=Quaternion.Euler(0, 0, 0);
else
quaternion=Quaternion.Euler(0, 90, 0);
Collider[] colliders = Physics.OverlapBox(center, new Vector3(scalex, 3, 1) / 2, quaternion);
Debug.Log(colliders.Length);
if (colliders.Length == 0)
{
GameObject wall = GameObject.CreatePrimitive(PrimitiveType.Cube);
wall.transform.position = center;
wall.transform.localScale = new Vector3(scalex, 3, 1);
wall.transform.rotation = quaternion;
wall.tag = "wall";
break;
}
}
}
}
After your comment I think I now know what the issue is:
The physics engine simply doesn't "know" your walls colliders yet since the physics engine is updated in the next FixedUpdate.
You might want to call Physics.Simulate after each wall in order to manually trigger a physics update.
The docs are a bit unclear if it is necessary but you might have to disable Physics.autoSimulation before the loop and turn it back on after you are finished with the wall creation.
The solution proposed by derHugo (a lot of thanks) works from Start method. I added rotation to the walls. No collisions.
The code:
public void Start()
{
Physics.autoSimulation = false;
for (int i = 0; i < 200; i++)
{
createWall();
Physics.Simulate(Time.fixedDeltaTime);
}
Physics.autoSimulation = true;
}
void createWall()
{
float x = Random.Range(-20f, 20f);
float z = Random.Range(-20f, 20f);
Vector3 position = new Vector3(x, 1.51f, z);
Quaternion rotation = Quaternion.Euler(0, Random.Range(0,360), 0);
int scalex = Random.Range(2, 5);
Collider[] colliders = Physics.OverlapBox(position, new Vector3(scalex, 1, 1)/2, rotation);
if (colliders.Length==0)
{
GameObject wall = GameObject.CreatePrimitive(PrimitiveType.Cube);
wall.transform.localPosition = position;
wall.transform.localScale = new Vector3(scalex, 3, 1);
wall.transform.rotation = rotation;
wall.tag = "wall";
}
}

Camera not displaying anything when clamped used to set restrictions in Unity

Good day
I am trying to restrict my camera movement using a function that I am using to restrict other elements in a 2D game. When I call this function using my camera, it does something strange.
For some reason it does not display anything as soon as I called the function. I have tested the camera's position using Debug.log, and it seems to be in exactly the same place. The constraints also seem to work, but that is useless if nothing displays.
I am using a Mathf.Clamp function to try and constrain the map. I know that there are many tutorials showing how to constrain map movement, and honestly my approach seems similar.
I want to know why this function is failing. I am trying to keep things generic, and am already using this function to restrict the movement of other game elements.
My code looks like this:
int cameraSpeed = 10;
GameObject camera;
int maxX = 20;
int minX = -20;
int maxY = 20;
int minY = -20;
// Use this for initialization
public void constrain(GameObject obj)
{
Vector2 pos = obj.transform.position;
pos.x = Mathf.Clamp(pos.x, -maxX, maxX);
pos.y = Mathf.Clamp(pos.y, -maxY, maxY);
obj.transform.position = pos;
}
void Start () {
camera = GameObject.Find("Main Camera");
}
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.RightArrow))
{
camera.transform.Translate(new Vector2(cameraSpeed * Time.deltaTime, 0));
}
if (Input.GetKey(KeyCode.LeftArrow))
{
camera.transform.Translate(new Vector2(-cameraSpeed * Time.deltaTime, 0));
}
if (Input.GetKey(KeyCode.DownArrow))
{
camera.transform.Translate(new Vector2(0, -cameraSpeed * Time.deltaTime));
}
if (Input.GetKey(KeyCode.UpArrow))
{
camera.transform.Translate(new Vector2(0, cameraSpeed * Time.deltaTime));
}
Debug.Log(camera.transform.position.x);
Debug.Log(camera.transform.position.y);
constrain(camera);
}
Screenshot of game without constraints:
Screenshot of game with constraints:
I am new to Unity and am trying to understand it thoroughly. Any advice would be greatly appropriated.
The Z-position of your camera is being set to 0. All of your other objects have the same Z-position, so the camera won't render them.
Change constrain() to:
public float zPos = -10
public void constrain(GameObject obj)
{
Vector3 pos = obj.transform.position;
pos.x = Mathf.Clamp(pos.x, -maxX, maxX);
pos.y = Mathf.Clamp(pos.y, -maxY, maxY);
pos.z = zPos
obj.transform.position = pos;
}
and that should fix it.
EDIT: The reason that this is happening is because you were using a Vector2 for your camera position. In Unity, a Vector2 is a Vector3 with a z-value of 0.
I have managed to find the bug with #DerwB's assistance. I now see that the camera needs to be on a lower z index than the objects it is displaying. DerwB's answer is close to a solution, but it does not allow the function to be reused to constrain other objects.
I have thus modified the function as below:
public void constrain(GameObject obj, bool isCamera = false)
{
Vector3 pos = obj.transform.position;
pos.x = Mathf.Clamp(pos.x, -maxX, maxX);
pos.y = Mathf.Clamp(pos.y, -maxY, maxY);
if(isCamera)
pos.z = 0;
else
pos.z = 1;
obj.transform.position = pos;
}
You then call the function as follows for the camera:
GameObject camera = GameObject.Find("Main Camera");
constrain(camera.gameObject,true); //if you are constraining the camera object
And like this if you are referencing other game objects:
GameObject player= GameObject.Find("Player");
constrain(player.gameObject,true); //skip the optional parameter if not referencing the camera

Unity 2D Rigidbody.velocity and transform.position causes random 'ghost' frame

I am creating a 2D platform / adventure game that uses flip screen to manage changing rooms.
My character moves using RigidBody.velocity, this works as I need it to, when my character reaches one of the screen's left or right extremes I use transform.position to move (effectively teleporting) the character to the other side of the screen, I then change the room. This gives the effect of moving to the next room along.
My flip screen code works fine, the changing room effect works without a problem, in fact almost everything works just as I like it, except that I get 1 frame where the character appears at a random point in between where the character moved from and where he moved to.
For example, my room is 16 tiles across, if my character moves left and passes x position '0' (the very left of the screen) I make a transform.position to x position 16 (keeping the y position constant) and then change rooms. I have logged the movement and what happens is (pseudo code)..
x < 0 (the change room code is run)
translate.position to x=16 (the far right)
x = 16 (this is correct)
The room changes
x = some float somewhere between 0 and 16 (this is NOT correct)
x = 16 (back to the correct position again)
This is my player code:
using UnityEngine;
using System.Collections;
public class MKManager : MonoBehaviour {
public float maxSpeed = 0.10f;
bool isFacingRight = false;
Rigidbody2D myBody;
bool grounded = true;
public static int liftdirection = 0;
void Start (){
myBody = GetComponent<Rigidbody2D> ();
}
void Update () {
checkRoomBounds ();
}
void FixedUpdate(){
float h = Input.GetAxisRaw ("Horizontal");
if (grounded) {
myBody.velocity = new Vector2 (h * maxSpeed, myBody.velocity.y);
if (h < 0) { //Moving Left
if (isFacingRight) {
FlipAnimation ();
}
} else if (h > 0) { //Moving Right
if (!isFacingRight) {
FlipAnimation ();
}
}
}
}
void checkRoomBounds(){
if (transform.position.x < 0) {
transform.position = new Vector3 (16.0f, transform.position.y, 0.0f);
GameManager.instance.moveRoom (-1);
} else if (transform.position.x > 16) {
transform.position = new Vector3 (0.0f, transform.position.y, 0.0f);
GameManager.instance.moveRoom (1);
}
}
void FlipAnimation(){
isFacingRight = !isFacingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
I have tried calling checkRoomBounds() in update, fixed update and lateupdate, all give the same result. If I do not call the moveRoom() function the same happens but the room is not changed, but the moveRoom() code is...
public void moveRoom(int direction){
if (room == 0) {
room = (10*currentFloor) + 1;
} else {
room += direction;
if (room == -1) {
room = 68;
} else if (room == 69) {
room = 0;
} else if (room % 10 == 9 || room % 10 == 0) {
//room += (direction * 2);
room = 0;
}
}
boardScript.SetupScene (room);
}
I've run out of ideas and don't know where I'm going wrong. Any help would be much appreciated.
Many thanks in advance

Painting sprite in unity

Problem :
I want to make prototype for cleaning windows (I mean cleaning dirty windows) in unity.
I was searching about this subject and finding that I can change pixel by Texture2D.SetPixel().
I try to do it by this method, First I enabled read/write of texture and try this method but nothing happened on my sprite.
So I want to ask it if it's possible to change alpha of the sprite that is clicked by mouse or touched to show the below sprite of original one !?
My Code :
private RaycastHit2D hitInfo;
private SpriteRenderer spriteRendererComponent;
private Color zeroAlpha;
// Use this for initialization
void Start ()
{
spriteRendererComponent = transform.GetComponent<SpriteRenderer>();
zeroAlpha = Color.blue;
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButton(0))
{
MouseClick();
}
}
public void MouseClick()
{
Vector2 mousePosition = Vector2.zero;
mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
hitInfo = Physics2D.Raycast(mousePosition, Vector2.zero);
if (hitInfo)
{
spriteRendererComponent.sprite.texture.SetPixel((int)hitInfo.point.x, (int)hitInfo.point.y, zeroAlpha);
spriteRendererComponent.sprite.texture.Apply();
}
}
Answer :
You can use this thread for Optimizing of changing pixels of sprite
I've found answer about changing pixels of sprite (Painting)
public float radius;
public Color InitialColor;
private RaycastHit2D hitInfo;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (CustomInput.ControlStay())
{
hitInfo = CustomInput.ClickednTouched().hitInfo;
if (hitInfo)
{
UpdateTexture();
}
}
}
public Texture2D CopyTexture2D(Texture2D copiedTexture2D)
{
float differenceX;
float differenceY;
//Create a new Texture2D, which will be the copy
Texture2D texture = new Texture2D(copiedTexture2D.width, copiedTexture2D.height);
//Choose your filtermode and wrapmode
texture.filterMode = FilterMode.Bilinear;
texture.wrapMode = TextureWrapMode.Clamp;
//Center of hit point circle
int m1 = (int)((hitInfo.point.x + 2.5f) / 5 * copiedTexture2D.width);
int m2 = (int)((hitInfo.point.y + 2.5f) / 5 * copiedTexture2D.height);
for (int x = 0; x < texture.width; x++)
{
for (int y = 0; y < texture.height; y++)
{
differenceX = x - m1;
differenceY = y - m2;
//INSERT YOUR LOGIC HERE
if (differenceX * differenceX + differenceY * differenceY <= radius * radius)
{
//This line of code and if statement, turn all texture pixels within radius to zero alpha
texture.SetPixel(x, y, InitialColor);
}
else
{
//This line of code is REQUIRED. Do NOT delete it. This is what copies the image as it was, without any change
texture.SetPixel(x, y, copiedTexture2D.GetPixel(x, y));
}
}
}
//This finalizes it. If you want to edit it still, do it before you finish with Apply(). Do NOT expect to edit the image after you have applied.
texture.Apply();
return texture;
}
public void UpdateTexture()
{
SpriteRenderer mySpriteRenderer = gameObject.GetComponent<SpriteRenderer>();
Texture2D newTexture2D = CopyTexture2D(mySpriteRenderer.sprite.texture);
//Get the name of the old sprite
string tempName = mySpriteRenderer.sprite.name;
//Create a new sprite
mySpriteRenderer.sprite = Sprite.Create(newTexture2D, mySpriteRenderer.sprite.rect, new Vector2(0.5f, 0.5f));
//Name the sprite, the old name
mySpriteRenderer.sprite.name = tempName;
//Update the material
//If you have multiple sprites, you will want to do this in a loop
//mySpriteRenderer.material.mainTexture = newTexture2D;
//mySpriteRenderer.material.shader = Shader.Find("Unlit/Transparent");
}
Another problem :
Finding pixel on sprite :
In Unity3d we have RaycastHit.textureCoord but it doesn't exist anymore in 2D. I was searching about this problem, a lot but I didn't find anything useful.
So I want to know the solution for this problem and I'm wondering why method like textureCoord in 3D doesn't exist in 2D.
Answer :
I've found answer again as you see in the previous code for finding pixel on sprite.
Thread : Finding pixel on sprite in Unity
Check this out!
I have fixed your script. Works on different texture sizes. Different texture places and camera size. Require box collider 2d.
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
public float radius;
public Color InitialColor;
private RaycastHit2D hitInfo;
// Update is called once per frame
void Update()
{
if (Input.GetMouseButton(0))
{
hitInfo = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
if (hitInfo)
{
UpdateTexture();
}
}
if (Input.GetMouseButtonUp(0))
{
Resources.UnloadUnusedAssets();
}
}
public Texture2D CopyTexture2D(Texture2D copiedTexture2D)
{
float differenceX;
float differenceY;
//Create a new Texture2D, which will be the copy
Texture2D texture = new Texture2D(copiedTexture2D.width, copiedTexture2D.height);
//Choose your filtermode and wrapmode
texture.filterMode = FilterMode.Bilinear;
texture.wrapMode = TextureWrapMode.Clamp;
//Center of hit point circle
int m1 = (int)((hitInfo.point.x - hitInfo.collider.bounds.min.x) * (copiedTexture2D.width / hitInfo.collider.bounds.size.x));
int m2 = (int)((hitInfo.point.y - hitInfo.collider.bounds.min.y) * (copiedTexture2D.height / hitInfo.collider.bounds.size.y));
//Vector2 extremeScreenPoint = Camera.main.ScreenToWorldPoint(new Vector2(0, 0));
//Debug.Log("extremeScreenPoint= " + extremeScreenPoint.x
// + " hitInfo.point.x =" + hitInfo.point.x
// //+ " mousePosition =" + Camera.main.ScreenToWorldPoint(Input.mousePosition).x
// + " bounds.min =" + hitInfo.collider.bounds.min .x
// + " bounds.max =" + hitInfo.collider.bounds.max .x
// + " size =" + hitInfo.collider.bounds.size.x
// + " hit =" + (hitInfo.point.x - hitInfo.collider.bounds.min.x)
// + " pixels =" + (hitInfo.point.x - hitInfo.collider.bounds.min.x) * (copiedTexture2D.width / hitInfo.collider.bounds.size.x)
// );
for (int x = 0; x < texture.width; x++)
{
for (int y = 0; y < texture.height; y++)
{
differenceX = x - m1;
differenceY = y - m2;
//INSERT YOUR LOGIC HERE
if (differenceX * differenceX + differenceY * differenceY <= radius * radius)
{
//This line of code and if statement, turn all texture pixels within radius to zero alpha
texture.SetPixel(x, y, InitialColor);
}
else
{
//This line of code is REQUIRED. Do NOT delete it. This is what copies the image as it was, without any change
texture.SetPixel(x, y, copiedTexture2D.GetPixel(x, y));
}
}
}
//This finalizes it. If you want to edit it still, do it before you finish with Apply(). Do NOT expect to edit the image after you have applied.
texture.Apply();
//DestroyImmediate(copiedTexture2D, true);
return texture;
}
public void UpdateTexture()
{
SpriteRenderer mySpriteRenderer = gameObject.GetComponent<SpriteRenderer>();
Texture2D newTexture2D = CopyTexture2D(mySpriteRenderer.sprite.texture);
//Get the name of the old sprite
string tempName = mySpriteRenderer.sprite.name;
//Create a new sprite
mySpriteRenderer.sprite = Sprite.Create(newTexture2D, mySpriteRenderer.sprite.rect, new Vector2(0.5f, 0.5f));
//Name the sprite, the old name
mySpriteRenderer.sprite.name = tempName;
//Update the material
//If you have multiple sprites, you will want to do this in a loop
//mySpriteRenderer.material.mainTexture = newTexture2D;
//mySpriteRenderer.material.shader = Shader.Find("Unlit/Transparent");
}
}
I worked with Writing and Reading a Texture once (for a scratching card).
You have to consider that when you change the Pixels of the Sprite, you are changing the pixels for the entire texture. So let's say that i change the pixel 1x1, most likely it will not change the pixel 1x1 in my sprite if i have a bunch of sprites in the same texture. So you have to consider the offsets of the sprite and reposition the pixel that you want to change.
Try to do something like this:
public void MouseClick()
{
Vector2 offset = new Vector2(XXX, YYY);
Vector2 mousePosition = Vector2.zero;
mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
hitInfo = Physics2D.Raycast(mousePosition, Vector2.zero);
if (hitInfo)
{
spriteRendererComponent.sprite.texture.SetPixel((int)hitInfo.point.x + offset.x, (int)hitInfo.point.y + offset.y, zeroAlpha);
spriteRendererComponent.sprite.texture.Apply();
}
}

How to find all colliders below mouse?

public static bool IsTopmost(GameObject go)
{
RaycastHit[] hits;
Vector3 wp = Camera.main.ScreenToWorldPoint(Input.mousePosition);
wp.z = Camera.main.transform.position.z;
hits = Physics.RaycastAll(wp, Vector3.forward, Vector3.Distance(Camera.main.transform.position, go.transform.position) * 2);
if (hits.Length == 0)
{
return false;
}
GameObject topMostSoFar = hits[0].collider.gameObject;
RaycastHit hit;
for (int i = 1; i < hits.Length; i++)
{
hit = hits[i];
if (Compare(topMostSoFar, hit.collider.gameObject) == -1)
{
topMostSoFar = hit.collider.gameObject;
}
}
Debug.Log("finishes method");
return topMostSoFar.name == go.name;
}
My camera position.z = -5, all sprites in the game position.z = 0. This method never finishes, it always enters the first if which says there are no colliders under the mouse position. What do I do wrong here?
EDIT: It turns out my mistake is very stupid, I'm using Physics instead of Physics2D for 2d colliders. How can I check same thing but with 2d raycasting?
The solution is to use the 2d methods and variable types everywhere and for the direction of the RaycastAll to use Vector2.zero, unless you put Vector2.zero it;s not going to work.