Objects instantiating at Run Time, but with a delay between each object - c#

What I want to do is instantiate a prefab in a circle, but over time. So that one prefab will appear and the others will appear over time. Should I be using a coroutine to achieve this effect?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Fire_Circle : MonoBehaviour
{
public GameObject prefab;
public int numberOfObjects = 20;
public float radius = 5f;
public float height;
void Start()
{
for (int i = 0; i < numberOfObjects; i++)
{
float angle = i * Mathf.PI * 2 / numberOfObjects;
Vector3 pos = new Vector3(Mathf.Cos(angle), height / radius,
Mathf.Sin(angle)) * radius;
Instantiate(prefab, pos, prefab.transform.rotation );
}
}
}

Coroutines are certainly a nice option:
void Start()
{
StartCoroutine(SpawnObjs());
}
IEnumerator SpawnObjs()
{
for (int i = 0; i < numberOfObjects; i++)
{
float angle = i * Mathf.PI * 2 / numberOfObjects;
Vector3 pos = new Vector3(Mathf.Cos(angle), height / radius,
Mathf.Sin(angle)) * radius;
Instantiate(prefab, pos, prefab.transform.rotation );
yield return new WaitForSeconds(.8f);
}
}

Related

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 move an object randomly in small area from his current position?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TargetMove : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
transform.transform.position = RandomVector(0.1f, 0.5f);
}
private Vector3 RandomVector(float min, float max)
{
var x = Random.Range(min, max);
var y = Random.Range(min, max);
var z = Random.Range(min, max);
return new Vector3(transform.position.x + x, transform.position.y + y, transform.position.z);
}
}
I want it to move in small area randomly between 0.1 and 0.5 but since I did + x and + y it keep changing position and move far far nonstop.
return new Vector3(transform.position.x + x, transform.position.y + y, transform.position.z);
What should I do instead transform.position.x + x and transform.position.x + y ?
This is what I wanted :
The script is attached to a cube.
Another script is attached to the sci-fi drone I have that all is do is making the drone LookAt the cube.
That's it this create a lost control effect of the sci-fi drone shooting out of control.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TargetMove : MonoBehaviour
{
[SerializeField] private List<Vector3> waypoints = new List<Vector3>(); // Hom many items you want, will show in Inspector
public float speed;
private int current = 0;
private float WPradius = 1;
private void Start()
{
GetRandom();
}
private void Update()
{
MoveBetweenWaypoints();
}
private void GetRandom()
{
for (int i = 0; i < 30; i++)
{
waypoints.Add(new Vector3(Random.Range(transform.position.x, transform.position.x + 3f),
Random.Range(transform.position.y, transform.position.y + 3f),
transform.position.z));
}
}
private void MoveBetweenWaypoints()
{
if(Vector3.Distance(waypoints[current], transform.position) < WPradius)
{
current = Random.Range(0, waypoints.Count);
if(current >= waypoints.Count)
{
current = 0;
}
}
transform.position = Vector3.MoveTowards(transform.position, waypoints[current], Time.deltaTime * speed);
}
}

