How to Transfer GameObject to another scene - c#

I know this has been asked previously here, but it doesn't work. It moves the GameObject to another scene successfully but It does not close the previous scene. Here is a screenshot.
Here is the Expanded Screen shot of the project Expanded Screen Shot
And here is the script but in the script you'll also find a code of a Slide Show menu which will display my models as menu
In function enableScene() On line 1 I have tried to close the previous scene but it doesn't work
public class PizzaScript : MonoBehaviour {
public Text header;
public List<GameObject> createObjects = new List<GameObject>();
private static int slideIndex = 1;
private GameObject instance;
private Vector3 temp = new Vector3(0.34f, 0.074f, 0);
private AsyncOperation sceneAsync;
public GameObject Pizza;
public GameObject Cube;
public GameObject Sphere;
public GameObject CocaCola;
// Use this for initialization
void Start()
{
object[] subListObjects = { Pizza, Cube, Sphere, CocaCola };
foreach(GameObject list in subListObjects )
{
GameObject lo = (GameObject)list;
createObjects.Add(lo);
}
showPrefabs(slideIndex);
StartCoroutine(loadScene(2));
}
IEnumerator loadScene(int index)
{
AsyncOperation scene = SceneManager.LoadSceneAsync(index, LoadSceneMode.Additive);
scene.allowSceneActivation = false;
sceneAsync = scene;
//Wait until we are done loading the scene
while (scene.progress < 0.9f)
{
Debug.Log("Loading scene " + " [][] Progress: " + scene.progress);
yield return null;
}
Debug.Log("Progress Completed.............................");
}
public void OnFinishedLoadingAllScene()
{
Debug.Log("Done Loading Scene");
enableScene(2);
Debug.Log("Scene Activated!");
}
private void enableScene(int index)
{
SceneManager.UnloadSceneAsync(1);
//Activate the Scene
sceneAsync.allowSceneActivation = true;
Scene sceneToLoad = SceneManager.GetSceneByBuildIndex(index);
if (sceneToLoad.IsValid())
{
Debug.Log("Scene is Valid");
SceneManager.MoveGameObjectToScene(instance, sceneToLoad);
SceneManager.SetActiveScene(sceneToLoad);
}
}
// Update is called once per fram
public void OnClickRightArrow()
{
plusPrefabs(1);
}
public void OnClickLeftArrow()
{
plusPrefabs(-1);
}
public void plusPrefabs(int n)
{
if(n == 1 || n == -1)
{
Destroy(instance,0.01f);
}
showPrefabs(slideIndex += n);
}
public void showPrefabs(int n)
{
var x = createObjects.Count;
if (n > createObjects.Count)
{
slideIndex = 1;
}
if (n < 1)
{
slideIndex = createObjects.Count;
}
if (slideIndex == 1)
{
header.text = slideIndex.ToString();
instance = Instantiate(createObjects[0], temp, Quaternion.Euler(-90,0,0));
instance.transform.localScale = new Vector3(20, 20, 20);
}
else if(slideIndex == 2)
{
header.text = slideIndex.ToString();
instance = Instantiate(createObjects[1], temp, transform.rotation);
instance.transform.localScale = new Vector3(10, 10, 10);
}
else if (slideIndex == 3)
{
header.text = slideIndex.ToString();
instance = Instantiate(createObjects[2], temp, transform.rotation);
instance.transform.localScale = new Vector3(10, 10, 10);
}
else if (slideIndex == 4)
{
header.text = slideIndex.ToString();
instance = Instantiate(createObjects[3], temp, Quaternion.Euler(-90,0,0));
instance.transform.localScale = new Vector3(120, 120, 120);
}
}
}
Here is the screen shot Screen shot of previous scene

It very easy to persist your one game object into antoher scene on loading, just attached thsi script to your desired gameobject.
public class DontDestroyOnLoad : MonoBehaviour {
void Awake () {
DontDestroyOnLoad(this);
}
}
What DontDestroyOnLoad work like this:
Makes the object target not be destroyed automatically when loading a
new scene.
When loading a new level all objects in the scene are destroyed, then
the objects in the new level are loaded. In order to preserve an
object during level loading call DontDestroyOnLoad on it. If the
object is a component or game object then its entire transform
hierarchy will not be destroyed either.

