Gizmos.DrawCube display bug when multiple cubes drawn near each other - unity3d

When I draw multiple cubes using Gizmos.DrawCubeto visualize some 3D tiles, I end up with a bunch of cubes inside out. It's called from Editor Code.
Here is the code for the call:
private void OnDrawGizmos() {
foreach (Vector3Int position in positions) {
Gizmos.DrawCube(position * Const.tileSize, Const.tileVectorSize);
}
}
Here is the display bug:
But everything is ok when _position only contains 1 cube
Edit: It also happens with few cubes drawn :
Any idea what is going on and how to correct it ?

This is not actually a bug. The gizmos don't write to the depth buffer. What that means (and what you see in the image) is gizmos being drawn on top of each other regardless of whether they are behind another gizmo. Maybe there is some way to enable depth buffer write or zWrite on gizmos, now you know what to look for.
What you could do in the meantime is try the Painter's algorithm. This is just sorting the gizmos from furthest from the camera to closest before you draw them.
private void OnDrawGizmos()
{
var sorted = positions.OrderByDescending((x) => Vector3.Distance(Camera.current.transform.position, x));
foreach (Vector3Int position in sorted)
{
Gizmos.DrawCube(position * Const.tileSize, Const.tileVectorSize);
}
}
And this is what it looks like:

Related

Converting mouse coordinates for ui in world space

Im having problems with position convertions. The way im trying to solve it may be very wrong but thats due to inexperience in that case and im up for any suggestion on how to do it differently.
What im trying to do is a gui with a dot graph envelope that the user can change by draging the dots with the mouse.
This is what i would wan it to look like.
https://imgur.com/FP6f1Cz
First i did the UI like normal in overlay but i couldnt get the line renderer to work so i took the whole ui into world space. This makes the line renderer visible. With the UI in world space ive tried both to put the envelope line renderer in the canvas with the rest of the ui and outside the canvas UI.
Here is the code that renders the lines where the dots are and moves the dots when the mouse drags them :
public class Envelope : MonoBehaviour
{
LineRenderer lineRenderer;
// Start is called before the first frame update
void Start()
{
lineRenderer = GetComponentInChildren<LineRenderer>();
}
// Update is called once per frame
void Update()
{
var points = GetComponentsInChildren<EnvelopePoint>().Select(ep => ep.transform.localPosition).ToArray();
lineRenderer.positionCount = points.Length;
lineRenderer.SetPositions(points);
}
}
public class EnvelopePoint : MonoBehaviour
{
[SerializeField] bool isHeld = false;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (isHeld)
{
// Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector3 mousePos = Input.mousePosition;
transform.position = mousePos;
}
}
private void OnMouseDown()
{
isHeld = true;
}
private void OnMouseUp()
{
isHeld = false;
}
}
The best result is to put the envelope outside of the canvas.
The lines render well to where the points are but im not able to convert the mouse position to correct coordinates for the dots. When i click on a dot to drag it the dot snaps to a position a bit lower and a bit to the left of the mouse. Like this:
https://imgur.com/3KK6VD3
But then i can drag the dots and the lines adjust perfectly.
I guess i have two questions:
How should i get the mouse position conversion correctly?
Is this a strange or over complicated way of doing this? Is there a more reasonable way?
Id love some tip as well on what i should read up on to better understand the different screen types and how to convert between them.
RectTransformUtility.ScreenPointToWorldPointInRectangle: Transform a screen space point to a position in world space that is on the plane of the given RectTransform.
There is also ScreenPointToLocalPointInRectangle but since you are modifying Line Renderer's points (which are in world space), I think ScreenPointToWorldPointInRectangle best suits your needs.

Best way to create a 2d top down race track procedurally