How can I add equal gap between gameobjects?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DropDown : MonoBehaviour
{
public GameObject dropdownPrefab;
public int numberOfObjects;
public float speed = 1.5f;
public float duration = 5f;
public Vector3 startPos;
public Vector3 endPos;
public float distanceToMove = 2f;
public float gap;
private List<GameObject> dropDownObjects = new List<GameObject>();
private List<Vector3> endPositions = new List<Vector3>();
private void Start()
{
for (int i = 0; i < numberOfObjects; i++)
{
dropDownObjects.Add(Instantiate(dropdownPrefab, transform.parent));
endPositions.Add(new Vector3(dropDownObjects[i].transform.position.x,
dropDownObjects[i].transform.position.y + i + 2,
dropDownObjects[i].transform.position.z) - Vector3.up * distanceToMove);
}
startPos = dropDownObjects[0].transform.position;
}
private void OnMouseDown()
{
StartCoroutine(StartDropObjects());
}
private IEnumerator StartDropObjects()
{
for (int i = 0; i < dropDownObjects.Count; i++)
{
// Random wait period before rotation starts
if (i == 0)
{
//yield return new WaitForSeconds(0);
}
else
{
//yield return new WaitForSeconds(Random.Range(0, 2f));
}
yield return new WaitForSeconds(2f);
StartCoroutine(Drop(dropDownObjects[i].transform, duration, endPositions[i]));
}
}
private IEnumerator Drop(Transform objectToDrop, float duration, Vector3 endpos)
{
float t = 0.0f;
while (t < duration)
{
t += Time.deltaTime;
objectToDrop.transform.position = Vector3.MoveTowards(objectToDrop.transform.position, endpos, speed * Time.deltaTime);
yield return null;
}
}
}
The objects should be moving down but when I'm adding the gap in this case the gap is i + 2 for example if I = 0 then the gap is 2 then I = 1 so the gap will be 3 then I = 2 the gap is 4.
endPositions.Add(new Vector3(dropDownObjects[i].transform.position.x,
dropDownObjects[i].transform.position.y + i + 2,
dropDownObjects[i].transform.position.z) - Vector3.up * distanceToMove);
But I want to have equal gaps between the objects. For example if I will set the gap value to 1 there will be equal spaces/gaps between the objects and if the gap value is 5 then equal 5 between each two objects.
The problem now is that I getting higher each time by 1 so the gaps are not equal.
And also the objects are moving up and not down when I'm doing: + i + 2
In the screenshot the objects moved up instead down and the top two objects seems too close to each other. And the gaps are not equal.
But the idea is when the objects are moving to the target destination endPositions that each one will move to his on endPosition depending on the gap.
So in the end the objects should be like this :
The first one is the one on the most bottom. The last one is the one on the top.
The first dropDownObjects[0] object moved to his endPosition the farest endPosition. In this case distanceToMove is set to 2.
Then dropDownObjects1 is moving to his distanceToMove - the gap. And so on. This is the logic that in the end after all objects move they will have equal gaps.
And the first moved object is the one that should get to the distnaceToMove.
Problem is not here:
endPositions.Add(new Vector3(dropDownObjects[i].transform.position.x,
dropDownObjects[i].transform.position.y + i + 2,
dropDownObjects[i].transform.position.z) - Vector3.up * distanceToMove);
But here:
private IEnumerator Drop(Transform objectToDrop, float duration, Vector3 endpos)
{
float t = 0.0f;
while (t < duration)
{
t += Time.deltaTime;
objectToDrop.transform.position = Vector3.MoveTowards(objectToDrop.transform.position, endpos, speed * Time.deltaTime);
yield return null;
}
}
Because you are using the same duration for all objects, but they have a different distance. The last objects just don't have time to finish their movement.
You can check this by changing your method Drop(...) to this code:
private IEnumerator Drop(Transform objectToDrop, float duration, Vector3 endpos)
{
while (objectToDrop.transform.position != endpos)
{
objectToDrop.transform.position = Vector3.MoveTowards(objectToDrop.transform.position, endpos, speed * Time.deltaTime);
yield return null;
}
}
I would change how you're determining your endPositions to make it easier to configure.
I would define a starting distance and a max distance and you can calculate the gap programmatically by interpolating between the starting distance and minDistanceToMove maxDistanceToMove using Mathf.Lerp with a t of (float)i/(numberOfObjects-1):
public float minDistanceToMove = 0.5f;
public float maxDistanceToMove = 2f;
private void Start()
{
for (int i = 0; i < numberOfObjects; i++)
{
dropDownObjects.Add(Instantiate(dropdownPrefab, transform.parent));
float t = (float)i/(numberOfObjects-1);
float distDown = Mathf.Lerp(minDistanceToMove,maxDistanceToMove,t);
endPositions.Add(new Vector3(dropDownObjects[i].transform.position.x,
dropDownObjects[i].transform.position.y,
dropDownObjects[i].transform.position.z) - Vector3.up * distDown);
}
startPos = dropDownObjects[0].transform.position;
}
Alternatively, you can set only a minDistanceToMove and a gap size and then calculate distDown that way:
public float minDistanceToMove = 0.5f;
public float gapSize = 0.5f;
private void Start()
{
for (int i = 0; i < numberOfObjects; i++)
{
dropDownObjects.Add(Instantiate(dropdownPrefab, transform.parent));
float distDown = minDistanceToMove + gapSize * i;
endPositions.Add(new Vector3(dropDownObjects[i].transform.position.x,
dropDownObjects[i].transform.position.y,
dropDownObjects[i].transform.position.z) - Vector3.up * distDown);
}
startPos = dropDownObjects[0].transform.position;
}
Either way, you then need to change Drop to last for however long it takes for the panel to drop to its destination:
private IEnumerator Drop(Transform objectToDrop, float duration, Vector3 endpos)
{
// duration is unused. It is in the method signature here to avoid
// confusion when swapping with the alternative below
while (objectToDrop.transform.position != endPos)
{
objectToDrop.transform.position = Vector3.MoveTowards(
objectToDrop.transform.position, endpos, speed * Time.deltaTime);
yield return null;
}
}
Alternatively, you can make each panel take the given duration and calculate the speed necessary to traverse the distance:
private IEnumerator Drop(Transform objectToDrop, float duration, Vector3 endpos)
{
float mySpeed = Vector3.Distance(
objectToDrop.transform.position, endpos) / duration;
while (objectToDrop.transform.position != endPos)
{
objectToDrop.transform.position = Vector3.MoveTowards(
objectToDrop.transform.position, endpos, mySpeed * Time.deltaTime);
yield return null;
}
}

