mapbox / mapbox-unity-sdk

Mapbox Unity SDK - https://www.mapbox.com/unity/
Other
721 stars 214 forks source link

Maps don't load outside of development environment #1071

Closed dpruitt90 closed 5 years ago

dpruitt90 commented 6 years ago

Unity Version: Unity 2018.2.11f1 Mapbox Version: 1.4.5

Description: We are working on a proof of concept in which we generate a player object on a specified real world map location (Lat/Lon) and also generate several prefabs at other locations on the map.

This works well in our development environment (Mac OS) but when we build for other devices (Windows/Mac desktop, iOS, and Android) the app does not work. See images below. The first image is from the game running in the development environment. The next two are from builds for Mac desktop and iOS. I am sure we are missing something in either the build or the configuration. We are not receiving any build (or other) errors.

Can you point us in the right direction?

dpruitt90 commented 6 years ago

Attached Pictures.... game_mac game-devenvironment game-ios

abhishektrip commented 6 years ago

@dpruitt90 Do you have location services turned on for iOS builds? I am not sure if Unity can get live location for MacOS.

dpruitt90 commented 6 years ago

On mobile builds we do. However, we are not using LocationProvider. We are instantiating a map and placing game objects on it re: Spawn on Map. We added the Location-based game scene to the game and that scene seems to load correctly. For the other scenes, we are dynamically adding the Player object as well as another game object through code with the initial placement occurring during the Awake event of a Player Factory. While not exact, the following snippet shows how we are attempting to start the scene (note the scene is called from a main menu):

private void Awake() { abstractMap = UnityEngine.Object.FindObjectOfType(); counter = 0;

    // Call to external web service to retrieve objects
    {Code}

    availablePlayers = new List<Player>();

                foreach (Player Returned from Web Service)
                {

                        Vector2d playerLatLon = new Vector2d(Double.Parse(player.UserLat), Double.Parse(player.UserLon));
                        Vector3 playerLocation = abstractMap.GeoToWorldPosition(playerLatLon, true);

                        _markerPrefab = FindObjectOfType<Player>().gameObject;

                        var instance = Instantiate(_markerPrefab, parentAnchor);
                        instance.transform.localPosition = abstractMap.GeoToWorldPosition(playerLatLon, true);
                        instance.transform.localScale = new Vector3(.2f, .2f, .2f);

                    }

            }
        }

I think it must be related to the way we are placing the players on the map. When we place the player through the IDE it works. When we dynamically generate the player and other objects it only works in the development environment. Assuming that the map is not loading before we attempt to place the objects, is there a prescribed methodology for ensuring the map is loaded prior to placing game objects dynamically? Or are we missing something else?

dpruitt90 commented 6 years ago

Two other notes:

  1. Why would location services be required if we are not using GPS?
  2. Our Player Factory is attached to the Map object in the scene.
abhishektrip commented 6 years ago

@dpruitt90

Why would location services be required if we are not using GPS?

Not required, I assumed you are using location provider to instantiate the map.

Looking at the code snippet, it might be that you are accessing the map before the map is initialized. map has an OnInitialized event which gets triggered. GeoToWorldPosition will not work correctly before the map is initialized.

dpruitt90 commented 6 years ago

@atripathi-mb Is there a recommended way to do this? Should I leave the instantiation of the map variable in Awake() and move the population of objects to an event wired up to the OnInitialized event of the map? I am unclear on what the Best Practice is for this problem. Thanks!

abhishektrip commented 6 years ago

@dpruitt90

Should I leave the instantiation of the map variable in Awake() and move the population of objects to an event wired up to the OnInitialized event of the map

Yes, this is the recommended best practice đź‘Ť

dpruitt90 commented 6 years ago

@atripathi-mb OK, I am TOTALLY lost.....

Project: Scene 0 is a menu with two buttons. Each button launches Scene 1 but passes in a different LatLon in which to instantiate the player (by setting the values for PersistantManagerScript.Instance.PlayerLat and PersistantManagerScript.Instance.PlayerLon - which are being passed correctly). Setting the location in the Start() method of the Player class (attached to the Player Object) works in the IDE but does not work in any other device.

Solution: Based on your initial feedback, I added the following code to the Awake() method of the Player Class:

abstractMap = UnityEngine.Object.FindObjectOfType();


if (abstractMap == null)
 {

Debug.LogWarning("Could not find AbstractMap...");

enabled = false;

return;

}

abstractMap.OnInitialized += OnMapReady;


I then creates an OnMapReady Method:

void OnMapReady()
 { 

abstractMap.OnInitialized -= OnMapReady;

enabled = true;

StartCoroutine(InitializePlayer()); }

This broke the player placement in the dev environment, so I then added the Coroutine “InitializePLayer()” (shown above):