Related

Is there any way to send gameobjects over the network? (Mirror)

I have a pathfinding script for my 2D multiplayer game (using Mirror) that returns available/walkable tiles in a list. The 'tiles' stored in this list are game objects which are generated over my grid in the scene. I have a function that makes a call to the server in order to move my character with a network transform.. That function checks the index of the list to see which tile to move to (notice path[0] referenced in this function. The index is a game object which is stored in my list of walkable tiles). If I try to use this function I'll get error "ArgumentOutOfRangeException" .. which I've gathered is because my 'tiles' are not actually being sent to the server.
My movement function:
[Command]
public void CmdMoveAlongPath()
{
var step = moveSpeed * Time.deltaTime;
var zIndex = path[0].transform.position.z;
character.transform.position = Vector2.MoveTowards(character.transform.position,
path[0].transform.position, step);
character.transform.position = new Vector3(character.transform.position.x, character.transform.position.y, zIndex);
if (Vector2.Distance(character.transform.position, path[0].transform.position) < 0.0001f)
{
PositionCharacterOnTile(path[0]);
path.RemoveAt(0);
}
}
I call this command from within my Movement script attached to my player.. For further context, startingTile and overlayTile variables shown here are the game objects that I pass to my pathfinding script which is shown here as pathFinder.FindPath(startingTile, overlayTile);
CmdMoveAlongPath is executed only when path.Count > 0
[ClientCallback]
private void LateUpdate()
{
if (!hasAuthority) { return; }
var focusedTileHit = GetFocusedOnTile();
var focusedOnTileFromPlayer = GetFocusedOnTileFromPlayer();
if (focusedOnTileFromPlayer.HasValue)
{
// Starting tile is the tile detected below player when the scene first loads.
startingTile = focusedOnTileFromPlayer.Value.collider.gameObject.GetComponent<OverlayTile>();
startingTile.GetComponent<OverlayTile>().ShowTile();
}
if (focusedTileHit.HasValue)
{
OverlayTile overlayTile = focusedTileHit.Value.collider.gameObject.GetComponent<OverlayTile>();
Vector2 touchPostion = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (Input.GetMouseButtonDown(0) && overlayTile != null) //&& !treeDetected
{
if (activeTile == null)
{
path = pathFinder.FindPath(startingTile, overlayTile);
activeTile = startingTile;
}
else
{
path = pathFinder.FindPath(activeTile, overlayTile);
}
}
}
if (path.Count > 0)
{
CmdMoveAlongPath();
}
}
My Pathfinding script which calculates the tiles in between the starting tile and selected tile:
public class Pathfinder
{
public List<OverlayTile> FindPath(OverlayTile start, OverlayTile end)
{
List<OverlayTile> openList = new List<OverlayTile>();
List<OverlayTile> closedList = new List<OverlayTile>();
openList.Add(start);
while (openList.Count > 0)
{
OverlayTile currentOverlayTile = openList.OrderBy(x => x.F).First();
if (currentOverlayTile != null) {
openList.Remove(currentOverlayTile);
closedList.Add(currentOverlayTile);
}
if (currentOverlayTile == end)
{
return GetFinishedList(start, end);
}
var neighborTiles = GetNeighborTiles(currentOverlayTile);
foreach (var neighbor in neighborTiles)
{
if (neighbor.isBlocked || closedList.Contains(neighbor) || Mathf.Abs(currentOverlayTile.gridLocation.z - neighbor.gridLocation.z) > 1)
{
continue;
}
neighbor.G = GetManhattanDistance(start, neighbor);
neighbor.H = GetManhattanDistance(end, neighbor);
neighbor.previous = currentOverlayTile;
if (!openList.Contains(neighbor))
{
openList.Add(neighbor);
}
}
}
return new List<OverlayTile>();
}
My OverlayTile class .. I do have a gridLocation property on this class. Sending this to the server might be the way to go..
public class OverlayTile : MonoBehaviour
{
public int G;
public int H;
public int F { get { return G + H; } }
public bool isBlocked;
public OverlayTile previous;
public Vector3Int gridLocation;
}
From what I've read on other posts, it doesn't seem possible to send game objects like this over the network. But I also haven't found a solid answer on this anywhere yet. Seeing as how my pathfinder needs to check for game objects on the scene, I need to find a way to make this work. Should I just scrap this approach to my pathfinder using game objects?

Why does the script ignore the part after the first WaitForSeconds()?

I am trying to use WaitForSeconds() in my game to perform a scene.
I would love to here improvements and answers to the not working WaitForSeconds() (Its just ignores the part after I start to use WaitForSeconds())
The script:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class FoodManager : MonoBehaviour
{
public bool[] isFull;
public GameObject[] slots;
public GameObject[] itemNames;
public GameObject[] itemImages;
public GameObject[] itemAmounts;
public GameObject foodObject;
public GameObject mainPanel;
public string[] foodNames;
public Sprite[] foodImages;
public Sprite[] foodHalfImages;
public GameObject foodPanel;
public GameObject bird;
private int _lastFood;
private int _hunger;
void Update()
{
_hunger = PlayerPrefs.GetInt("_hunger");
for(int i = 0; i < 6; i++)
{
if (isFull[i] == true)
slots[i].SetActive(true);
if (isFull[i] == false)
slots[i].SetActive(false);
}
}
private void addItem(int max, string itemName, GameObject itemImage, int addingAmount)
{
for (int j = 0; j < max; j++)
{
if (isFull[j] == true && itemNames[j].GetComponent<Text>().text == itemName)
{
itemAmounts[j].GetComponent<Text>().text = (int.Parse(itemAmounts[j].GetComponent<Text>().text) + addingAmount).ToString();
_lastFood = j;
return;
}
if (isFull[j] == false)
{
isFull[j] = true;
itemNames[j].GetComponent<Text>().text = itemName;
itemAmounts[j].GetComponent<Text>().text = addingAmount.ToString();
itemImages[j].GetComponent<Image>().sprite = foodImages[j];
_lastFood = j;
return;
}
if (isFull[j] == true && int.Parse(itemAmounts[j].GetComponent<Text>().text) == 0)
{
isFull[j] = false;
return;
}
}
}
public void foodButtonsBehavior(int a)
{
if(a >= 0 && a <= 5)
{
StartCoroutine(foodEat(slots[a]));
}
if (a == 7) //add food button
{
addItem(7, "Special Seeds", itemImages[1], 2);
}
}
public void closeFoodMenu()
{
foodPanel.SetActive(false);
}
public IEnumerator foodEat(GameObject slot)
{
mainPanel.SetActive(false);
foodPanel.SetActive(false); // Start Of Animation
itemAmounts[_lastFood].GetComponent<Text>().text = (int.Parse(itemAmounts[_lastFood].GetComponent<Text>().text) - 1).ToString();
moveFood(-1f, -1f); // Resetting Position for the food
foodObject.GetComponent<SpriteRenderer>().sprite = foodImages[_lastFood];
yield return new WaitForSeconds(1.1f);
print("Continuing");
foodObject.SetActive(true);
//bird.transform.Rotate(0, 0, 0);
bird.transform.position = new Vector2(0, -2.4f);
yield return new WaitForSeconds(0.7f);
moveFood(-1f, -2f);
bird.transform.Rotate(0, 0, 0);
bird.transform.position = new Vector2(0, -2.4f);
yield return new WaitForSeconds(0.7f);
moveFood(-1f, -2.7f);
bird.transform.Rotate(0, 0, 0);
bird.transform.position = new Vector2(0, -2.4f);
yield return new WaitForSeconds(0.4f);
foodObject.GetComponent<SpriteRenderer>().sprite = foodHalfImages[_lastFood];
bird.transform.Rotate(0, 0, 0);
bird.transform.position = new Vector2(0, -2.4f);
yield return new WaitForSeconds(0.4f);
foodObject.SetActive(false);
bird.transform.Rotate(0, 0, 0);
bird.transform.position = new Vector2(0, -2.4f);
yield return new WaitForSeconds(0.8f);
PlayerPrefs.SetInt("_hunger", _hunger + 24);
foodPanel.SetActive(true); // End Of Animation
mainPanel.SetActive(true);
}
private void moveFood(float x, float y)
{
foodObject.transform.position = new Vector2(x, y);
}
public void changeBird(GameObject x)
{
bird = x;
}
}
I would love to get some help here, as this is critical for my game and I couldn't find my answer online, so I would appreciate if someone decides to help with the problem. (Srry stackOverFlow wouldn't let me post without the last lines.)
Something important to note is that Coroutines only run when the the gameobject it is attached to remains active. From the Coroutine documentation:
A coroutines also stops when the GameObject
it is attached to is disabled with SetActive(false)
This behaviour is consistent with the error you are seeing, albeit a little confusing because the code appears to continue running after you disable the object. There's a very nuanced explanation, but for a simplified version: SetActive(false) waits until the end of the frame to stop MonoBehaviours running on the gameobject.