Multiple GameObjects Instantiated Between Two Angles

I am trying to spawn n GameObjects between angles equally spaced out.
Ideally, I'd like to be able to adjust the "cone" to so that the enemy can shoot in any direction, in any density.
Can someone see what I have done wrong?
These are enemy projectiles. That I am trying "scatter shot". Think of the dragon from Level 1 in NES Zelda:
Though, I am not entirely sure what is happening with my implementation.
Projectile.cs
public Vector2 moveDirection = Vector2.zero;
public float moveSpeed = 4.0f;
private void FixedUpdate()
{
_body.MovePosition(transform.position + (new Vector3(moveDirection.x, moveDirection.y, 0).normalized) * (moveSpeed * Time.deltaTime));
}
MultiShooter.cs
public GameObject projectileObject;
public Transform projectileEmitter;
[Range(2, 10)] public int numToShoot = 3;
[Space]
[Range(0, 360)] public int angle = 30;
[Range(1, 50)] public float rayRange = 10.0f;
[Range(0, 360)] public float coneDirection = 180;
public void OnStartShooting()
{
for (int i = 1; i <= numToShoot; i++)
{
var projectile = Instantiate(projectileObject);
projectile.transform.position = projectileEmitter.position;
var projectileScript = projectile.GetComponent<Projectile>();
projectileScript.moveDirection = DirFromAngle(((angle / i) + coneDirection)* pointDistance, rayRange);
projectile.SetActive(true);
}
}
public Vector3 DirFromAngle(float angleInDegrees, float range)
{
return Quaternion.AngleAxis(angleInDegrees, Vector3.forward) * transform.up * range;
}
Editor script to show the lines.
private void OnSceneGUI()
{
MultiShooter fow = (MultiShooter)target;
Handles.color = Color.magenta;
Vector3 upDirection = fow.DirFromAngle((-fow.angle / 2.0f) + fow.coneDirection, fow.rayRange);
Vector3 dwDirection = fow.DirFromAngle((fow.angle / 2.0f) + fow.coneDirection, fow.rayRange);
Handles.DrawLine(fow.projectileEmitter.position, upDirection);
Handles.DrawLine(fow.projectileEmitter.position, dwDirection);
}
For the ith object, the fraction of angular distance from one side of the range to the other can be expressed with the formula i/(numToShoot-1) for values ofnumToShoot > 1. If numToShoot == 1, you can just have the percentage be 50% to shoot right in the middle of the range.
Your drawing method seems to work with coneDirection ± angle/2, so we can subtract .5 from this angular percentage to express it in terms of angular distance from the center of the range.
Then we can use the same math as the drawing method with coneDirection + angle percentage * angle range:
public void OnStartShooting()
{
for (int i = 0; i < numToShoot; i++)
{
var projectile = Instantiate(projectileObject);
projectile.transform.position = projectileEmitter.position;
var projectileScript = projectile.GetComponent<Projectile>();
float anglePercentage;
if (numToShoot == 1)
anglePercentage = 0f;
else
anglePercentage = (float)i/(numToShoot-1f) - .5f;
projectileScript.moveDirection = DirFromAngle(
coneDirection
+ anglePercentage * angle, rayRange);
projectile.SetActive(true);
}
}

