Getting transforms of objects in other scenes?

About a week ago now, I was tasked to create a Skyrim functioning door system, where you could give the script the player object, a new scene, and an object name, and it load the new level without destroying the character, find the object via its name and send the player to that objects transform, I think I am about half way there, but not sure.
As I am a 3D artist, I had to do my best with the limited scripting knowledge I had.

Can anyone help me complete this? All help is hugely appreciated.

P.S. For anyone who manages to get this working how I need it to, will get a date driven event system for stuff like timed Christmas, New Years and Easter objects, if they want it.

#pragma strict

var PlayerCharacter : Transform;
var SpawnPoint : String = "";
private var drawGUI = false;
var Spawner : Vector3;
var NewScene : String = "";
var toText : String = "";

function Update ()
{
if (drawGUI == true && Input.GetKeyDown(KeyCode.F))
{
     LoadNewScene();
}
}

function OnTriggerEnter (theCollider : Collider)
{
    if (theCollider.tag == "Player")
    {
        drawGUI = true;
    }
}

function LoadNewScene ()
{
    DontDestroyOnLoad(PlayerCharacter);
    Application.LoadLevel(NewScene);
    yield WaitForSeconds (0.2);
    Spawner = GameObject.Find(SpawnPoint).transform.position;
    //Vector3 position = Spawner.transform;
    PlayerCharacter.transform.Translate(Spawner);
   
}

function OnGUI()
{
    if (drawGUI == true)
    {
        //GUI.Label (Rect (Screen.width*0.5-0, 200, 120, 22), "Press F to open to");
        //GUI.Label (Rect (Screen.width*0.5-35, 220, 150, 22), toText);
       
    //GUI.color = new Color(1,1,1,1.0f);
    GUI.skin.box.fontSize=15;
    GUI.backgroundColor = Color(0, 0, 0, 0);
    GUI.BeginGroup (Rect (Screen.width / 2 - 75, Screen.height / 2 - 0, 150, 50));

    GUI.Box (Rect (0,0,150,25), "Press F to open to");
    GUI.Box (Rect (0,22,150,25), toText);
   
    GUI.EndGroup ();
    }
}

function OnTriggerExit (theCollider : Collider)
{
    if (theCollider.tag == "Player")
    {
        drawGUI = false;
    }
}

You’re using a coroutine without using StartCoroutine (I don’t know if it is necessary with UnityScript ??).

Also, you should use the event “OnLevelWasLoaded” if you want to teleport the player when the level is loaded. Currently, you’re trying to get a spawn even if the level was not loaded… so it can fail.

  • in your LoadNewScene function, remove everything from “yield WaitForSeconds (0.2)”.
  • create a game object “Spawn” in your new scene (where the player should be) and assign it a script (SpawnSpot ?)
  • within “OnLevelWasLoaded”, find the player character and teleport him to the current position.

Your player character must have something unique if you want to find him (tag ? game object name ? a component ?).

I don’t think in this instance I need to state a StartCoroutine, and this provides no errors.
The player is the only object with the tag Player, why do I need a script on Spawn and what needs to go in it?

If you don’t use StartCoroutine, how do you start your Coroutine ? Put a Debug.Log in “LoadNewScene”, the function will not be executed because you didn’t use StartCoroutine (I just checked on Unity Documentation, I wasn’t sure you need to use StartCoroutine with UnityScript but it appears you have to use it). And yes, if you try to launch a Coroutine without using StartCoroutine, no error will be displayed, I don’t know why…

Edit: Nevermind ! I didn’t read the entire description… “When using JavaScript it is not necessary to use StartCoroutine, the compiler will do this for you. When writing C# code you must call StartCoroutine.”. Anyway, in C#, no error is displayed if you don’t call StartCoroutine.

I told you what your Spawn game object needs to do : implement the event “OnLevelWasLoaded” (find the player using his tag and teleport it to the Spawn position).

I think you would only want to use DontDestroyOnLoad one time. I do this in an init scene in an awake and then load the next scene in the start. If you put it all over the place and the player returns to the level, you will have two players. I don’t know about the door you are talking about, never played Skyrim.

in the main world (outside) we will be having multiple doors to other locations, how do i determine one from the other if I am only using find via component for the spawn point?

So far, I have this.
The only problem is when it goes to print the objects coords, it prints the location of another object with that script on, instead of the object named in the script.

#pragma strict

var PlayerCharacter : Transform;
var Player;
var SpawnPoint : String = "";
private var drawGUI = false;
var Spawner;
var SpawnerPos;
var NewScene : String = "";
var toText : String = "";

function Update ()
{
if (drawGUI == true && Input.GetKeyDown(KeyCode.F))
{
     LoadNewScene();
}
}

function OnTriggerEnter (theCollider : Collider)
{
    if (theCollider.tag == "Player")
    {
        drawGUI = true;
    }
}