IEnumerator InitializePlayer()
 {

player = GameObject.Find("Player");


Vector2d playerLatLon = new Vector2d(Double.Parse(PersistantManagerScript.Instance.PlayerLat), Double.Parse(PersistantManagerScript.Instance.PlayerLon));


player.transform.localPosition = Conversions.GeoToWorldPosition(playerLatLon, abstractMap.CenterMercator, abstractMap.WorldRelativeScale).ToVector3xz();


   player.transform.position = Conversions.GeoToWorldPosition(playerLatLon, abstractMap.CenterMercator, abstractMap.WorldRelativeScale).ToVector3xz();

        player.transform.localScale = new Vector3(.2f, .2f, .2f);

       

 player.transform.position = abstractMap.GeoToWorldPosition(playerLatLon, true);


        

 yield return null;
    

}

This results in the game not working in Development environment.

What am I doing wrong????? If don’t add the code shown above, the player is instantiated in the correct position (based on the LatLon passed in from the buttons on the menu), however it does not work in any deployed devices (mobile or desktop).


abhishektrip commented 6 years ago

@dpruitt90 Is the InitializePlayer() method being invoked correctly? Could you put a screen shot of your map settings here please?

dpruitt90 commented 6 years ago

@atripathi-mb I moved the following code from the InitializePlayer() method to Start():

player = GameObject.Find("Player");

    Vector2d playerLatLon = new Vector2d(Double.Parse(PersistantManagerScript.Instance.PlayerLat), Double.Parse(PersistantManagerScript.Instance.PlayerLon));
    //abstractMap = UnityEngine.Object.FindObjectOfType<AbstractMap>();

    player.transform.localPosition = Conversions.GeoToWorldPosition(playerLatLon, abstractMap.CenterMercator, abstractMap.WorldRelativeScale).ToVector3xz();
    player.transform.position = Conversions.GeoToWorldPosition(playerLatLon, abstractMap.CenterMercator, abstractMap.WorldRelativeScale).ToVector3xz();

    player.transform.localScale = new Vector3(.2f, .2f, .2f);

and it began to work in the IDE, but still not in deployed instances.

Here is the screen shot of my map settings (note: I removed the SoldierFactory reference to concentrate on troubleshooting the instantiation of the player):

image

dpruitt90 commented 6 years ago

@atripathi-mb And yes, the Initialize Player method is being called as a Coroutine from the OnMapReady method. It just isn't instantiating the player.

abhishektrip commented 6 years ago

@dpruitt90 I created a test script based on your code and it worked fine for me right out of the box.

public class PlaceCube : MonoBehaviour
{

    AbstractMap abstractMap;

    private void Awake()
    {
        abstractMap = UnityEngine.Object.FindObjectOfType<AbstractMap>();

        Debug.Log("Awake");
        if (abstractMap == null)
        {

            Debug.LogWarning("Could not find AbstractMap...");

            enabled = false;

            return;

        }
        abstractMap.OnInitialized += OnMapReady;

    }

    private void OnMapReady()
    {
        Debug.Log("OnMapReady");
        abstractMap.OnInitialized -= OnMapReady;

        enabled = true;

        StartCoroutine(InitializePlayer());
    }

    private IEnumerator InitializePlayer()
    {
        Debug.Log("InitPlayer");
        gameObject.SetActive(true);
        Vector2d playerLatLon = new Vector2d(37.7873886618601, -122.397240448021);

        gameObject.transform.localScale = new Vector3(1f, 200f, 1f);

        gameObject.transform.position = abstractMap.GeoToWorldPosition(playerLatLon, true);

        yield return null;

    }
}

btw any specific reason you are setting both localPosition and position ?

dpruitt90 commented 6 years ago

@atripathi-mb On what device is it working? Windows Player? Mac Player? iOS? Android? It only works for me in the Unity IDE.

No reason I am setting both, except a lack of understanding and too many changes trying to debug this.....:-)

abhishektrip commented 6 years ago

Working in editor and MacOS. image

dpruitt90 commented 6 years ago

@atripathi-mb OK. After all of this it seems the issue is map-dependent and that the scripts are working. I did the following:

  1. Created a new scene with a default map and added a cube with your script. It worked in both the IDE and Mac OS.
  2. Changed the map in that scene, and had the same issues.

Why is the spawning so map-dependent? If I make any changes to the map in either scene, the game stops working and either generates floating game objects (at the incorrect scale) or has the game objects fall forever (sometimes passing through the map and other times starting below the map and falling).

Here is a screen shot of my map settings.

image Can you see if your basic script works with this map setting and let me know what I have to do to get a non-basic map (i.e. using satellite image and non-flat terrain) working with dynamic spawning.

Thank you!

dpruitt90 commented 6 years ago

@atripathi-mb Steps to reproduce:

  1. Create New Scene
  2. Add Map Prefab
  3. Add Cube
  4. Add PlaceCube Script (that you sent) and attach to cube.
  5. Run Scene (It works in Dev as well as deployed instances).