How do I make a pool cue rotate around the cue ball?

I want the pool cue to rotate around the cue ball as the player drags the mouse, I've played some pool games on the internet and they all seem to work this way. This will eventually be a browser game.
This game isn't mine, but it has the basic mechanic that I want (I don't care about the lines that are displayed, I just want the rotate and hit mechanic) https://www.crazygames.com/game/8-ball-billiards-classic
I have tried some orbiting scripts so far, none of them work.
I've tried some scripts that make objects orbit based on time hoping to make it so it orbits with the mouse dragging instead of time. I also can't get the cue to constantly face the cue ball.
This code has gotten me the closest.
public int vertexCount = 40;
public float lineWidth = 0.2f;
public float radius;
public bool circleFillscreen;
//circle variables
static float timeCounter = 0;
float width;
float height;
private LineRenderer lineRenderer;
private void Awake()
{
lineRenderer = GetComponent<LineRenderer>();
SetupCircle();
}
void Update()
{
timeCounter += Time.deltaTime;
float x = Mathf.Cos(timeCounter);
float y = 0;
float z = Mathf.Sin(timeCounter);
}
private void SetupCircle()
{
lineRenderer.widthMultiplier = lineWidth;
if (circleFillscreen)
{
radius = Vector3.Distance(Camera.main.ScreenToWorldPoint(new Vector3(0f, Camera.main.pixelRect.yMax, 0f)),
Camera.main.ScreenToWorldPoint(new Vector3(0f, Camera.main.pixelRect.yMin, 0f))) * 0.5f - lineWidth;
}
float deltaTheta = (2f * Mathf.PI) / vertexCount;
float theta = 0F;
lineRenderer.positionCount = -vertexCount;
for (int i = 0; i < lineRenderer.positionCount; i++)
{
Vector3 pos = new Vector3(radius * Mathf.Cos(theta), radius * Mathf.Sin(theta), 0f);
lineRenderer.SetPosition(i, pos);
theta += deltaTheta;
}
}
#if UNITY_EDITOR
private void OnDrawGizmos()
{
float deltaTheta = (2f * Mathf.PI) / vertexCount;
float theta = 0f;
Vector3 oldPos = Vector3.zero;
for (int i = 0; i < vertexCount + 1; i++)
{
Vector3 pos = new Vector3(radius * Mathf.Cos(theta), 0F,radius * Mathf.Sin(theta));
Gizmos.DrawLine(oldPos, transform.position + pos);
oldPos = transform.position + pos;
theta += deltaTheta;
}
}
#endif
}
Not really getting any error messages, code "works" but doesn't work.

Categories