How can I fix this imperfect circle I made using LineRenderer? - c#

So I made this shape which I applied to a sprite via this script:
using UnityEngine;
using System.Collections;
public class CircleShapeGenerator : MonoBehaviour
{
public int segments = 100;
public float radius = 1;
public Color c1 = new Color( 1, 1, 1, 0.1f );
public Color c2 = new Color( 1, 1, 1, 0.1f );
LineRenderer line;
void Start ()
{
line = gameObject.AddComponent<LineRenderer>();
line.material = new Material(Shader.Find("Particles/Additive"));
line.SetWidth(0.05F, 0.05F);
line.SetVertexCount (segments + 1);
line.useWorldSpace = false;
}
void Update()
{
line.SetColors(c1, c2);
float angle = 20f;
for (int i = 0; i < (segments + 1); i++)
{
float x = Mathf.Sin (Mathf.Deg2Rad * angle) * radius;
float y = Mathf.Cos (Mathf.Deg2Rad * angle) * radius;
line.SetPosition( i, new Vector3( x,y,0) );
angle += (360f / segments);
}
}
}
As you can see in the screenshot, the start and end do not connect as they should. How can I fix this? I found this snippet of code on the entire internet but all give this result. Can somebody fix this or provide, perhaps, a spline solution? I think its overkill to go to a Shader solution (0 experience with shaders).

This solution could be a little bit complicated. But it'll works.
The idea is
1) Draw first segment as small segmented area.
2) Draw from seconds to last -1 segments as big segment.
3) Draw last segment as small segmented area too.
It makes seamless edge between the start segment and the end segment.
And total segment's count is not too many.
total segment = segment + 2 * subsegment
This is sample code.
using UnityEngine;
using System.Collections;
public class CircleShapeGenerator : MonoBehaviour {
public int segments = 100;
public int edgeSegments = 10;
public float radius = 1f;
int vertCount;
float increAngle, increAngleEdge;
public Color c1 = new Color( 1, 1, 1, 1f );
public Color c2 = new Color( 1, 1, 1, 1f );
LineRenderer line;
void Start ()
{
vertCount = segments + 2*edgeSegments - 2 + 1;
increAngle = 360f / segments;
increAngleEdge = increAngle/edgeSegments;
line = gameObject.AddComponent<LineRenderer>();
line.material = new Material(Shader.Find("Particles/Additive"));
line.SetWidth(0.05F, 0.05F);
line.SetVertexCount (vertCount);
line.useWorldSpace = false;
}
void Update()
{
line.SetColors(c1, c2);
//draw first segment
float angle = 0;
for (int i = 0; i < edgeSegments; i++)
{
float x = Mathf.Sin (Mathf.Deg2Rad * angle) * radius;
float y = Mathf.Cos (Mathf.Deg2Rad * angle) * radius;
line.SetPosition( i, new Vector3(x, y, 0) );
angle += increAngleEdge;
}
//draw from seconds to last-1 segment
angle -= increAngleEdge;
for (int i = 0; i < segments-2; i++)
{
angle += increAngle;
float x = Mathf.Sin (Mathf.Deg2Rad * angle) * radius;
float y = Mathf.Cos (Mathf.Deg2Rad * angle) * radius;
line.SetPosition( edgeSegments + i, new Vector3(x, y, 0) );
}
//draw last segment
for (int i = 0; i < edgeSegments+1; i++)
{
angle += increAngleEdge;
float x = Mathf.Sin (Mathf.Deg2Rad * angle) * radius;
float y = Mathf.Cos (Mathf.Deg2Rad * angle) * radius;
line.SetPosition( edgeSegments + segments - 2 + i, new Vector3(x, y, 0) );
}
}
}

Related

Mandelbrot Set function crashes