Why when replacing a gameobject with prefab the prefab position is a bit to the back and not exactly on the gameobject position?

This is the code for replacing :
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
public class SaveTransformsInfo : EditorWindow
{
[SerializeField] private GameObject prefab;
[MenuItem("Tools/Replace With Prefab")]
static void CreateReplaceWithPrefab()
{
EditorWindow.GetWindow<SaveTransformsInfo>();
}
private void OnGUI()
{
prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", prefab, typeof(GameObject), false);
if (prefab == null || Selection.gameObjects.Length == 0)
{
GUI.enabled = false;
}
else
{
GUI.enabled = true;
}
if (GUILayout.Button("Replace"))
{
var selection = Selection.gameObjects;
var parentGameobjects = CheckParents(selection);
#if UNITY_EDITOR
UnityEditor.Selection.objects = parentGameobjects;
#endif
for (var i = parentGameobjects.Length - 1; i >= 0; --i)
{
var selected = parentGameobjects[i];
var prefabType = PrefabUtility.GetPrefabType(prefab);
GameObject newObject;
if (prefabType == PrefabType.Prefab)
{
newObject = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
}
else
{
newObject = Instantiate(prefab);
newObject.name = prefab.name;
}
if (newObject == null)
{
Debug.LogError("Error instantiating prefab");
break;
}
Undo.RegisterCreatedObjectUndo(newObject, "Replace With Prefabs");
newObject.transform.parent = selected.transform.parent;
newObject.transform.position = selected.transform.position;
newObject.transform.rotation = selected.transform.rotation;
newObject.transform.localScale = selected.transform.localScale;
newObject.transform.SetSiblingIndex(selected.transform.GetSiblingIndex());
DestroyObjectInPrefab(selected.transform);
}
}
if(GUILayout.Button("Get Info"))
{
TransformSaver.SaveTransform(null, Selection.gameObjects[0]);
}
GUI.enabled = false;
EditorGUILayout.LabelField("Selection count: " + Selection.gameObjects.Length);
}
private GameObject[] CheckParents(params GameObject[] objects)
{
List<GameObject> parents = new List<GameObject>(objects.Length);
Transform[] transforms = objects.Select(go => go.transform).ToArray();
for (int objectIndex = 0; objectIndex < transforms.Length; objectIndex++)
{
if (!IsChildOfAny(transforms[objectIndex], transforms))
parents.Add(transforms[objectIndex].gameObject);
}
return parents.ToArray();
}
private bool IsChildOfAny(Transform potentialChild, params Transform[] potentialParents)
{
for (int index = 0; index < potentialParents.Length; index++)
{
if (IsParentOf(potentialParents[index], potentialChild))
return true;
}
return false;
}
private bool IsParentOf(Transform potentialParent, Transform potentialChild)
{
if (potentialChild.parent == null)
return false;
if (potentialChild.parent == potentialParent)
return true;
return IsParentOf(potentialParent, potentialChild.parent);
}
private void DestroyObjectInPrefab(Transform transform)
{
if (PrefabUtility.IsPartOfPrefabInstance(transform))
{
//if a part of a prefab instance then get the instance handle
Object prefabInstance = PrefabUtility.GetPrefabInstanceHandle(transform);
//destroy the handle
if (prefabInstance != null)
{
Undo.DestroyObjectImmediate(prefabInstance);
}
}
//the usual destroy immediate to clean up scene objects
//DestroyImmediate(transform.gameObject, true);
Undo.DestroyObjectImmediate(transform.gameObject);
}
private void OnSelectionChange()
{
Repaint();
}
}
I'm selecting this door the door is inside a space station and the door is a child of another gameobject and the other gameobject is also child :
Then I have a prefab I want to replace it with the door :
The prefab is the same door I just changed the two doors in the middle made them in red but the prefab is just a door like in thecfirst screenshot. Same size scaling :
Then when making the replacing the prefab is places in a bit back from where the door was position but in the inspector I see same position as the door :
Now the prefab is positioned much to the back inside the room.
If I change the position and rotation in my code to local then the prefab will be positioned to much forward. It will never position at the place of the door.
I tried other replace scripts all give the same result/s.
I didn't change anything in the prefab(The prefab is a door) only add this colors.
This is happening because the center of the prefab is different than the original object's center.
You can recenter object by putting it in a empty object and moving it in the local position of that object.
Then you can use that object as the prefab that is going to be in the scene.
Hope it helped