function LoadNewScene ()
{
    DontDestroyOnLoad(PlayerCharacter);
    Application.LoadLevel(NewScene);
   
}

function OnLevelWasLoaded ()
{
    Player = GameObject.FindGameObjectsWithTag ("Player");
    Spawner = GameObject.Find (SpawnPoint);
    SpawnerPos = transform.position;
    Debug.Log (SpawnerPos);
}

function OnGUI()
{
    if (drawGUI == true)
    {
        //GUI.Label (Rect (Screen.width*0.5-0, 200, 120, 22), "Press F to open to");
        //GUI.Label (Rect (Screen.width*0.5-35, 220, 150, 22), toText);
       
    //GUI.color = new Color(1,1,1,1.0f);
    GUI.skin.box.fontSize=15;
    GUI.backgroundColor = Color(0, 0, 0, 0);
    GUI.BeginGroup (Rect (Screen.width / 2 - 75, Screen.height / 2 - 0, 150, 50));

    GUI.Box (Rect (0,0,150,25), "Press F to open to");
    GUI.Box (Rect (0,22,150,25), toText);
   
    GUI.EndGroup ();
    }
}

function OnTriggerExit (theCollider : Collider)
{
    if (theCollider.tag == "Player")
    {
        drawGUI = false;
    }
}

Okay, so there is a problem if you have several spawns. You should use DontDestroyOnLoad on the trigger too ;

var PlayerCharacter : Transform;
var SpawnPoint : String = "";
var NewScene : String = "";

private var drawGUI = false;
private var hasToBeDestroyed = false;

function Update ()
{
    if (drawGUI == true && Input.GetKeyDown(KeyCode.F))
    {
         LoadNewScene();
    }
}
function OnTriggerEnter (theCollider : Collider)
{
    if (theCollider.tag == "Player")
    {
        drawGUI = true;
    }
}
function LoadNewScene ()
{
    // Don't destroy the player
    DontDestroyOnLoad(PlayerCharacter);

    // Don't destroy this trigger because we want it to handle the teleportation of the player
    DontDestroyOnLoad(gameObject);

    // When the level will be loaded, we must know which trigger has to be destroyed
    hasToBeDestroyed = true;

    // Load the new scene ; a room or "outside"
    Application.LoadLevel(NewScene);
}

// Called once the level is fully loaded
function OnLevelWasLoaded ()
{
    if (hasToBeDestroyed)
    {
        // We need to find the right spawn point (so it MUST have a unique name)
        var spawner = GameObject.Find (SpawnPoint);

        // Teleport the player to the spawn point
        PlayerCharacter.position = spawner.transform.position;

        // Destroy the trigger because we don't need it anymore
        Destroy(gameObject);
    }
}
function OnGUI()
{
    if (drawGUI == true)
    {
        // GUI stuff
    }
}
function OnTriggerExit (theCollider : Collider)
{
    if (theCollider.tag == "Player")
    {
        drawGUI = false;
    }
}

There are maybe some code mistakes (I never used UnityScript).

In your world (outside), you can have several triggers that lead to different scene (and / or spawn points). We keep the trigger alive just to know which spawn is used to teleport the player. The variable “hasToBeDestroyed” is used to know which trigger has been kept alive (when you will load the “world” scene, if you do not check this variable, all triggers will execute the code within “OnLevelWasLoaded”).

I don’t know why you’re not following the suggestions from the other thread(s).

I don’t think having Don’tDestroyOnLoad is a good idea on the trigger, because I will have a trigger to load that level in a place that makes no sense (not all the levels doors are in the same place (myfault)).

But as we are creating something with a similar functioning door to Skyrim, we were actually trying to create doors to new scenes that allow the player to dart back and forth, Skyrim was the best example I could think of, its not the easiest thing to explain as you can probably imagine. That was why I was trying to find the spawn via its name, so when you go back to the original outdoors world, you can set it to go back to the right door.

This is the main bit I am having trouble with.

#pragma strict

var PlayerCharacter : Transform;
var Player;
var SpawnPoint : String = "";
private var drawGUI = false;
var Spawner;
var SpawnerPos;
var NewScene : String = "";
var toText : String = "";

function Update ()
{
if (drawGUI == true && Input.GetKeyDown(KeyCode.F))
{
     LoadNewScene();
}
}

function OnTriggerEnter (theCollider : Collider)
{
    if (theCollider.tag == "Player")
    {
        drawGUI = true;
    }
}

function LoadNewScene ()
{
    DontDestroyOnLoad(PlayerCharacter);
    Application.LoadLevel(NewScene);
   
}

function OnLevelWasLoaded ()
{
    Player = GameObject.FindGameObjectsWithTag ("Player");
    Spawner = GameObject.Find (SpawnPoint);
    SpawnerPos = transform.position;
    Debug.Log (SpawnerPos);
}