I am attempting to create a 2d top-down car racing game. This game will have a random road map each time the player plays the game. I have thought about doing this in two different ways: A tilemap, or just generate the roads by placing different prefabs (straight roads, turns, etc). I have decided to go with the prefab route.
The way I believe it should work is to have prefab square "tiles" which have their own colliders set on the edges so I can tell if a player goes off the track in which case they blow up. I would have a MapGenerator Script which will generate an initial random map by keeping track of the last tile placed (including its location and road type: left turn, straight, right, etc). This script will then keep adding onto the road randomly as the player gets closer and closer to the end which makes it an infinite road.
I just want to know if this is just not efficient or if I am thinking of this completely wrong.
Here are a couple of images showing my road tiles which I made in photoshop and then one prefab for a straight road (take note of the colliders on its edges).
A similar game to one I want to make is Sling Drift which I can provide the link if you want. I don't know the policy on adding links to forum chat.
Also, here is my code for the map generator:
//Type of tyle, types are normal (straight road or horizontal road) and turns
public enum MapTileType
{
NORMAL,
N_E,
N_W,
S_E,
S_W
}
//structure for holding the last tile location and its type.
public struct TypedTileLocation
{
public TypedTileLocation(Vector2 pos, MapTileType tyleType)
{
m_tileType = tyleType;
m_position = pos;
}
public Vector2 m_position;
public MapTileType m_tileType;
}
public class MapGenerator : MonoBehaviour
{
//Map Tiles
public GameObject m_roadTile;
public GameObject m_turnNorthWestTile;
//holds all the tiles made in the game
private List<GameObject> m_allTiles;
//Map Tile Widths and Height
private float m_roadTileWidth, m_roadTileHeight;
//Used for generating next tile
TypedTileLocation m_lastTilePlaced;
private void Awake()
{
//store the initial beginning tile location (0,0)
m_lastTilePlaced = new TypedTileLocation(new Vector2(0,0), MapTileType.NORMAL);
//set height and width of tiles
m_roadTileWidth = m_roadTile.GetComponent<Renderer>().bounds.size.x;
m_roadTileHeight = m_roadTile.GetComponent<Renderer>().bounds.size.y;
m_allTiles = new List<GameObject>();
}
// Start is called before the first frame update
void Start()
{
SetupMap();
}
void SetupMap()
{
//starting at the beginning, just put a few tiles in straight before any turns occur
for (int i = 0; i < 6; ++i)
{
GameObject newTempTile = Instantiate(m_roadTile, new Vector2(0, m_roadTileHeight * i), Quaternion.identity);
m_lastTilePlaced.m_tileType = MapTileType.NORMAL;
m_lastTilePlaced.m_position.x = newTempTile.transform.position.x;
m_lastTilePlaced.m_position.y = newTempTile.transform.position.y;
m_allTiles.Add(newTempTile);
}
//now lets create a starter map of 100 road tiles (including turns and straigt-aways)
for (int i = 0; i < 100; ++i)
{
//first check if its time to create a turn. Maybe I'll randomly choose to either create a turn or not here
//draw either turn or straight road, if the tile was a turn decide which direction we are now going (N, W, E, S).
//this helps us determine which turns we can take next
//repeat this process.
}
}
void GenerateMoreMap()
{
//this will generate more map onto the already existing road and then will delete some of the others
}
// Update is called once per frame
void Update()
{
}
private void OnDrawGizmos()
{
}
}
Thanks!
Have you tried splines? They let you make curvy paths like race tracks easily. If not, here is a video that might help: https://www.youtube.com/watch?v=7j_BNf9s0jM.

Spawn prefab randomly over polygon collider 2d in Unity

I have attached pollygon collider 2d on this gameObject.
This gameObject is parent of another gameObject (just small circle).
I want that small circle to randomly spawn somwhere on pollygon collider.
I tried something like this:
private void GetBounds()
{
polygonCollider = transform.parent.gameObject.GetComponent<PolygonCollider2D>();
bounds = polygonCollider.bounds;
}
public void TargetSetPosition()
{
x = Random.Range(bounds.min.x, bounds.max.x);
y = Random.Range(bounds.min.y, bounds.max.y);
transform.localPosition = new Vector2(x, y);
}
private void Start()
{
GetBounds();
TargetSetPosition();
}
This script is attached to that small circle. In 80% cases is good result but sometimes it get weird something like this:
Can someone help me please, becouse i tried almost everything.
The bounds = polygonCollider.bounds is getting the bounds of the bounding box. So in your second pic, the ball is inside the bounds.
To make it be inside the collider of your objects, you need to try something else, like this

