Unity: How to choose specific zone in Vector3(X, 0, Z)) - c#

An example of my code, lets say I have a solar system, center being the sun, this code will spawn all the planets around it randomly with a set radius for each planet, in the Vector3 I change and randomize the X and Z, leaving Y at 0.
This is the code, planetInt is the number of planet in the for loop, 0 being first planet up to the 8 planet.
private float orbitRadius = 3150f;
// Get Radius
float newOrbitRadius = orbitRadius * (planetInt + 1);
// Get Random Positon (here)
Vector3 randomPlanetPosition = new Vector3(Random.insideUnitSphere.x * newOrbitRadius, 0, Random.insideUnitSphere.z * newOrbitRadius);
How would I change the Vector3( X and Z) to be in a specific zone, for example I want all the positions to be in the same area like this picture.
How do specify a specific angle like the multiple ones in this image, with Y being 0.

Here is an example:
I created this script:
(I suppose your sun is at the center 0;0;0)
public class NewBehaviourScript : MonoBehaviour
{
public GameObject PlanetPrefab = null;
public int numPlanets = 20;
public float orbitLengthBase = 0.3f;
public float angleMin = 45f;
public float angleMax = 120f;
void Start()
{
for (int i = 0; i < numPlanets; i++)
{
var newPlanet = Instantiate(PlanetPrefab);
var randomRotationAngle = Random.Range(angleMin, angleMax);
var rotation = Quaternion.Euler(0, randomRotationAngle, 0);
newPlanet.transform.position = rotation * Vector3.right * orbitLengthBase * i;
}
}
}
I always assign an arbitrary base vector (here: pointing to the right, (1;0;0)) as the position of the new planet, I multiply it by some factor the change the distance from sun just for the example.
More importantly, I multiply it on the left by a quaternion (math thing to represent a rotation), that I just created with a random Y angle between the max and the min that you want.
You can play with some parameters like angleMax and angleMin to see by yourself.

Related

Drawing collider boundaries (Unity)