i made a sim for the Mandelbrot Set function, zn + 1 = power(zn) + c
and it work but when i get to the point were the function is unstable it crashes, now i have a boolen that when true makes a wire that connects all the circles, when its false its fine(dosent crash) but when its on it does, the code works like this:
start:
building a list of circles and making there pos by the equation, and then crating a wire between the circle and the last circle,
update:
then when you move the circle it uses the already made list of gameobj to update there pos.
you can try it here:
build
github:
git
but it crashes:(, heres the code:
private void updateCircles()
{
StartUpdateCircles();
}
private void StartCircles()
{
float x = BlackCircle.anchoredPosition.x;
float y = BlackCircle.anchoredPosition.y;
AllCircles.Add(BlackCircle.gameObject);
for (int i = 1; i < itarations; i++)
{
Vector2 RedCircleVec2 = RedCircle.anchoredPosition;
Vector2 LastCircleVec2 = AllCircles[i - 1].GetComponent<RectTransform>().anchoredPosition;
GameObject Circle = Instantiate(BlackCircle.gameObject, Vector3.zero, Quaternion.identity);
Circle.transform.SetParent(CanvasPerent);
AllCircles.Add(Circle);
x = Mathf.Pow(x, 2);
x -= Mathf.Pow(LastCircleVec2.y, 2);
x += RedCircleVec2.x;
y = (2 * LastCircleVec2.x
* LastCircleVec2.y) + RedCircleVec2.y;
Circle.GetComponent<RectTransform>().anchoredPosition = new Vector2(x, y);
if (HasWire)
{
GameObject wire = GenrateWireStart(LastCircleVec2
, Circle.GetComponent<RectTransform>().anchoredPosition);
AllWires.Add(wire);
}
}
}
private void StartUpdateCircles()
{
float x = BlackCircle.anchoredPosition.x;
float y = BlackCircle.anchoredPosition.y;
for (int i = 1; i < itarations; i++)
{
Vector2 RedCircleVec2 = RedCircle.anchoredPosition;
Vector2 LastCircleVec2 = AllCircles[i - 1].GetComponent<RectTransform>().anchoredPosition;
RectTransform ICircle = AllCircles[i].GetComponent<RectTransform>();
x = Mathf.Pow(x, 2);
x -= Mathf.Pow(LastCircleVec2.y, 2);
x += RedCircleVec2.x;
y = (2 * LastCircleVec2.x
* LastCircleVec2.y) + RedCircleVec2.y;
ICircle.anchoredPosition = new Vector2(x, y);
if (HasWire)
{
GenrateWireUpdate(LastCircleVec2
,ICircle.anchoredPosition, i);
}
}
}
public GameObject GenrateWireStart(Vector2 NodeA, Vector2 NodeB)
{
GameObject Connector = new GameObject("connector", typeof(Image));
Connector.transform.SetParent(CanvasPerent);
RectTransform ConnectorRT = Connector.GetComponent<RectTransform>();
ConnectorRT.anchorMin = new Vector2(0, 0);
ConnectorRT.anchorMax = new Vector2(0, 0);
Connector.GetComponent<Image>().color = new Color(0f, 0f, 0f, 0.25f);
Vector2 dir = (NodeB - NodeA).normalized;
float distance = Vector2.Distance(NodeA, NodeB);
ConnectorRT.sizeDelta = new Vector2(distance, 0.005f);
ConnectorRT.position = NodeA + dir * distance * .5f;
ConnectorRT.localEulerAngles = new Vector3(0, 0, UtilsClass.GetAngleFromVectorFloat(dir));
return Connector;
}
public void GenrateWireUpdate(Vector2 NodeA, Vector2 NodeB, int i)
{
RectTransform ConnectorRT = AllWires[i - 1].GetComponent<RectTransform>();
Vector2 dir = (NodeB - NodeA).normalized;
float distance = Vector2.Distance(NodeA, NodeB);
ConnectorRT.sizeDelta = new Vector2(distance, 0.005f);
ConnectorRT.position = NodeA + dir * distance * .5f;
ConnectorRT.localEulerAngles = new Vector3(0, 0, UtilsClass.GetAngleFromVectorFloat(dir));
}
pls help, thank you.
I looked briefly into your code and you seem to get some invalid positions like infinite / undefined from your calculations or just some positions too far away for Unity.
I could remove these by simply limiting positions to e.g.
x = Mathf.Clamp(Mathf.Pow(x, 2), -Screen.width, Screen.width);
x = Mathf.Clamp(x - Mathf.Pow(LastCircleVec2.y, 2), -Screen.width, Screen.width);
x = Mathf.Clamp(x + RedCircleVec2.x, -Screen.width, Screen.width);
y = Mathf.Clamp((2 * LastCircleVec2.x * LastCircleVec2.y) + RedCircleVec2.y, -Screen.width, Screen.width);
which simply limits all positions to some off-screen max positions

Create a hexagonal grid where I can get the position of the corners

I find a lot of examples of creating a hex grid like the following. But I'm having a hard time understanding how I might have a list of the corners in a hex grid. Basically I'd want a character to move along the line of the grid instead of the center. so I want to grab the position of the next corner in the hex grid and move them there.
I was thinking of using a basic hex grid code to create the prefabs in the right place and then just add empty game objects on each corner of the prefab, but then I have a bunch of overlapping positions that are shared corners for each hexagon. I thought I could delete them if they are overlapping but it just all seems too brute force and hard to keep track of. I'd love to hear some ideas on approaching something like this. By the way I'd also want to know the center of the hex besides knowing the corners.
this code successfully creates a hex grid pattern where I can add a hex shaped game object to instance.
using UnityEngine;
public class Grid : MonoBehaviour
{
public Transform hexPrefab;
public int gridWidth = 11;
public int gridHeight = 11;
float hexWidth = 1.732f;
float hexHeight = 2.0f;
public float gap = 0.0f;
Vector3 startPos;
void Start()
{
AddGap();
CalcStartPos();
CreateGrid();
}
void AddGap()
{
hexWidth += hexWidth * gap;
hexHeight += hexHeight * gap;
}
void CalcStartPos()
{
float offset = 0;
if (gridHeight / 2 % 2 != 0)
offset = hexWidth / 2;
float x = -hexWidth * (gridWidth / 2) - offset;
float z = hexHeight * 0.75f * (gridHeight / 2);
startPos = new Vector3(x, 0, z);
}
Vector3 CalcWorldPos(Vector2 gridPos)
{
float offset = 0;
if (gridPos.y % 2 != 0)
offset = hexWidth / 2;
float x = startPos.x + gridPos.x * hexWidth + offset;
float z = startPos.z - gridPos.y * hexHeight * 0.75f;
return new Vector3(x, 0, z);
}
void CreateGrid()
{
for (int y = 0; y < gridHeight; y++)
{
for (int x = 0; x < gridWidth; x++)
{
Transform hex = Instantiate(hexPrefab) as Transform;
Vector2 gridPos = new Vector2(x, y);
hex.position = CalcWorldPos(gridPos);
hex.parent = this.transform;
hex.name = "Hexagon" + x + "|" + y;
}
}
}
}

How can I make a circle from grid of GameObjects?

What I am trying to achieve is something like this:
What I have so far is the edges for the circles.
I know this would involve a nested for loop. This is what I have so far:
public GameObject player;
private GameObject playerGrid;
public int numOfObjects;
private Vector3 centerPos;
public int size = 2;
public Vector2 speed = new Vector2(50, 50);
private float smoothTime = 0.25f;
void Start()
{
playerGrid = new GameObject();
centerPos = transform.position;
for (int i = 0; i < numOfObjects; i++)
{
float pointNum = (i * 1.0f) / numOfObjects;
float angle = pointNum * Mathf.PI * 2;
float r = size / 2 * (Mathf.PI);
float x = Mathf.Sin(angle) * r;
float y = Mathf.Cos(angle) * r;
Vector3 pointPos = new Vector3(x, y, 0) + centerPos;
GameObject obj = Instantiate(player, pointPos, Quaternion.identity);
obj.transform.SetParent(playerGrid.transform);
}
}
I am stuck on how to implement the conditional for the nested for loop. Also, I have trouble understanding the calculations of column positions in the nested for loop. I believe the conditional would be the start and end of I for that column or row: for(int j = i + 1; j < i - 1, j++)
For the col positions, I would think it would be incrementing the angle enough to give the square its space for that column: float x = (Mathf.Sin(angle) + somethingHere) * r;
I just not sure how to progress from here.
Here's a simple way to draw a circle:
public float circleRadius = 5f;
public float objectSize = 1f;
void OnDrawGizmos()
{
for (var x = -circleRadius; x <= circleRadius; x++)
{
for (var y = -circleRadius; y <= circleRadius; y++)
{
var pos = new Vector3(x, 0f, y);
if (pos.magnitude >= circleRadius) continue;
Gizmos.DrawSphere(pos * (objectSize * 2f), objectSize);
}
}
}

How can I set random positions on radius?

In this script I'm creating a circle with specific radius size and get the radius size :
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(LineRenderer))]
public class DrawRadiusAroundTurret : MonoBehaviour
{
[Range(0, 50)]
public int segments = 50;
[Range(0, 5)]
public float xradius = 5;
[Range(0, 5)]
public float yradius = 5;
[Range(0.1f, 5f)]
public float width = 0.1f;
LineRenderer line;
void Start()
{
line = gameObject.GetComponent<LineRenderer>();
line.enabled = true;
line.positionCount = segments + 1;
line.widthMultiplier = width;
line.useWorldSpace = false;
CreatePoints();
}
private void Update()
{
CreatePoints();
}
public Vector3[] CreatePoints()
{
line.widthMultiplier = width;
float x;
float y;
float z;
float angle = 20f;
for (int i = 0; i < (segments + 1); i++)
{
x = Mathf.Sin(Mathf.Deg2Rad * angle) * xradius;
y = Mathf.Cos(Mathf.Deg2Rad * angle) * yradius;
line.SetPosition(i, new Vector3(x, 0f, y));
angle += (380f / segments);
}
var positions = new Vector3[line.positionCount];
return positions;
}
}
And in this script I have this method and I want the last point/s to be set randomly on the radius edge positions :
private void GeneratePointsInTracks()
{
var startPoints = GameObject.FindGameObjectsWithTag("Start Point");
var curvedLines = GameObject.FindGameObjectsWithTag("Curved Line");
for (int i = 0; i < startPoints.Length; i++)
{
for (int x = 0; x < numberOfPointsInTrack; x++)
{
GameObject go = Instantiate(tracksPrefab, curvedLines[i].transform);
go.name = "Point In Track";
go.transform.position = turrent.position + new Vector3(Random.Range(-100f, 100f), Random.Range(-100f, 100f), Random.Range(-100f, 100f));
if(x == numberOfPointsInTrack - 1)
{
go.name = "Last Point In Track";
for(int y = 0; y < drawRadius.CreatePoints().Length; y++)
{
go.transform.position = new Vector3(Random.Range(0,1)[y].x,
drawRadius.CreatePoints()[y].y,
drawRadius.CreatePoints()[y].z);
}
}
}
}
}
I tried this :
go.transform.position = new Vector3(Random.Range(0,1)[y].x,
drawRadius.CreatePoints()[y].y,
drawRadius.CreatePoints()[y].z);
but the random on the x give error :
Cannot apply indexing with [] to an expression of type 'int'
The first script create a circle like this :
And this is an example I drawed in paint just to show what I mean that I said I want the endPoints in the second script to be position randomly on the circle edges :
So each "Last Point In Track" object should be position randomly on the circle edge like in the second screenshot.
If you know the center and radius it is fairly easy to get random points on the circle:
go.name = "Last Point In Track";
Vector2 p = Random.insideUnitCircle.normalized * radius;
go.transform.position = center + new Vector3(p.x, 0, p.y);
To get rid of the edge case where Random.insideUnitCircle is to small to be normalized you should use:
Vector2 RandomOnUnitCircle(){
Vector2 result = Vector2.zero;
do{
result = Random.insideUnitCircle.normalized;
}while(result == Vector2.zero);
return result;
}
I think what you want is this:
Vector3[] points = drawRadius.CreatePoints(); //get all edge points
Vector3 randomPoint = points[Random.Range(0, points.Length)]; //pick a random one
go.transform.position = randomPoint; //set go.transform.position to position of random point
Sorry if I am misunderstanding your intentions, but I hope this works for you!