Dynamically added LineRenderer doesn't show in game view

I add some line dynamically and they appear in the scene view perfectly, but not in game view. The z indexes are properly set, I use different layer just for the lines. I tried changing the camera clipping planes values, culling mask is on everything.
void Update()
{
Vector2 mousePos;
if (Input.GetMouseButtonDown(0))
{
Vector3 closeToPoint = IsClickCloseToPoint();
if (closeToPoint.z != -10000f)
{
GameObject newObj = Instantiate(lineGenerator);
startMousePos = closeToPoint;
newLine = newObj.GetComponent<LineRenderer>();
newLine.transform.SetParent(parentObject.transform);
newLine.positionCount = 2;
}
}
if (Input.GetMouseButton(0))
{
if (newLine != null)
{
mousePos = Input.mousePosition;
newLine.SetPosition(0, new Vector3(startMousePos.x, startMousePos.y, -5f));
newLine.SetPosition(1, new Vector3(mousePos.x, mousePos.y, -5f));
distance = (mousePos - startMousePos).magnitude;
distanceText.text = distance.ToString("F2");
}
}
if (Input.GetMouseButtonUp(0))
{
if (newLine != null)
{
newLine = null;
}
}
}
You are drawing everything on a canvas. But LineRenderer is not a UI component and therefore is not shown on the canvas.
If you want to work with LineRenderer nontheless check this info in Unity Answers. The basic idea is to have the canvas set up as Screen Space and increase the width of the lines. Don't forget to assign the camera.
i think you need to put a material on the lineRenderer. What you see in the scene view is the "non material" texture that doesn't appear in game view :)
I hope that help :)
Raph
The problem was that the coordinates are different in the scene view and the game view, or at least you have to design to the game view, not the scene view. My lines were present in the game view, but they were out of the canvas. I used Camera.main.ScreenToWorldPoint(Vektor3) to convert every vektor.
I can't see the Inspector settings of your LinRenderer but I suspect that you have
Alignment set to Transform Z
Lines face the Z axis of the Transform Component.
And thos becomes completely invisible if your orthographic Camera looks exactly in Z direction onto it.
Try and change the Alignment to View.
Also note that literally nothing is rendered on top of a ScreenSpace Overlay Canvas. It is one of the last things to be rendered in a frame.

Moving something rotated on a custom pivot Unity

I've created an arm with a custom pivot in Unity which is essentially supposed to point wherever the mouse is pointing, regardless of the orientation of the player. Now, this arm looks weird when pointed to the side opposite the one it was drawn at, so I use SpriteRenderer.flipY = true to flip the sprite and make it look normal. I also have a weapon at the end of the arm, which is mostly fine as well. Now the problem is that I have a "FirePoint" at the end of the barrel of the weapon, and when the sprite gets flipped the position of it doesn't change, which affects particles and shooting position. Essentially, all that has to happen is that the Y position of the FirePoint needs to become negative, but Unity seems to think that I want the position change to be global, whereas I just want it to be local so that it can work with whatever rotation the arm is at. I've attempted this:
if (rotZ > 40 || rotZ < -40) {
rend.flipY = true;
firePoint.position = new Vector3(firePoint.position.x, firePoint.position.y * -1, firePoint.position.z);
} else {
rend.flipY = false;
firePoint.position = new Vector3(firePoint.position.x, firePoint.position.y * -1, firePoint.position.z);
}
But this works on a global basis rather than the local one that I need. Any help would be much appreciated, and I hope that I've provided enough information for this to reach a conclusive result. Please notify me should you need anything more. Thank you in advance, and have a nice day!
You can use RotateAround() to get desired behaviour instead of flipping stuff around. Here is sample code:
public class ExampleClass : MonoBehaviour
{
public Transform pivotTransform; // need to assign in inspector
void Update()
{
transform.RotateAround(pivotTransform.position, Vector3.up, 20 * Time.deltaTime);
}
}