everyone!
I ran into the problem. I need to draw a radius of enemy attack. The radius needs to be equal radius of SphereCollider that is hanging on it. I've tried to do it with the help of LineRenderer which draws circle. Yeah, actually it draws circle correctly, but the radius of my circle is less than radius of collider on it, despite the fact that I've given the value of a variable from the GetComponent().
Does anyone know what the problem is?
Part of my code:
float x;
float z;
float change = 2 * (float)Math.PI / segments;
float angle = change;
x = Mathf.Sin(angle) * radius;
_line.SetPosition(0, new Vector3(x, 0, Mathf.Cos(angle) * radius));
for (int i = 1; i < (segments + + 2); i++)
{
x = Mathf.Sin(angle) * radius;
z = Mathf.Cos(angle) * radius;
yield return new WaitForSeconds(drawSpeed);
_line.SetPosition((int)i, new Vector3(x, 0, z));
angle += change;
}
In the comments you mentioned that you get your radius from
float radius = _collider.radius;
where _collider is your SphereCollider.
So note that the SphereCollider.radius
The radius of the sphere measured in the object's local space.
The sphere radius will be scaled by the transform's scale.
It appears to me that either your object or one of its parent is somehow scaled differently than 1,1,1 in which case the actual final radius will be influenced by that scale.
You would need to scale the radius accordingly by the transform.lossyScale like e.g.
// Get the lossyScale
// this is the localScale of all parent objects and this localScale combined
var lossyScale = _collider.transform.lossyScale;
// find the biggest extends of the lossyScale
// if you already know they are always equal anyway simply use e.g. lossyScale.x instead
float maxScale = 0;
for(var i = 0; i < 3; i++)
{
maxScale = Mathf.Max(maxScale, Mathf.Abs(lossyScale[i]);
}
float radius = _collider.radius * maxScale;
It's a little hacky, but I've used a sphere outline sprite for just this sort of thing. Just put it on the game object and make sure it is scaled same as your collider. No need for fancy line drawing.
Don't use collider component for the enemy attack range!
Instead of adding a circle collider component you should a collider via code & physics.
What should you do?
This is an example of using a collider via code & physics:
float theCircleRadios = /* You radios */;
Collider2D[] detectedEnemiesColliders = Physics2D.OverlapCircleAll(theCirclePosition, theCircleRadios, DetectedLayers);
Then make your line lineRenderer radios == theCircleRadios.

How to calculate and divide uniformly point around a circle?

Hello there everybody!
I'm trying to create a variable where you can put the number of points and the radius of a circle, and it will divide those points uniformly around the circle.
I'm trying to not use the Euler angles to set rotation or the Rotate or RotateAroundmethods.
But I am not having success...
These are how my code looks until the moment
public class PowerUps : MonoBehaviour
{
public GameObject PowerUpPrefab;
public GameObject Player;
public int PowerUpCount = 3;
public float PowerUpRadius = 1;
public Vector3 newPowerupSpace;
public GameObject[] SpawnPowerUps()
{
//get player positin
Vector3 anchorPoint = Player.transform.position;
GameObject[] SpawnPowerUps = new GameObject[PowerUpCount];
float angleStep = Mathf.HalfToFloat((ushort)(360.0 / PowerUpCount));
for (int i = 0; i < PowerUpCount; i++)
{
float theta = i * angleStep;
newPowerupSpace.x = anchorPoint.x + (PowerUpRadius * Mathf.Cos(theta));
newPowerupSpace.y = anchorPoint.y + (PowerUpRadius * Mathf.Sin(theta));
SpawnPowerUps[i] = (GameObject)Instantiate(PowerUpPrefab, newPowerupSpace, Quaternion.identity);
}
return null;
}
}
Any suggestions?
Update:
I changed the
float angleStep = Mathf.HalfToFloat((ushort)(360.0 / PowerUpCount));
to
float angleStep = ((ushort)((360.0 / PowerUpCount) * Mathf.Deg2Rad));
and now is working.
I feel kind of stupid....
Update 2:
After doing some tests, I notice that some numbers don't divide uniformly across the circle. That's because I was converting de circle degrees to radium in the wrong part.
Here's how the code looks like now:
public GameObject[] SpawnPowerUps()
{
Vector3 anchorPoint = Player.transform.position;
GameObject[] SpawnPowerUps = new GameObject[PowerUpCount];
float angleStep = ((ushort)(360.0 / PowerUpCount));
for (int i = 0; i < PowerUpCount; i++)
{
float theta = i * angleStep;
newPowerupSpace.x = anchorPoint.x + (PowerUpRadius * Mathf.Cos(theta * Mathf.Deg2Rad));
newPowerupSpace.y = anchorPoint.y + (PowerUpRadius * Mathf.Sin(theta * Mathf.Deg2Rad));
SpawnPowerUps[i] = (GameObject)Instantiate(PowerUpPrefab, newPowerupSpace, Quaternion.identity);
}
return null;
}
}
To describe a circle in 3D it should have three parameters, Position, Radius and Normal. The normal can be used to create a transform from the unit circle to the 3D space. This example uses instance methods instead of static methods for cross/dot/normalization, but it should be trivial to translate to the unity3D conventions.
First we create an arbitrary vector that is orthogonal to the normal:
public static Vector3 GetOrthogonal(this Vector3 self)
{
self = self.Normalized();
if (Math.Abs(self.Dot(Vector3.UnitX)) > 0.9)
{
return self.Cross(Vector3.UnitY).Normalized();
}
return self.Cross(Vector3.UnitX).Normalized();
}
We can then create two vectors that are orthogonal to the normal, and to each other:
var xAxis = normal.GetOrthogonal();
var yAxis = xAxis.Cross(normal).Normalized();
Getting the points is then simply multiplying each coordinate with the corresponding axis:
var x = xAxis * (PowerUpRadius * Mathf.Cos(theta * Mathf.Deg2Rad));
var y = yAxis * (PowerUpRadius * Mathf.Sin(theta * Mathf.Deg2Rad));
newPowerupSpace = x + y + anchorPoint;
You could do the same by producing a transform matrix and transforming the 2D points. But this is fairly simple to do.

How to make two objects inversely orbiting a point do so in a curve? Unity, C#