Can I have some help optimizing this script

I wrote a infinite terrain script which works! Saddly everytime the player moves a chunk it lags for a moment. I know my code isn't great but I'm here to learn why :D
I'm unsure of what else to do. I've looked online and found no simple or understandable solution to me because I just don't know enough so I tried to write it on my own and it works but barley.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GEN_InfiniteTerrain : MonoBehaviour
{
public GameObject targetObject;
public GameObject chunkObject;
public int chunkSize;
public float unitSize;
public int renderDistance;
Dictionary<Vector2, GameObject> gridOfChunks = new Dictionary<Vector2, GameObject>();
List<Vector2> expectedChunkGridPositions = new List<Vector2>();
public float noiseScale;
// Infinite terrain values
float absoluteChunkSize;
private void Start()
{
// Calculate absolute chunk size
GetAbsoluteChunkSize();
// Generate base world
GenerateBase();
}
Vector2 lastTargetGridPosition = Vector2.zero;
private void LateUpdate()
{
// Get the targets position in world space
Vector3 targetAbsolutePosition = targetObject.transform.position;
// Convert the targets world position to grid position (/ 10 * 10 is just rounding to 10)
Vector2 targetGridPosition = new Vector2();
targetGridPosition.x = Mathf.RoundToInt(targetAbsolutePosition.x / 10) * 10 / absoluteChunkSize;
targetGridPosition.y = Mathf.RoundToInt(targetAbsolutePosition.z / 10) * 10 / absoluteChunkSize;
if (targetGridPosition - lastTargetGridPosition != Vector2.zero)
{
GenerateExpectedChunkAreas(targetGridPosition);
UpdateChunkPositions(targetGridPosition);
}
lastTargetGridPosition = targetGridPosition;
}
void GenerateBase()
{
for (int x = -renderDistance / 2; x < renderDistance / 2; x++)
{
for (int z = -renderDistance / 2; z < renderDistance / 2; z++)
{
Vector2 gridPosition = new Vector2(x, z);
Vector3 worldPosition = new Vector3(x * (unitSize * chunkSize), 0, z * (unitSize * chunkSize));
GameObject chunk = Instantiate(chunkObject, worldPosition, Quaternion.identity);
chunk.GetComponent<GEN_Chunk>().gridPosition = gridPosition;
gridOfChunks.Add(gridPosition, chunk);
}
}
GenerateExpectedChunkAreas(Vector2.zero);
}
void GenerateExpectedChunkAreas(Vector2 targetGridPosition)
{
expectedChunkGridPositions.Clear();
for (int x = -renderDistance / 2; x < renderDistance / 2; x++)
{
for (int z = -renderDistance / 2; z < renderDistance / 2; z++)
{
Vector2 gridPosition = new Vector2(x, z) + targetGridPosition;
expectedChunkGridPositions.Add(gridPosition);
}
}
}
void UpdateChunkPositions(Vector2 targetGridPosition)
{
List<Vector2> positionsWithoutChunks = new List<Vector2>();
List<Vector2> positionsWithOldChunks = new List<Vector2>();
for (int chunkCount = 0, x = -renderDistance / 2; x < renderDistance / 2; x++)
{
for (int z = -renderDistance / 2; z < renderDistance / 2; z++)
{
Vector2 gridPosition = new Vector2(x, z) + targetGridPosition;
if(!gridOfChunks.ContainsKey(gridPosition))
{
positionsWithoutChunks.Add(gridPosition);
}
chunkCount++;
}
}
foreach (GameObject chunk in gridOfChunks.Values)
{
if(!expectedChunkGridPositions.Contains(chunk.GetComponent<GEN_Chunk>().gridPosition))
{
positionsWithOldChunks.Add(chunk.GetComponent<GEN_Chunk>().gridPosition);
}
}
for (int i = 0; i < positionsWithOldChunks.Count; i++)
{
Vector3 worldPosition = new Vector3(positionsWithoutChunks[i].x * absoluteChunkSize, 0, positionsWithoutChunks[i].y * absoluteChunkSize);
gridOfChunks[positionsWithOldChunks[i]].transform.position = worldPosition;
// Recalculating noise for chunk based on its new position does lag more but even WITHOUT this it still stutters when player moves around. ( plan to learn threading just to calculate noise on seperate threads )
// gridOfChunks[positionsWithOldChunks[i]].GetComponent<GEN_Chunk>().ApplyNoise();
}
}
void GetAbsoluteChunkSize()
{
absoluteChunkSize = unitSize * chunkSize;
}
}
I need some smooth working infinite terrain (in quotes 'infinite')
And I'd like to learn too!

Categories