Unity what's wrong with my instantiating algorithm? - c#

I dont know if I can call this algorithm. But I am working on a game in which player will move in a circular path.
As you can see in the picture player is suppose to orbit the circle. And obstacle shall be instantiated in the circle.I am trying to first create the obstacle in first half(left to the long cube) and then in the second half. But things are getting created in the next half too when code is not supposed to do that. Also, it is showing argument exception error. Please have a look at my code and tell me whether my method is wrong or my formulas are wrong or anything else.
public class ObjectInstantiater : MonoBehaviour {
DataHolder dataholder;
GameObject Obstacle;
LevelData leveldata;
private int currentlevel=0; // default level starts from 0
private List<GameObject> Inactivegameobject = new List<GameObject>(); // this object can be used
private List<GameObject> Activegameobject = new List<GameObject>();
private int totalgameobjects;
private int firsthalfgameobjects, secondhalfgameobjects;
public float outerradius;
public float innerradius;
private bool shallspawnouterradiues = true;
// Use this for initialization
void Awake () {
dataholder = (Object)GameObject.FindObjectOfType<DataHolder>() as DataHolder;
Obstacle = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
leveldata = dataholder.Leveldata[0];
}
void Start()
{
Updateleveldata();
FirstHalf();
}
public int Currentlevel
{
get { return currentlevel; }
set { currentlevel = value;
leveldata = dataholder.Leveldata[currentlevel];//sets the level data
}
}
private void Updateleveldata() // this function gets called after a round
{
totalgameobjects = Random.Range(leveldata.MinimumObstacle, leveldata.MaximumObstacle);
firsthalfgameobjects = Mathf.RoundToInt(totalgameobjects / 2);
secondhalfgameobjects = totalgameobjects - firsthalfgameobjects;
}
private void FirstHalf()
{
Debug.Log(firsthalfgameobjects);
Vector3 pos;
if (Inactivegameobject.Count < firsthalfgameobjects)
{
for (int x = 0; x <= (firsthalfgameobjects - Inactivegameobject.Count); x++)
{
GameObject obs = Instantiate(Obstacle) as GameObject;
obs.SetActive(false);
Inactivegameobject.Add(obs);
}
}
float spawnangledivision = 180 / firsthalfgameobjects;
float spawnangle = 180f;
for(int x = 0; x < firsthalfgameobjects; x++)
{
float proceduralRandomangle = spawnangle;
proceduralRandomangle = Random.Range(proceduralRandomangle , proceduralRandomangle + 2f);
if (shallspawnouterradiues)
{
pos = new Vector3(outerradius * Mathf.Cos(spawnangle), outerradius * Mathf.Sin(spawnangle), 0f);
shallspawnouterradiues = false;
}else
{
pos = new Vector3(innerradius * Mathf.Cos(spawnangle), innerradius * Mathf.Sin(spawnangle), 0f);
shallspawnouterradiues = true;
}
spawnangle += spawnangledivision;
Inactivegameobject[0].SetActive(true); // set it to 0
Inactivegameobject[0].transform.position = pos;
Activegameobject.Add(Inactivegameobject[0]);
Inactivegameobject.RemoveAt(0);
}
}
private void SecondHalf()// No need to check this
{
if (Inactivegameobject.Count < firsthalfgameobjects)
{
GameObject obs = Instantiate(Obstacle) as GameObject;
obs.SetActive(false);
Inactivegameobject.Add(obs);
}
}
}

Related

How to utilize stacking blocks under the player object(cylinder) by using rigidbodies in unity3d?

