So I'm making a project where I need an Object to mimic the properties of a set of other Objects with a certain time in between.
For that I used the following IEnumerator:
public IEnumerator GoBack(GameObject[] go)
{
for (int i = go.Length-1; i >= 0; i--)
{
if (go[i] != null)
{
GameObject g = go[i];
transform.position = g.transform.position;
sprRenderer.flipX = g.GetComponent<SpriteRenderer>().flipX;
sprRenderer.sprite = g.GetComponent<SpriteRenderer>().sprite;
Destroy(go[i]);
yield return new WaitForSecondsRealtime(rollBack);
}
}
GetComponent<Animator>().Play("EndTurnBack");
}
This basically alters my Object to be equal to the position, sprite and flipX of the object it is mimicking.
The problem is that only the position appears to work and I have no clue as to why
I tried printing in the console what was the sprite and flipX of my Object for each iteration and it is exactly what I want but the results don't appear on the screen.
Related
Context
Hello, currently creating a clone of "Crossy Road" and what I'm trying to do is to spawn my moving object called "Vehicle" at a random speed and rate of spawn. This is also applicable to "Plank", but I will start first with the vehicle. So far, everything is working fine as intended for the game mechanics, but I would like to finalize with this issue so it is fully functional in terms of playability.
Problem
My issue now is I 3 different spawns objects: grass, river, and road. Each object holds other objects (let's call it spawners) depending of what field is being spawn. For example, if grass field object is spawned, it will spawn trees depending in a random varied selection. Another example is with road field. When the road is spawned, a vehicle will be spawned from either left or right in its current initial position. This vehicle will moves as intended with a random speed, but not with the original spawn position and rate (as shown in the GIF. The vehicle spawns in the middle of the road and not in the beginning of the left/right road).
As far I'm aware, my rate is currently unused because it is not the main issue I want to solve. However, the issue now is with the transform position not working as I have pictured in my head. So what is happening is that when the road is spawned again, the vehicle is spawned in the middle of the trajectory instead of resetting to the beginning.
Also, I have noticed that when I print the vehicle object, the Z-axis has a weird number compared to the original position.
Attempts done
I have been thinking that maybe it is the way I have set everything up. I have 4 vehicle objects with a child object called "Tank". However, in each vehicle object, I'm using SetActive(...) only and not really reusing the object itself to the beginning. Later on, I want to organize this spaghetti code and optimize it (e.g ObjectPool to spawn my roads and other GameObjects after hitting a certain range, adding a player range detection to spawn a field to name a few).
To be honest, my whole code feels bloated for something simple. This will be fixed once everything is working accordingly.
Code (DISCLAIMER: there is the possibility that there are unused variables)
SpawnManager.cs (some links provided too from learning to make this)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
** Weighted randomness: https://forum.unity.com/threads/random-numbers-with-a-weighted-chance.442190/
** Scriptable Object Weight spawn example: https://www.youtube.com/watch?v=FCksj9ofUgI&ab_channel=LlamAcademy
** From scratch loot tables with Scriptable Objects to make a loot table: https://www.youtube.com/watch?v=tX3RWsVLnzM&ab_channel=GregDevStuff
** Creating a random with an animation curve: https://www.youtube.com/watch?v=zw1OERK5xvU&ab_channel=HamzaHerbou
** Random Vehicle position spawn (maybe this can help me): https://stackoverflow.com/questions/51312481/move-spawn-object-to-random-position
*/
public class SpawnManager : MonoBehaviour
{
public GameObject Player;
public Spawn[] Field;
public GameObject[] SpawnObjectTrees;
public GameObject[] SpawnObjectVehicles; //different vehicles
public GameObject[] SpawnObjectPlanks; //3 sizes (small, medium, large)
private PlayerControl2 playerControlScript;
private int distancePlayer;
private int toggle;
private bool keepSpawning;
bool vehicleFlag = false;
bool plankFlag = false;
public float randomNumSpawn;
void Awake()
{
keepSpawning = true;
playerControlScript = GameObject.Find("PlayerObject").GetComponent<PlayerControl2>();
InvokeRepeating("Spawner", 3f, randomNumSpawn);
}
void Update()
{
if (Input.GetButtonDown("up") && !playerControlScript.gameOver)
SpawnField();
}
void Spawner()
{
bool activeLeft = false;
bool activeRight = false;
if (vehicleFlag)
{
print(initialObjectSpawn);
for (int i = 0; i < SpawnObjectVehicles.Length; i++)
{
print($"{SpawnObjectVehicles[i]}: {SpawnObjectVehicles[i].transform.position}"); //Here I get the weird position.z values pretty wonky
toggle = Random.Range(0, 2);
if (toggle == 1 && !activeLeft)
{
activeLeft = true;
SpawnObjectVehicles[i].SetActive(true);
}
if (toggle == 0 && !activeRight)
{
activeRight = true;
SpawnObjectVehicles[i].SetActive(true);
}
else
SpawnObjectVehicles[i].SetActive(false);
}
}
}
void SpawnField()
{
//I want to spawn the vehicles, planks, and trees in sets accordingly to the field (grass, river, road)
//For vehicles and planks, they can move horizontally from either -z or z boundaries
//NOTE: keepSpawning may be useless if i have a playerControlScript.gameOver already in here
if (keepSpawning)
{
distancePlayer += 3;
Vector3 intPos = new Vector3(0, 0, 0);
int i = Random.Range(0, 1000);
for (int j = 0; j < Field.Length; j++)
{
if (i >= Field[j].minProbabilityRange && i <= Field[j].maxProbabilityRange)
{
intPos = new Vector3(distancePlayer, -1f, 0);
GameObject Surface = Instantiate(Field[j].spawnField);
if (Surface.CompareTag("Grass"))
TreeToggle();
if (Surface.CompareTag("Road"))
{
vehicleFlag = true;
VehicleToggle();
}
// if (Surface.CompareTag("River")) this will be the same as vehicle
// {
// plankFlag = true;
// PlankToggle();
// }
//Add spawn for vehicles and planks with given spawnrate/spawn intervals
Surface.transform.position = intPos;
vehicleFlag = false;
plankFlag = false;
}
}
}
}
void TreeToggle()
{
int counter = 0;
for (int i = 0; i < SpawnObjectTrees.Length; i++)
{
int toggle = Random.Range(0, 2); //[0, 2)
if (toggle == 1 && counter < 5) //True and when there are already 5-4 trees to toggle
{
counter++;
SpawnObjectTrees[i].SetActive(true);
}
else //fills the rest to inactive Trees
SpawnObjectTrees[i].SetActive(false);
}
}
void VehicleToggle()
{
// I have Left and Right with 2 vehicles in each. My goal is to setActive one of them each side at a time with a different interval spawnrate and speed
Spawner();
}
void PlankToggle()
{
Spawner();
}
}
[System.Serializable]
public class Spawn
{
public GameObject spawnField;
public float minProbabilityRange = 0.0f;
public float maxProbabilityRange = 0.0f;
}
Hierarchy/Inspector
If there is any information you want to know, feel free to ask and I will make a quick edit to fulfill these goals. Again, thank you for your time and appreciate it :D I hope you are having a good day!
I'm stuck with this one for quite some time now. I am trying to create spheres via script and update their position based on the position of points. Their position is updating on the Debug.Log() but they are not moving in Game View.
Here is my code:
void createSpheres(int objCount, float xPointsPos, float yPointsPos){
var sphereCreator = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphereCreator.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
sphereCreator.transform.position = new Vector3(xPointsPos, yPointsPos, 0);
sphereCreator.AddComponent<Rigidbody>();
sphereCreator.GetComponent<Rigidbody>().useGravity = false;
sphereCreator.AddComponent<SphereCollider>();
//ADD THE SPHERES TO THE SPHERELIST
sphereList = new List<Sphere>();
for(int loop = 0; loop < objCount-1; loop++){
Sphere temp = new Sphere();
temp.sphereName = "sphere"+sphereNameCount;
temp.sphereObj = sphereCreator;
temp.sphereXPos = xPointsPos;
temp.sphereYPos = yPointsPos;
sphereList.Add(temp);
}
sphereNameCount++;
}
void UpdateSpheres()
{
for(int i = 0; i < sphereList.Count - 1; i++){
sphereList[i].sphereXPos = points[i].position.x;
sphereList[i].sphereYPos = points[i].position.y;
Debug.Log($"{sphereList[i].sphereXPos}" + " -- " + $"{points[i].position.x}");
}
}
public class Sphere{
public string sphereName;
public float sphereXPos;
public float sphereYPos;
public GameObject sphereObj;
}
The createSpheres() method is called inside a loop containing how many points are spawned to match it.
I also tried checking if the ArrayList is empty or not using Debug.Log() and it returned all the Sphere gameObjects that I added.
Any help or hint will be highly appreciated. Thanks!
You do not create a number of spheres according to the code. You create just a single sphere and assign it to all your Sphere instances. To create and move your spheres:
create GameObject object for every object instead of assigning the same object for each Sphere class instance
use .transform.position of the created object, assigned to Sphere class instance to move the corresponding GameObject instance
I made a right click menu and i want to make objects change material color while i have my mouse on a button in that menu.
This is the code:
Color[] startCo;
public void OnPointerEnter(PointerEventData eventData)
{
GameObject[] objects = GameObject.FindGameObjectsWithTag(myMenu.selected.title);
for (int i = 0; i < startCo.Length; i++)
{
startCo[i] = objects[i].gameObject.GetComponent<MeshRenderer>().material.color;
}
foreach (GameObject obj in objects)
{
obj.gameObject.GetComponent<MeshRenderer>().material.color = Color.red;
}
}
public void OnPointerExit(PointerEventData eventData)
{
GameObject[] objects = GameObject.FindGameObjectsWithTag(myMenu.selected.title);
for (int i = 0; i < objects.Length; i++)
{
objects[i].gameObject.GetComponent<MeshRenderer>().material.color = startCo[i];
}
}
With first for loop it does not work at all, but without it, when I put my mouse on the button, it makes material colors red, but it won't change it back to orginal.
My question is, is there any better way to save original colors with using foreach?
Try this version. It basically does exactly the same thing as your version, but makes sure to initialize the color array before using it (which was probably your main issue). It also keeps a copy of the list of objects whose colors were replaced, which is important in case new objects with a matching tag are created, or existing one's deleted. Finally, it adds a few safeguards to make it more robust in case you want to use ReplaceColors() and RestoreColors() in other places, too.
GameObject[] objectsWithReplacedColors;
Color[] originalColors;
public void OnPointerEnter(PointerEventData eventData)
{
ReplaceColors(GameObject.FindGameObjectsWithTag(myMenu.selected.title), Color.red);
}
public void OnPointerExit(PointerEventData eventData)
{
RestoreColors();
}
private void ReplaceColors(GameObject[] forObjects, Color withColor)
{
if (objectsWithReplacedColors != null) // if there are already objects with replaced colors, we have to restore those first, or their original color would be lost
RestoreColors();
objectsWithReplacedColors = forObjects;
originalColors = new Color[objectsWithReplacedColors.Length];
for (int i = 0; i < objectsWithReplacedColors.Length; i++)
{
originalColors[i] = objects[i].GetComponent<MeshRenderer>().material.color;
objectsWithReplacedColors[i].GetComponent<MeshRenderer>().material.color = withColor;
}
}
private void RestoreColors()
{
if (objectsWithReplacedColors == null)
return;
for (int i = 0; i < objectsWithReplacedColors.Length; i++)
{
if (objectsWithReplacedColors[i]) // check if the objects still exists (it may have been deleted since its color was replaced)
objectsWithReplacedColors[i].GetComponent<MeshRenderer>().material.color = originalColors[i];
}
objectsWithReplacedColors = null;
originalColors = null;
}
Well my guess is you are finding objects every time these methods are called using GameObject.FindGameObjectsWithTag and i am pretty sure the order of these objects returned by FindGameObjectsWithTag is not specified so it can change ever time you call this method. This issue ends up giving you different original colors for different objects. My suggestion would be getting objectsin the Startonce and assigning colors to the array. Then use this array in OnPointerExitfunction.
Other than that your code and logic seems fine to me.
I have some 2D objects in same transform position. How can I find out how many objects are in one same position and which objects are they?
EDIT:
Here is my code:
I want save all object on transform.position - new Vector3(speed, 0, 0)
GameObject go = GetObjectAt(transform.position - new Vector3(speed, 0, 0));
public GameObject GetObjectAt(Vector3 position)
{
string pos = position.x + "_" + position.y + "_";
if (obstacleDictionary.ContainsKey(pos + "BigRed"))
{
return obstacleDictionary[pos + "BigRed"];
}
else if (obstacleDictionary.ContainsKey(pos + "SmallRed"))
{
return obstacleDictionary[pos + "SmallRed"];
}
else return null;
}
I think you can use List<SomeModel> for keep object and postion.
Add your object to list when the object created
then find same postion object used by LINQ
CodeSample
Public class ObjectListener
{
public string ObjectName {get; set;}
public Vector2 ObjectVector {get; set;}
}
public class CreateObject : MonoBehaviour
{
List<ObjectListener> _gameObjectListener = new List<ObjectListener>();
void Update()
{
private GameObject _gameObject ; // you must create _gameObject
// and set tranform.Postion maybe you
// can use a method returned gameObject
Instantiate(_gameObject, _gameObject.transform.position, Quaternion.identity);
_gameObjectListener.Add(new ObjectListener
{
ObjectName = _gameObject.Name,
ObjectVector = _gameObject.transform.postion
});
}
}
I'm not sure that's the right way, but you can keep all created object name and postion in list object. So you can find how many object are in same object or not
Assuming all of the objects have a Collider2D on them, you just need to call Physics2D.BoxCastAll( and it will return a array of RaycastHit2D which you can call hitItems[i].collider.gameObject on to get the object.
RaycastHit2D[] hitItems = Physics2D.BoxCastAll(origin, size, angle, direction);
for(int i = 0; i < hitItems.Length; i++)
{
GameObject hitObject = hitItems[i].collider.gameObject;
//Do something with the hit object.
}
One method is mentioned in the below article
http://answers.unity3d.com/questions/638319/getting-a-list-of-colliders-inside-a-trigger.html
The basics of the above article
Make sure everything has a collider
Make sure at least one thing has a trigger
User "TriggerList" to get all items with a collider within the trigger.
This article is a second option
http://answers.unity3d.com/questions/532746/finding-gameobjects-within-a-radius.html
The basics
Get a position/transform
Get all colliders within a sphere
iterate through the list.
I'm creating a game in XNA and I need a collision detection logic:
public Rectangle boundingBox = new Rectangle((int)playerShipPos.X, (int)playerShipPos.Y, frameWidth, frameHeight);
this.boundingBox = new Rectangle((int)meteorPosPub.X, (int)meteorPosPub.Y, (int)meteorTexture.Width, (int)meteorTexture.Height);
for (int i = meteorList.Count - 1; i >= 0; i--)
{
meteorGenerator meteor = new meteorGenerator(Vector2.Zero);
if (meteorList[i].meteorPosPub.Y > 664)
{
meteorList.RemoveAt(i);
if (meteor.boundingBox.Intersects(playerShip.boundingBox))
{
meteorList.RemoveAt(i);
}
}
}
So I want to achive this effect: if the player ship touches the meteor the meteor is hides and is removed from the list but nothing happens, actually.
for (int i = meteorList.Count - 1; i >= 0; i--)
{
meteorGenerator meteor = new meteorGenerator(Vector2.Zero);//you are creating new list meteors every frame, this is ridiculous
if (meteorList[i].meteorPosPub.Y > 664)
{
meteorList.RemoveAt(i);//if you are removing a position from a list, not destroying the meteor
if (meteor.boundingBox.Intersects(playerShip.boundingBox))
{
meteorList.RemoveAt(i);//you already did this, this conditional is unnecessary
}
}
}
I have no idea what it is you are doing, but this is what I would do.
1.Let the player and meteor inherit from a class with the properties a solid object would have.
Add those to a list with unique IDs based on the object type.
Every frame, check for IDs (this gives you extra control on what you want to collide with what).
Proceed to check for collisions, in case you want to remove an element, just remove it from the list and destroy it.