How to set distance between spawned prefabs?

I want to spawn prefab objects but now the object spawn multiply in one position. I have set up 4 positions around the player and for spawning the objects I'm using this code:
public class EnemySpawner : MonoBehaviour {
public static EnemySpawner instance;
[SerializeField]
private int scoreMileStone = 100; //this will define number of cars in the scene
private int milestoneIncreaser = 100; //this sets new milestone once old is reached
[SerializeField]
private Transform[] spawnPos; //store all the available spawn position
[SerializeField]
private int policeCarRequired; //this will tell how much cars are needed in the scene at a time
private int currentPoliceCar; //this variables keep track of total number of cars in the scene
private GameObject target; //store player reference in this variable
private int lastPosition, r;
private int lastSpawnPos;
public int CurrentPoliceCar { get { return currentPoliceCar; } set { currentPoliceCar = value; } } //getter and setter
// Use this for initialization
void Awake ()
{
if (instance == null) instance = this;
}
// Update is called once per frame
void Update ()
{
if (GuiManager.instance.GameStarted == false || GuiManager.instance.GameOver == true)
return;
if (target == null) //if target is null
{
target = GameObject.FindGameObjectWithTag("Player"); //try detecting target again
return; //return from the method
}
MilestoneIncreaser(); //increase milestone
if (currentPoliceCar < policeCarRequired) //if currentPoliceCar is less than policeCarRequired
{
SpawnPoliceCar(); //spawn police car
}
}
void SpawnPoliceCar() //spawn police car
{
GameObject wolf = ObjectPooling.instance.GetPooledObject("Wolf"); //get police car reference from objectpooling
RandomPos();
int r = Random.Range (0, spawnPos.Length);
while(lastSpawnPos == r)
r = Random.Range (0, spawnPos.Length);
wolf.transform.position = new Vector3(spawnPos[r].position.x, 0, spawnPos[r].position.z); //set the transform
wolf.SetActive(true); //set it active in scene
wolf.GetComponent<Damage>().DefaultSetting(); //call DefaultSettings method
lastSpawnPos = r;
currentPoliceCar++; //increase currentPoliceCar by 1
}
void MilestoneIncreaser() //increase the milestone
{
if (GuiManager.instance.Score >= scoreMileStone) //if currentScore is greater or equal to scoreMilestone
{
scoreMileStone += milestoneIncreaser; //increase the milestone
if (policeCarRequired < 8) //if max policeCarRequired is less than 8
policeCarRequired++; //increase policeCarRequired by 1
}
}
void RandomPos()
{
int r = Random.Range(0, spawnPos.Length); //get random number between zero and total spawnpos
while(lastPosition == r)
r = Random.Range(0, spawnPos.Length);
}
}
That gives me the objects but without any space between them, the objects spawn for example 4 in one position and 3 in the other but they are squeezed. Can I fix that in some way?