Next

  1. Change Map to Lat/Lon to 36.0966, -112.0985
  2. Change Map Image to Mapbox Satellite
  3. Change Terrain to Mapbox Terrain with Elevation Layer Type of "Terrain with Elevation"
  4. Add Collider
  5. Press Play - The Cube does not show up on the map
  6. Build to Mac OS - The object and map generation exhibit the same issues I originally reported.

Thanks for your help! Please let me know what I am doing wrong....

abhishektrip commented 6 years ago

@dpruitt90 I am not able to reproduce the issue. I tried the steps exactly as you outlined. ( I did change the lat long of the cube to be visible from the new center) Here is it working on a MacOS build image

Here is screenshot of my settings. I tried both with & w/o tilemap and it worked both times. image

Not related to this issue, but I would recommend turning off relative Height setting.

abhishektrip commented 6 years ago

If it helps, we are in the process of releasing a new version early next week. This issue may most likely be already fixed.

Let me know how we can help get your issue resolved.

dpruitt90 commented 6 years ago

@atripathi-mb Thank you for all your help. I don’t know what the problem could be. I am using 3D and my camera is set as a first person (just behind and above the player). I am finding that even small changes blow up the IDE and/or deployed versions. Can you provide me with the same,e project you are using? Seriously at a loss on this. I do appreciate your help!

abhishektrip commented 6 years ago

@dpruitt90 Do you mind filing a ticket through our support channel? It would help us get in touch directly via email. Will be easier to send files if needed. https://www.mapbox.com/contact/support/#bug/unity

dpruitt90 commented 6 years ago

@atripathi-mb ok. thanks.

dpruitt90 commented 6 years ago

@atripathi-mb Couple of things. First, I thought the GitHub issue log was the venue for reporting issues. I submitted a bug via the link you provided. Second, I think there are two issues. First, the GeoToWorldPositin method of Abstract map seems to ignore the queryHeight parameter. When I change maps (and use Terrain with Elevation), the object spawns below the map (one of the issues). The other issue is (I think) related in that the spawning of objects outside of the IDE does not seem to work with the Satellite/Terrain w/elevation combinations. Thanks.

dpruitt90 commented 6 years ago

@atripathi-mb Sorry, last question. How long does it generally take to work through issues when submitted via the contact link you sent? We need to make a decision regarding how we are going to move forward (deciding between Unity and UE4) and I am fast approaching the decision point. Thanks again!

abhishektrip commented 6 years ago

@dpruitt90 we try to resolve issues as soon as possible. It would help if you could send us a sample project/package to reproduce the issue.

dpruitt90 commented 6 years ago

@dpruitt90 Deleting the link for security reasons, you can delete the dropbox folder. For future, don't include your key in the project.

abhishektrip commented 6 years ago

@dpruitt90 Finally, I was able to reproduce the issue. The issue was that when you were doing the height query, the terrain information was not yet processed and the height returned is zero. Here is how I modified the script, this should fix your issue. Can you give it a spin?

public class PlaceCube : MonoBehaviour
{

    AbstractMap abstractMap;

    private void Start()
    {
        abstractMap = UnityEngine.Object.FindObjectOfType<AbstractMap>();

        Debug.Log("Awake");
        if (abstractMap == null)
        {

            Debug.LogWarning("Could not find AbstractMap...");

            enabled = false;

            return;

        }
        abstractMap.MapVisualizer.OnMapVisualizerStateChanged += OnMapReady;

    }

    private void OnMapReady(ModuleState moduleState)
    {
        Debug.Log("OnMapReady");
        if (moduleState == ModuleState.Finished)
        {
            abstractMap.MapVisualizer.OnMapVisualizerStateChanged -= OnMapReady;

            enabled = true;

            StartCoroutine(InitializePlayer());
        }

    }

    private IEnumerator InitializePlayer()
    {
        Debug.Log("InitPlayer");
        Vector2d playerLatLon = new Vector2d(36.0966, -112.0985);  //new Vector2d(37.7873886618601, -122.397240448021);

        //gameObject.transform.localScale = new Vector3(1f, 200f, 1f);
        Debug.Log("Height ->" + abstractMap.QueryElevationInMetersAt(playerLatLon));

        gameObject.transform.position = abstractMap.GeoToWorldPosition(playerLatLon, true);

        yield return null;

    }
}
dpruitt90 commented 6 years ago

@atripathi-mb Thank you! Thank you! Thank you! Finally got everything working and loading in Mac OS as well as the Dev environment. I really appreciate your help! I will be looking into two other issues today: Errors when building for iOS and how to properly move a dynamically spawned object.

Again thank you! I can't remember the last time I had this much trouble getting into a new API/Environment, but your help has been invaluable and I think we are making progress on our evaluation. Hoping this is all worth it in the end! Best Regards!