Topic: UI Marker and gameobject

Hello,
Quick question before i refactor things, to check if there is an existing option to my issue.
- I m having a prefab to instantiate in order to replace classic texture marker, and i use the uGUIMarkerDrawer example to do so.
- I would need to access a reference of the gameobject instance created from the prefab, but in UGuiMarker Drawer, it is shown as an inner variable of some function.
Any chance a function already exists to retrieve the corresponding gameobject ref from the corresponding onlineMapsMarker created with this call : OnlineMapsMarker marker = OnlineMapsMarkerManager.CreateItem(coords, unit.Title);
?

Thanks a lot.

Re: UI Marker and gameobject

Hello.

In the uGUIMarkerDrawer example, a reference to the instance is stored inside the marker and you can get it from anywhere.
But keep in mind that the instance is destroyed when the marker goes out of the map.

GameObject markerInstance = marker ["instance"] as GameObject;
Kind Regards,
Infinity Code Team.

Do not know the best way to thank the developer? Rate the asset in Asset Store!

3 (edited by emmanuel.g.blanchard 2020-09-14 14:56:57)

Re: UI Marker and gameobject

Thanks for the quick reply.
Didn t notice the destroy stuff before you mentioned it to me, and i need objects to remain alive (and rather play with their enabled/disabled property)
Then i guess i will probably go with something close to this thread, along with ui objects : https://forum.infinity-code.com/viewtopic.php?id=1571
Looks like a quick and easy approach. Makes sense to you?

4 (edited by emmanuel.g.blanchard 2020-09-14 16:10:44)

Re: UI Marker and gameobject

Ok. Indeed using the other forum thread, it was super- easy unless there are performance issues i haven't noticed. Putting a code example here in case someone need it. My prefab also has a button script for test

public class TestMapItem : MonoBehaviour
{
    public float Longitude {get;set;}
    public float Latitude {get;set;}
        
    void Awake()
    {
        OnlineMaps.instance.OnChangePosition += UpdatePosition;
        OnlineMaps.instance.OnChangeZoom += UpdatePosition;
        this.GetComponent<Button>().onClick.AddListener(this.HandleButtonClicked);    
    }

    public void UpdatePosition()
    {
        // the object is disabled when not in the visible map
        this.gameObject.SetActive(OnlineMaps.instance.InMapView(Longitude, Latitude));
        // the following line works with uGui controller
        this.gameObject.transform.position = OnlineMapsControlBase.instance.GetScreenPosition(Longitude, Latitude);
        // if you want to use tileset controller, you may use OnlineMapsControlBaseDynamicMesh.instance.GetWorldPosition
    }
    public void HandleButtonClicked()
    {
        Debug.Log("test click");
    }

    public void Activate(float longitude, float latitude)
    {
        this.Longitude = longitude;
        this.Latitude = latitude;
        this.UpdatePosition();
    }

    // to instantiate the prefab i.e. pass it as the parameter; root is where the object is placed. i used the map transform
    // the script is attached to the prefab itself... but could be added with SetComponent instead.
    public static TestMapItem Create(float longitude, float latitude, Transform root, GameObject prefab)
    {
        GameObject obj = Instantiate(prefab, root, false);
        TestMapItem result = obj.GetComponent<TestMapItem>();
        result.Activate(longitude, latitude);
        return result;
    }
}

Re: UI Marker and gameobject

One small thing about your script:
We do not recommend using singletons in Awake or OnEnable methods, because the singletons may not have been initialized yet.
Use singletons in Start method or later.

Kind Regards,
Infinity Code Team.

Do not know the best way to thank the developer? Rate the asset in Asset Store!

Re: UI Marker and gameobject

thanks for the input.

One quick note, when dealing with events (zoom especially, but movements as well), the result of OnlineMapsControlBase.instance.GetScreenPosition frequently ends a bit misplaced within the map. That s easy to notice if you refer to a precise and known location (e.g. your house). If you have a big zoom value, it s a question of meters, but if you have smaller ones, it could mean hundreds of kms.