So I have this function attached to a sphere and in inverse one attached to another. They are rigged to emit a trail and the game object they are orbiting around is a sphere which is locked at 0,0,0. This is my code so far :
float t = 0;
float speed;
float width;
float height;
int cat = 0;
public GameObject orbit; //the object to orbit
// Use this for initialization
void Start()
{
speed = 2;
width = 5;
height = 2;
InvokeRepeating("test", .001f, .009f);
}
void test()
{
t += Time.deltaTime * speed;
Vector3 orbitv = orbit.transform.position;
float inc = .0000000001f;
inc += inc + t;
float angmom = .00001f;
angmom = angmom + t;
float x = orbitv.x + Mathf.Cos(t);
float z = orbitv.z + inc; //+ (Mathf.Cos(t)*Mathf.Sin(t));
float y = orbitv.y + Mathf.Sin(t);
transform.position = new Vector3(x, y, z);
}}
Which does this:
Instead of moving in the z direction exclusively, I'd like them to continue their current rotation, but in a circle around the sphere at 0,0,0 while staying at the same y level. Anyone have any ideas how I can do this?
Edit: This is what I'm trying to do:
Here's some code I cooked up for you.
All the movement is achieved with basic trigonometric functions and some easy vector math.
To tackle problems like these, try to break things down like I did with dividing the movement into circular/up-down & sideways. This lets you create the ring effect.
Adding more intertwined waves should be trivial by changing the phase of the oscillations and adding more trails.
public class Orbit : MonoBehaviour {
float t = 0;
public float speed;
public float width;
public float height;
public float radius;
int cat = 0;
public GameObject center; //the object to orbit
public Vector3 offset;
void Update()
{
t = Time.time * speed;
OrbitAround();
AddSideways();
}
void OrbitAround()
{
float x = radius * Mathf.Cos(t);
float y = Mathf.Sin(offset.y * t);
float z = radius * Mathf.Sin(t);
transform.position = new Vector3(x, y, z);
}
void AddSideways()
{
float x = Mathf.Cos(offset.x * t);
Vector3 dir = transform.position - center.transform.position;
transform.position += dir.normalized * x;
}
}
It should give you a trail like this:
You can play around with the Vec3 offset which changes the frequency of the oscillations and essentially lets you choose the number of rings.

Controlling both angles of a Ray