I am working on a hypercasual game project which is very similar to Matching Cubes. Initially, I was using transform to stack blocks under my cylinder(player object). But in the game there will be a ramp to jump through it and by using transform I was ignoring the physics and it passes through the ramp. So I changed it a little bit by utilizing the rigidbody for the cylinder. If there is no block it jumps through the ramp but I need it to jump with blocks. The problem is I couldn't find a way to stack them under the cylinder by using rigidbody. Tried MovePosition or AddForce but it does not work at all.
How can I stack the blocks under the cylinder but also make them jump through the ramp together?
Here is my StackManager.cs . There is a Regulator function that will check the 'picks' list and regulate the positions. It is the function where I handle all positioning.
I also tried making the positioning by transform and when it collides with ramp, stop the Regulator() and AddForce(Vector3.up*offset) but it did not move up a bit.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks;
public class StackManager : MonoBehaviour
{
public static StackManager instance;
[SerializeField] private float distanceBetweenObjs;
[SerializeField] private Transform prevObject = null;
[SerializeField] private Transform parent;
[SerializeField] private Transform cylinder;
[SerializeField] private Transform trailer;
private List<Transform> picks; // Use this to order gate and random gate
private Vector3 firstPosition;
private int comboCounter; // fever mode tracker
private Rigidbody rb;
private Transform prev;
private void Awake() {
if(instance == null) {
instance = this;
}
}
void Start()
{
rb = cylinder.gameObject.GetComponent<PlayerController>().rb;
comboCounter = 0;
picks = new List<Transform>();
firstPosition = new Vector3(cylinder.position.x, cylinder.position.y, cylinder.position.z);
}
// Update is called once per frame
void Update()
{
Regulator();
}
void CheckChildren() {
List<Transform> children = new List<Transform>();
foreach (Transform child in picks)
{
children.Add(child);
}
for(int i = 0; i < children.Count - 2; i++) {
if (children[i].isSameMaterial2(children[i+1], children[i+2])) {
comboCounter++;
Destroy(children[i].gameObject);
Destroy(children[i+1].gameObject);
Destroy(children[i+2].gameObject);
picks.Remove(children[i]);
picks.Remove(children[i+1]);
picks.Remove(children[i+2]);
};
}
if(comboCounter == 3) {
SpeedBoost(); //fever mode
comboCounter = 0;
}
}
public void PickUp(GameObject pickedObj){
pickedObj.tag = "Picked";
pickedObj.transform.parent = parent;
picks.Add(pickedObj.transform);
}
private void Regulator(){
//Position of cylinder
//set y value based on the # of children objects
/**
*hold the first position of cylinder
*make calculation by referencing it
*reference + localScale.y + 0.1f:
*/
Vector3 newPos = new Vector3(cylinder.position.x, firstPosition.y, cylinder.position.z);
foreach (Transform child in picks)
{
newPos.y += child.localScale.y + 0.1f;
}
//cylinder.position = newPos;
rb.MovePosition(newPos);
//Position of children
if(picks.Count>0) {
prevObject = picks[picks.Count-1];
}
/**
*For each child
* cylinder-0.1f-pick-0.1f-pick-...
*/
prev = cylinder;
for(int i = 0; i < picks.Count; i++)
{
if(i==0){
picks[i].position = new Vector3(prev.position.x, prev.position.y-1.2f, prev.position.z);
//picks[i].gameObject.GetComponent<Rigidbody>().position(new Vector3(prev.position.x, prev.position.y-1.2f, prev.position.z));
} else {
//picks[i].gameObject.GetComponent<Rigidbody>().MovePosition(new Vector3(prev.position.x, prev.position.y-prev.localScale.y -0.1f, prev.position.z));
picks[i].position = new Vector3(prev.position.x, prev.position.y-prev.localScale.y -0.1f, prev.position.z);
}
prev = picks[i];
}
//Position of trailer object
if(picks.Count>0) {
trailer.position = new Vector3(prev.position.x, prev.position.y-0.2f, prev.position.z); //relocate the trailer object under last pick
trailer.GetComponent<TrailRenderer>().material = prev.GetComponent<MeshRenderer>().material; //change the color of the trail
}
CheckChildren(); //check for the 3-conjugate combo
}
public void ChangeRampState() {
Debug.Log("prev.gameObject");
Debug.Log(prev.gameObject);
prev.gameObject.GetComponent<Collider>().isTrigger = false;
rb.AddForce(Vector3.up * 300);
}
public void OrderPicks() {
picks.Sort((x, y) => string.Compare(x.GetComponent<MeshRenderer>().sharedMaterial.name, y.GetComponent<MeshRenderer>().sharedMaterial.name));
}
public void ShufflePicks() {
picks = picks.Fisher_Yates_CardDeck_Shuffle();
}
async public void onObstacle(Transform pickToDestroy) {
pickToDestroy.gameObject.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezePosition;
pickToDestroy.parent = null;
await Task.Delay(200);
picks.Remove(pickToDestroy);
}
public void SpeedBoost() {
cylinder.gameObject.GetComponent<PlayerController>().rb.velocity *= 2;
}
}