function OnGUI()
{
    if (drawGUI == true)
    {
        //GUI.Label (Rect (Screen.width*0.5-0, 200, 120, 22), "Press F to open to");
        //GUI.Label (Rect (Screen.width*0.5-35, 220, 150, 22), toText);
       
    //GUI.color = new Color(1,1,1,1.0f);
    GUI.skin.box.fontSize=15;
    GUI.backgroundColor = Color(0, 0, 0, 0);
    GUI.BeginGroup (Rect (Screen.width / 2 - 75, Screen.height / 2 - 0, 150, 50));

    GUI.Box (Rect (0,0,150,25), "Press F to open to");
    GUI.Box (Rect (0,22,150,25), toText);
   
    GUI.EndGroup ();
    }
}

function OnTriggerExit (theCollider : Collider)
{
    if (theCollider.tag == "Player")
    {
        drawGUI = false;
    }
}

@Suddoha As I have stated, I am NOT a programmer, I very rarely touch things like this, the only programming I do on a regular basis, and that isnt even very often is HTML, CSS and Asp.Net so not everything posted is much use to me as I don’t understand half of it.

I think my code works well and do what you want. I made the code for you and I tried to explain it.

I don’t understand why you don’t try it ? I understood what you want, I played Skyrim (and it’s not a “Skyrim thing”, all games do that).

Please… even if you’re not a programmer, can you read at least my comments ? The trigger will be destroyed once the level will be loaded. We don’t care if it makes sense or not, it works and it is not “ugly”. It may exist another solution (a better one) but as you said, you’re NOT a programmer so I can’t do something more complex.

What you basically just said is:

“I am not a driver, I very rarely operate vehicles, the only driving I do on a regular basis is ride my riding lawn mower around. So not everything posted about driving a car down the highway I need to get down is much use to me as I don’t understand half of it.”

Well it sounds to me like it’s time for you to either start understanding it, or find/hire someone who understands it.

I’ve understood that from the beginning. That’s why i kept it pretty simple and even documented my code and posted an additional description and a HowTo. Don’t get me wrong, It’s okay to look for another solution but for me it seemed you haven’t even tried to use it.

Once again, i know you’re not a programmer and there’s probably also an easier way to achieve that (in one script, less code etc) but in order to make it re-usable and seperate the differents tasks, you have to think a bit further.

As you just said, you don’t think it’s a good idea to take the trigger with you and i agree on that. Regarding that I had already mentioned in the other thread numerous times that you should split that up and put every functionality into a single script which is then re-usable for different obects/prefabs or even purposes.

When i wrote the example, i kept in mind you want something which can be dragged from the project window and and dropped into the scene. Once set up, there wouldn’t be anything else to do than the latter and select the level to be loaded as far as i remember.

@Sbizz
After removing a few bugs (caused by my horrible GUI method not your code) It works, this has been bugging me for days.

The only problem I am having now is when I am going back to the original scene (looping back round) Unity seems to crash, I think this is due to the multiple characters now occupying the scene, is there any way to delete the old character and keep the new one?

What ? Is the Player Character dynamically created (using a script) or is he already created in the scene ?

Edit: can I have a link to the other thread ?

@Suddoha
First of all, sorry about all of this.
I understand it can be very infuriating for people, I get the same problem when I try to explain 3D artwork and modelling to audio artists and concept artists so I know what its like.

Bits and pieces of what you have all supplied have helped hugely with this, I just find some languages harder than others, I can pick up most web development languages up quite quickly, but clearly I need to take the time to learn a LOT more about scripts like Javascript and C#.

@Sbizz
The player is placed in the scene, I was going to instantiate it in there, but thought I would still have the same problem with that, as they would be still left in the scene upon returning, so never got round to it.
By dynamically I assume you do mean instantiating?

I think I know how to do this, I just avoided it as I thought it would present me with the same problem.

The other thread is here:

Okay, I saw the other thread. Apparently, the Player Character is already created in the main scene, so every time you’ll load this scene, you’ll create another Player Character. You have 2 solutions:

  • If your Player Character has a script, you can check in the Start or Awake function if a player already exists. It it does, destroy it. I don’t really like this option, but it’s gonna work.
  • When you start your game, you instantiate yourself the Player Character. Because you start the game only once, there will be no problem to load several times the main scene.

Also, @Suddoha doesn’t like my method too and I checked his solution ; it works, but if your building has several doors, it will fail ; imagine a castle… you enter using the DoorA, you leave it using the DoorB (he keeps the last position / rotation of your player character had in the main scene). You should know what you want, so If you have only one door per building, so you can use his method. But I prefer my method, even if we don’t destroy directly the trigger (it will be destroyed once the level is loaded).

If I were to instantiate my character, I couldn’t do it in a regular script, it would have to be something that could only be done once per new game, so how would this be done? How would I stop the script instantiating the character every time I loaded that scene?