Intergrating life of player in each level in unity

In my game there are various levels
I have made those level in separate scenes
Every Scene has a player at the starting point and when it crosses the exit point the next level (next scene) is loaded but the health and life are reset as starting point in the game and not remain what the player currently has when he exited the level
Exit level Script:-
using UnityEngine;
using System.Collections;
public class ExitLevel : MonoBehaviour {
public string scene;
private Player player;
// Use this for initialization
void Start () {
player = GameObject.Find ("Player").GetComponent<Player> ();
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter2D(Collider2D target){
if (target.gameObject.tag == "Player") {
if (player.ArtifactCount == 1) {
player.ArtifactCount = 0;
Destroy (target.gameObject);
Application.LoadLevel (scene);
}
}
}
}
LifeMeter Script:-
using UnityEngine;
using System.Collections;
public class LifeMeter : MonoBehaviour {
public float Life = 100;
public float maxLife = 100;
public float LifeBurnRate = 1f;
public Texture2D bgTexture;
public Texture2D LifeBarTexture;
public Texture2D HeartTexture;
public int iconWidth = 32;
public Vector2 LifeOffset = new Vector2(255, 10);
public int HeartCount = 3;
public Vector2 HeartOffset = new Vector2(455, 6.5f);
public int HeartDistance = 0;
public int HeartDistanceAddup = 40;
public int HeartDisplayWidth = 40;
public int HeartDisplayHeight = 40;
private Player player;
private ExitLevel exitLevel;
// Use this for initialization
void Start () {
player = GameObject.FindObjectOfType<Player> ();
}
public void OnGUI(){
var percent = Mathf.Clamp01 (Life / maxLife);
if (!player)
percent = 0;
if(Life == 0 && HeartCount !=0 ){
HeartCount = HeartCount - 1;
Life = 100;
}
HeartDistance = 0;
DrawMeter (LifeOffset.x, LifeOffset.y, LifeBarTexture, bgTexture, percent);
for (int i = 0; HeartCount > i; i++) {
HeartDistance = HeartDistance + HeartDistanceAddup;
GUI.DrawTexture (new Rect (HeartOffset.x + HeartDistance, HeartOffset.y, HeartDisplayWidth, HeartDisplayHeight), HeartTexture);
}
}
void DrawMeter(float x, float y, Texture2D texture, Texture2D background, float percent){
var bgW = background.width;
var bgH = background.height;
GUI.DrawTexture (new Rect (x, y, bgW, bgH), background);
var nW = ((bgW - iconWidth) * percent) + iconWidth;
GUI.BeginGroup (new Rect (x, y, nW, bgH));
GUI.DrawTexture (new Rect (0, 0, bgW, bgH), texture);
GUI.EndGroup ();
}
// Update is called once per frame
void Update () {
}
public void life(){
Life = Life - LifeBurnRate;
if (HeartCount == 0) {
{ Explode script = player.GetComponent<Explode> ();
script.OnExplode ();
}
}
}
}
you can use PlayerPrefs (Stores and accesses player preferences between game sessions)for save current status of Player.
Reffer this link http://docs.unity3d.com/ScriptReference/PlayerPrefs.html
There are two ways to proceed in the above case:
You can add DontDestroyOnload(this); to your player object. This
will not destroy that game object when the new level loads. And On
Every start of level you can spawn him your level start point. This
way your player's stats will remain consistent throughout the game.
You can use a static class to get the players health and other
required stats. Save the players health in the static class while
exiting the level and apply the values to the next levels player
object when the next level loads.

Categories