Array inaccessible only at certain times

I am currently building a parallax background effect in Unity and starting with some starter code that I'm trying to work though. The code works for the most part, with some small issues I'm slowly getting through.
I have been testing out various stats of public vs. private, etc. but can't seem to work out exactly why and where the issue I'm facing is occurring.
When I run the same script and it calls Update() every frame, I would expect to have the same size "poolObjects" length. However, when I call it with a starting pool size of 10, I get 10, then 2, then 0, then 10, 2, 0, etc.
I am truncating it but posting what I think to be relevant here. Hope you can help me see what is likely obvious!
I do see "In GetPool Object" but because the length is never > 0, I never see within the For Loop, which is essential. I can't figure out why the poolObjects length would be showing up as 0.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Parallaxer : MonoBehaviour {
class PoolObject {
public Transform transform;
public bool inUse;
public PoolObject(Transform t) { transform = t; }
public void Use() { inUse = true; }
public void Dispose() { inUse = false; }
}
...
public int poolSize;
public float shiftSpeed;
public float spawnRate;
...
float spawnTimer;
PoolObject[] poolObjects;
float targetAspect;
GameManager game;
void Awake() {
Configure();
}
void Start() {
game = GameManager.Instance;
}
...
void Update() {
Debug.Log(poolObjects.Length + "Len here of pool objects");
if (game.GameOver) return;
Shift();
spawnTimer += Time.deltaTime;
if (spawnTimer > spawnRate) {
Spawn();
spawnTimer = 0;
}
}
void Configure() {
//spawning pool objects
targetAspect = targetAspectRatio.x / targetAspectRatio.y;
// targetAspect = Camera.main.aspect;
// Debug.Log(targetAspectRatio.x +" " + targetAspectRatio.y);
poolObjects = new PoolObject[poolSize];
for (int i = 0; i < poolObjects.Length; i++) {
GameObject go = Instantiate(Prefab) as GameObject;
Transform t = go.transform;
t.SetParent(transform);
t.position = Vector3.one * 1000;
poolObjects[i] = new PoolObject(t);
}
if (spawnImmediate) {
SpawnImmediate();
}
}
void Spawn() {
//moving pool objects into place
Transform t = GetPoolObject();
Debug.Log("In to Spawn" + t);
if (t == null) return;
Vector3 pos = Vector3.zero;
pos.y = Random.Range(ySpawnRange.minY, ySpawnRange.maxY);
pos.x = (defaultSpawnPos.x * Camera.main.aspect) / targetAspect;
// Debug.Log("Spwaning");
// Debug.Log(Camera.main.aspect);
// Debug.Log(immediateSpawnPos.x + " " + immediateSpawnPos.y + " " + targetAspect);
t.position = pos;
// Debug.Log(pos);
}
void SpawnImmediate() {
Transform t = GetPoolObject();
if (t==null) return;
Vector3 pos = Vector3.zero;
pos.y = Random.Range(ySpawnRange.minY, ySpawnRange.maxY);
pos.x = (immediateSpawnPos.x * Camera.main.aspect) / targetAspect;
t.position = pos;
Spawn();
}
void Shift() {
//loop through pool objects
//moving them
//discarding them as they go off screen
Debug.Log(poolObjects.Length + "Finding Length");
for (int i = 0; i < poolObjects.Length; i++) {
poolObjects[i].transform.position += -Vector3.right * shiftSpeed * Time.deltaTime;
Debug.Log(poolObjects[i].transform.position);
CheckDisposeObject(poolObjects[i]);
}
}
void CheckDisposeObject(PoolObject poolObject) {
//place objects off screen
if (poolObject.transform.position.x < (-defaultSpawnPos.x * Camera.main.aspect) / targetAspect) {
poolObject.Dispose();
poolObject.transform.position = Vector3.one * 1000;
}
}
Transform GetPoolObject() {
//retrieving first available pool object
Debug.Log("In GetPool Object" + poolObjects.Length);
for (int i = 0; i < poolObjects.Length; i++) {
Debug.Log("This is not showing up "+ poolObjects[i].inUse);
if (!poolObjects[i].inUse) {
poolObjects[i].Use();
return poolObjects[i].transform;
}
}
return null;
}
}