I'm new to Unity and have a problem I can't figure out. I want objects to spawn randomly at a distance of 20 from a FPS player. You could say the objects need to spawn on the surface of a half sphere with the player as the center. But: not all of that sphere can be used. The "highest" part is too high for objects to spawn, so basically it's a sphere with the top cut off.
What I tried:
thePosition = Random.onUnitSphere * 20 + object2.transform.position;
Obviously, this takes into account the whole sphere (should be only half a sphere) and doesn't take into account the "cut off" part.
So I thought: I basically want to make a ray that can pivot on the ground (so the max angle is 360°), and can go up and down, with a max angle of 90°. Think of it like a canon that can turn (pivot) and go up/down with an angle. Here's an image of what I mean:
So I tried:
Vector3 raydirection = new Vector3 (1f, 1f, 0);
raydirection = Quaternion.Euler (45, 0, 0) * raydirection;
Ray ray = new Ray (player.transform.position, raydirection);
thePosition = ray.GetPoint (20);
But that doesn't allow me to control the pivot angle (angle 1) and the "up-down" angle (angle 2) separately.
So my question is: how can I make it so that I can control both angles of this ray? Because if I can do that, I can just take a random number between 0 and 360 for the pivoting part, and between 0 and 90 for the up/down part.
Any help is much appreciated!
Coincidentally, I needed something very similar to this. The following Behavior will spawn a certain prefab (objectToSpawn) exactly spawnCount times within the set parameters.
The helper class (bottom code) generates a Vector from Yaw, Pitch and a Vector (basically the distance in your case).
What it does:
Pick a random direction (yaw and pitch) within set parameters
Pick a random distance (sounds like you can omit this step)
Calculate the vector
Spawn object
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RandomSpawner : MonoBehaviour {
public GameObject objectToSpawn;
public int spawnCount;
public float minDistance = 2;
public float maxDistance = 10;
public float minPitchDegrees = 0;
public float maxPitchDegrees = 45;
public float minYawDegrees = -180;
public float maxYawDegrees = 180;
void Start ()
{
for (int i = 0; i < spawnCount; i++)
{
float distance = minDistance + Random.value * (maxDistance - minDistance);
float yaw = minYawDegrees + Random.value * (maxYawDegrees - minYawDegrees);
float pitch = minPitchDegrees + Random.value * (maxPitchDegrees - minPitchDegrees);
Vector3 position = RotationHelper.ConvertYawPitch (Vector3.forward * distance, yaw, pitch);
Instantiate (objectToSpawn, position, Quaternion.identity);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class RotationHelper {
public static Vector3 ConvertYawPitch(Vector3 vector, float yaw, float pitch)
{
Quaternion yawRotation = Quaternion.AngleAxis (yaw, Vector3.up);
Vector3 yawedZAxis = yawRotation * Vector3.left;
Quaternion pitchRotation = Quaternion.AngleAxis (pitch, yawedZAxis);
Vector3 yawedVector = yawRotation * vector;
Vector3 position = pitchRotation * yawedVector;
return position;
}
}
In your specific case, the parameters should be:
minDistance = 20
maxDistance = 20
minPitchDegrees = 0
maxPitchDegrees = 0-90, whatever the angle is after you "cut off the top"
minYawDegrees = -180
maxYawDegrees = 180
I want objects to spawn randomly at a distance of 20 from a FPS
player.
What I understood from this is that you want to spawn objects on the ground, distant 20 units away from the player, in random directions.
You could say the objects need to spawn on the surface of a half
sphere with the player as the center.
Now, this is just another way to make things complex. No need to use the sphere to solve this.
If you want to spawn objects on the surface, easiest solution will be to get a random angle in relation with Vector3.up and walk for 20 units to find the desired point.
Script:
public class Spawner : MonoBehaviour
{
public Transform player;
public Transform prefab;
[Range(10,50)]
public float distance = 20f;
IEnumerator Start()
{
while (true)
{
yield return new WaitForSeconds(0.05f);
Spawn();
}
}
[ContextMenu("Spawn")]
public void Spawn()
{
Vector3 spawnPoint = FindPoint(player.position, distance, Random.Range(0, 360));
Instantiate(prefab, spawnPoint, Quaternion.identity, transform);
}
[ContextMenu("Clear")]
public void Clear()
{
foreach (var item in transform.GetComponentsInChildren<Transform>())
{
if (item != transform)
DestroyImmediate(item.gameObject);
}
}
Vector3 FindPoint(Vector3 center, float radius, int angle)
{
return center + Quaternion.AngleAxis(angle, Vector3.up) * (Vector3.right * radius);
}
}
Result:
Calculates random point based on player's position:
Hope this helps :)

Formula to convert position axis into time

I have a cube which i am moving in circle shape (with horizontal key input) is below code suggested.
public class Oscillator : MonoBehaviour {
float timeCounter = 0;
float speed,width, height;
public float yPosition = 30;
// Use this for initialization
void Start () {
speed = 2; width = 10; height = 10;
}
// Update is called once per frame
void Update () {
timeCounter += Time.deltaTime * speed * Input.GetAxis("Horizontal");
float x = Mathf.Sin (timeCounter)* height;
float y = yPosition;
float z = Mathf.Cos (timeCounter) * width;
transform.position = new Vector3 (x, y, z);
}
}
Now my object is moving in circular shape which is fine. Now i want to translate my objects movement into time.
Let suppose
if my object x position is 1 then it should give me time 1.0
if it is 1.5 then it should give me 1.5
it increase or decrease according to x postion of my object (or possibly throught z).
I logged my object's x position which is starting from 0 to 9.999 and then become decrease 0, then -1 to -9 then it become decrease 0 and reached to its initial position. This circular movement x values are strange for me, i am unable to form any formula that can convert my x position into time.
Please can any one help me in this purely mathematics and 3d math problem?
You could try the following:
Get the vector between origin of the circle and the 0 of your circle, like 12 on a clock. This one is constant.
Then you have the vector between the origin of the circle and the current point.
Try the following:
Vector3 from = new Vector3(0,0,1); / This is your 12
Vector3 to = GetCurrentVector();
float angle = Quaternion.FromToRotation(Vector3.up, to - from).eulerAngles.z;
Debug.Log(angle / 360f);

Categories

Resources