Looks to me what could explain this temporary lack of precision is the latest event not being caught (hence not triggering position update) because as soon as you slightly move again, it repositions correctly.

Re: UI Marker and gameobject

This is because GetScreenPosition returns values for the current (displayed) state of the map.
The map is not redrawn immediately, and no one knows how many frames it will take to render the new map state.

How to work around this problem:
1. When calling OnChangePosition and OnChangeZoom, just set the flag, that you need to update the position.
2. Subscribe to OnlineMaps.OnMapUpdated and when this action is called update the position and clear the flag.

Kind Regards,
Infinity Code Team.

Do not know the best way to thank the developer? Rate the asset in Asset Store!

Re: UI Marker and gameobject

This fixed the issue. Thanks :-)

But actually, if one use OnMapUpdated... OnChangePosition and OnChangeZoom do not seem to be needed at all?  I commented them and the result is the same. Or does it happen frequently that map is redrawn without being moved/zoomed? Just to get a better understanding of the onlineMaps process.

Re: UI Marker and gameobject

The map can be redrawn not only when the position or zoom has changed.
Redrawing also occurs when tiles are loaded, marker positions are changed, drawing elements are added, etc.
By listening to OnChangePosition and OnChangeZoom, you know for sure that the positions of your objects are out of date, and you need to update this.

Kind Regards,
Infinity Code Team.

Do not know the best way to thank the developer? Rate the asset in Asset Store!

10 (edited by emmanuel.g.blanchard 2020-09-15 13:22:37)

Re: UI Marker and gameobject

Makes sense. Thanks for the explanations.

For ref, below is the updated code if it is of interest to someone:

using UnityEngine;
using UnityEngine.UI;

public class TestMapItem : MonoBehaviour
{
    public float Longitude { get; set; }
    public float Latitude { get; set; }
    private bool PositionToUpdate = false;


    public void Start()
    {
        OnlineMaps.instance.OnChangePosition += this.FlagUpdatePosition;
        OnlineMaps.instance.OnChangeZoom += this.FlagUpdatePosition;
        OnlineMaps.instance.OnMapUpdated += this.UpdatePosition;
        this.GetComponent<Button>().onClick.AddListener(this.HandleButtonClicked);
    }

    private void FlagUpdatePosition()
    {
        this.PositionToUpdate = true;
    }

    private void UpdatePosition()
    {
        if (this.PositionToUpdate)
        {
            float longitude = this.Longitude;
            float latitude = this.Latitude;
            // object is enabled only if it is visible
            this.gameObject.SetActive(OnlineMaps.instance.InMapView(longitude, latitude));
            // works for uGui controller; if you want to use tileset controller, you may use OnlineMapsControlBaseDynamicMesh.instance.GetWorldPosition
            this.gameObject.transform.position = OnlineMapsControlBase.instance.GetScreenPosition(longitude, latitude);
            this.PositionToUpdate = false;
        }
    }

    private void HandleButtonClicked()
    {
        // for test purpose
        Debug.Log("test click");
    }

    public void Destroy()
    {
        OnlineMaps.instance.OnChangePosition -= this.FlagUpdatePosition;
        OnlineMaps.instance.OnChangeZoom -= this.FlagUpdatePosition;
        OnlineMaps.instance.OnMapUpdated -= this.UpdatePosition;
        GameObject.Destroy(this.gameObject);
    }

    public void Activate(float longitude, float latitude)
    {
        this.Longitude = longitude;
        this.Latitude = latitude;
        this.PositionToUpdate = true;
        this.UpdatePosition();
    }

    public static TestMapItem Create(float longitude, float latitude, Transform root, GameObject prefab)
    {
        GameObject obj = Instantiate(prefab, root, false);
        TestMapItem result = obj.GetComponent<TestMapItem>();
        result.Activate(longitude, latitude);
        return result;
    }
}