How can I generate the units at the same time?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GenerateStairs : MonoBehaviour
{
[Header("Stairs Prefb")]
public GameObject stairsPrefab;
[Space(5)]
[Header("Platforms")]
public bool addPlatforms = false;
public GameObject platformsPrefab;
[Space(5)]
[Header("Settings")]
[Range(1, 20)]
public int numberOfUnits = 1;
public float delay = 3;
public int stairsNumber = 5;
public Vector3 stairsStartPosition;
public Vector3 stairSize;
public Vector3 stairsSize;
public float stepWidthFactor = 1f;
private Vector3 stairsPosition;
private GameObject stairsParent;
private int oldNumberOfUnits = 0;
// Use this for initialization
void Start()
{
oldNumberOfUnits = numberOfUnits;
for (int i = 0; i < numberOfUnits; i++)
{
stairsParent = new GameObject();
stairsParent.name = "Stairs";
StartCoroutine(BuildStairs());
}
}
// Update is called once per frame
void Update()
{
if(oldNumberOfUnits != numberOfUnits)
{
StartCoroutine(BuildStairs());
oldNumberOfUnits = numberOfUnits;
}
}
private IEnumerator BuildStairs()
{
for (int i = 1; i <= stairsNumber; i++)
{
stairsPosition = new Vector3(
stairsStartPosition.x,
stairsStartPosition.y + (i * stairsSize.y),
stairsStartPosition.z + (i * stairsSize.y) * stepWidthFactor);
GameObject stair = Instantiate(
stairsPrefab,
stairsPosition,
Quaternion.identity);
stair.tag = "Stair";
stair.transform.parent = stairsParent.transform;
stair.transform.localScale = stairSize;
yield return new WaitForSeconds(delay);
}
stairsParent.AddComponent<MoveObjects>().Init();
}
}
In the Start I'm doing a loop and start the Coroutine according to the numberOfunits.
It's working fine if numberOfUnits is 1. But is it's more then 1 for example 2 it's first creating the first set of stairs but then on the second "Stairs" parent it's creating only 1 stair. I don't want it to wait to finish the first Coroutine I want in the same time to create number of Coroutine's of stairs.
And I want also to add a gap between each stairs unit.
And also to make that in the Update if I change the numberOfUnits it will add/destroy more stairs units. All the stairs units should be Instantiate inside StartCoroutine.
You are mistaking how the coroutine works its not at thread. What is happening is your continually invoking the coroutine so its starting over and over again not creating a separate instance.
what you should do is create create a prefab and Instantiate that to do the work. My last remark was about threads but you wont be able to instantiate anything unless its on the main thread so the easiest way to get this done would be like so.
public GameObject yourGoWithAboveClassOnIt;
void Start()
{
oldNumberOfUnits = numberOfUnits;
for (int i = 0; i < numberOfUnits; i++)
{
Instantiate(yourGoWithAboveClassOnIt);
}
}
your prior class will remove this
void Start()
{
//oldNumberOfUnits = numberOfUnits;
//for (int i = 0; i < numberOfUnits; i++)
//{
stairsParent = new GameObject();
stairsParent.name = "Stairs";
StartCoroutine(BuildStairs());
//}
}

Instantiated object does not have desired scale

I am trying to get two blocks to respawn vertically with a gap in-between. I have done this however, when I click play, one of the blocks width is too short. this results in having two gaps. how can I stop this from happening. I would only like the one gap which is between the two blocks. the code I am currently using:
public Transform block;
public Transform player;
private float objectSpawnedTo = 5.0f;
public static float distanceBetweenObjects = 9.5f;
private float nextCheck = 0.0f;
private ArrayList objects = new ArrayList();
void Start () {
maintenance(0.0f);
}
void Update () {
float playerX = player.position.y;
if(playerX > nextCheck)
{
maintenance(playerX);
}
}
private void maintenance(float playerX)
{
nextCheck = playerX + 30;
for (int i = objects.Count-1; i >= 0; i--)
{
Transform blck = (Transform)objects[i];
if(blck.position.y < (transform.position.y - 30))
{
Destroy(blck.gameObject);
objects.RemoveAt(i);
}
}
spawnObjects(5);
}
private void spawnObjects(int howMany)
{
float spawnX = objectSpawnedTo;
for(int i = 0; i<howMany; i++)
{
Vector3 pos = new Vector3(6.0f, spawnX, 0);
float firstRandom = Random.Range(1,8.6f);
Transform blck = (Transform)Instantiate(block, pos, Quaternion.identity);
blck.localScale+=new Vector3(firstRandom*2,0,0);
objects.Add(blck);
pos = new Vector3(-6.0f, spawnX, 0);
blck = (Transform)Instantiate(block, pos, Quaternion.identity);
blck.localScale +=new Vector3((8.6f-firstRandom)*2,0,0);
objects.Add(blck);
spawnX = spawnX + distanceBetweenObjects;
}
objectSpawnedTo = spawnX;
}
i have attached an image to show what i am trying to achieve. the red outline is the mobile screen. also i would like to be able to move the blocks either left or right using touch. how would i go about doing this.

GameObject being set to null after being made

I put together a simple script that creates a sprite-based pointer I can use in UI. It's not complete yet (still needs support for when the player pushes a button), but already running into problems.
I get a NullReferenceException: Object reference not set to an instance of an object
At line 52...
_ptrSpriteRenderer.sprite = newSprite;
...and 72
_ptr.transform.position = new Vector2(((float)_ptrPosX * _ptrPositionXDistance) + _ptrPositionTopLeft.x, ((float)_ptrPosY * _ptrPositionYDistance) + _ptrPositionTopLeft.x);
I am creating _ptr and _ptrSpriteRenderer in the Start, but for some reason at all my other functions these two GameObjects are null, and yet they aren't null during Start.
I'm sure it's something simple that I goofed up on, but I've spent hours comparing this class to other classes where I've created sprites and I can't see the issue.
using UnityEngine;
using System.Collections;
public class Pointer : MonoBehaviour {
private GameObject _ptr;
private Sprite _ptrSprite;
private SpriteRenderer _ptrSpriteRenderer;
private bool _ptrEnabled; // Is the pointer receiving input?
private int _ptrMovePerSecond; // Number of positions to move per second if input held down
private int _ptrXInput;
private int _ptrYInput;
private float _ptrTimeSinceLastInput = 0f;
private float _ptrTimePerInput = 0.25f;
private bool _ptrInputDelay = false;
private Vector2 _ptrPositionTopLeft; //The top left position the pointer can reach in the grid
private Vector2 _ptrPositionBottomRight; //The bottom right position the pointer can reach in the grid
private int _ptrPositionsX; //The number of grid positions the pointer can traverse in X
private int _ptrPositionsY; //The number of grid positions the pointer can traverse in Y
private float _ptrPositionXDistance; //The distance of each X position in the grid
private float _ptrPositionYDistance; //The distance of each Y position in the grid
private int _ptrPosX; //Current X position of pointer in the grid
private int _ptrPosY; //Current Y position of pointer in the grid
// Use this for initialization
void Start () {
_ptr = new GameObject();
_ptrSpriteRenderer = new SpriteRenderer();
_ptr.AddComponent<SpriteRenderer>();
_ptrSpriteRenderer = _ptr.GetComponent<SpriteRenderer>();
_ptrEnabled = true;
}
public void setSprite ( Sprite newSprite )
{
if (newSprite == null)
{
Debug.LogError("No sprite passed to setSprite in Pointer");
}
else
{
_ptrSpriteRenderer.sprite = newSprite;
}
}
public void setPositions (Vector2 positionTopLeft, Vector2 positionBottomRight, int numPositionsX, int numPositionsY)
{
_ptrPositionsX = numPositionsX;
_ptrPositionsY = numPositionsY;
_ptrPositionTopLeft = positionTopLeft;
_ptrPositionBottomRight = positionBottomRight;
_ptrPositionXDistance = Mathf.Abs((positionBottomRight.x - positionTopLeft.x) / numPositionsX);
_ptrPositionYDistance = Mathf.Abs((positionBottomRight.y - positionTopLeft.y) / numPositionsY);
}
public void setPosition (int x, int y)
{
_ptrPosX = x;
_ptrPosY = y;
_ptr.transform.position = new Vector2(((float)_ptrPosX * _ptrPositionXDistance) + _ptrPositionTopLeft.x, ((float)_ptrPosY * _ptrPositionYDistance) + _ptrPositionTopLeft.x);
}
// Update is called once per frame
void Update () {
//Is the pointer enabled?
if (_ptrEnabled)
{
if (_ptrInputDelay)
{
_ptrTimeSinceLastInput += Time.deltaTime;
if (_ptrTimeSinceLastInput >= _ptrTimePerInput)
{
_ptrInputDelay = false;
}
}
if (_ptrInputDelay == false)
{
_ptrXInput = (int)Input.GetAxis("Horizontal");
_ptrYInput = (int)Input.GetAxis("Vertical");
if (_ptrXInput != 0 || _ptrYInput != 0)
{
_ptrPosX += _ptrXInput;
_ptrPosY += _ptrYInput;
Debug.Log("WHEE");
if (_ptrPosX < 0) _ptrPosX = 0;
if (_ptrPosX > _ptrPositionsX) _ptrPosX = _ptrPositionsX;
if (_ptrPosY < 0) _ptrPosY = 0;
if (_ptrPosY > _ptrPositionsY) _ptrPosY = _ptrPositionsY;
_ptr.transform.position = new Vector2(((float)_ptrPosX * _ptrPositionXDistance) + _ptrPositionTopLeft.x, ((float)_ptrPosY * _ptrPositionYDistance) + _ptrPositionTopLeft.x );
_ptrInputDelay = true;
_ptrTimeSinceLastInput = 0f;
}
}
}
}
}
And the place where my Pointer class is being called is done like this:
GameObject newPointer = new GameObject();
newPointer.AddComponent<Pointer>();
Pointer newPointerScript = newPointer.GetComponent<Pointer>();
newPointerScript.setPositions(new Vector2(-1f, -1f), new Vector2(1f, 1f), 3, 3);
newPointerScript.setSprite(newWeapon);
newPointerScript.setPosition(1, 1);
These lines look wrong:
_ptrSpriteRenderer = new SpriteRenderer();
_ptr.AddComponent<SpriteRenderer>();
_ptrSpriteRenderer = _ptr.GetComponent<SpriteRenderer>();
You are creating a SpriteRenderer and then two lines later overwriting the value with what's in _ptr which is, in all probability, null.
Do you really need this line?
Also if you're adding a component shouldn't you be actually passing the component into the Add method?
So turns out everything works fine if I switch Start() with Awake(). That's all that was needed.

Categories