Feb 272015
 

To ease testing out maps — to avoid moving the player GO every time we want to start at a different part of the map — we have a player_start object. It teleports the player GO to itself on game start. However, if you could only have 1 such player_start on map, it would kinda defeat the purpose of easing the work, right?

vap_player_start

So, we allow to have multiple such GOs in the map. But how to determine at which player_start the player should start? Well, the player_start component has a boolean for that. That’s nice, but if you set that bool on a new player_start, the last player_start that was previously active will still have the bool set to true as well; so the player will be teleported twice, and you can hardly predict where he will end up.

So first you need to set off the currently active player start and then set on the new player start. Easy, right? No, it’s annoying and there’s a better solution! Let’s change those bools on player_starts right in the editor (in edit mode) whenever we change one player start.

For this, there is a nice unity attribute: [ExecuteInEditMode]. It will call the callbacks just as it would in play mode, but only when something changes in the scene; not per frame.

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
[AddComponentMenu("Vaporum Scripts/Player Start")]
public class VapPlayerStart : VapBehaviour
{
	[Tooltip("Tick this on to start gameplay here.")]
	public bool on = false;
	bool lastOn = false;
	
	void Start()
	{
		// Execute only in play mode.
		if (Application.isPlaying)
		{
			// First snap this GO to grid to correct any human mistakes in editing.
			VapGM.SnapToTileGrid(this.gameObject);
	
			// Teleport player here.
			if (on == true)
			{
				Transform p = VapGM.playerGO.transform;
				p.position = this.transform.position;
				p.rotation = this.transform.rotation;
				
				// Set TileObject if we're standing on one.
				VapTileObject t = VapGM.GetTileObject(p.position);
				if (t)
				{
					p.GetComponent().SetCurrentTile(t);
				}
			}
		}
	}
	
	void Update()
	{
		#if UNITY_EDITOR
		// In editor mode, check if 'on' was changed.
		if (Application.isEditor)
		{
			if (on != lastOn) SetPlayerStart();
		}
		#endif
	}
	
	#if UNITY_EDITOR
	// Sets this component as the only player start on map.
	void SetPlayerStart()
	{
		if (on)
		{
			VapPlayerStart[] list = FindObjectsOfType(typeof(VapPlayerStart)) as VapPlayerStart[];
			
			foreach (VapPlayerStart p in list)
			{
				if (p != this)
				{
					p.on = false;
					UnityEditor.EditorUtility.SetDirty(p);
				}
			}
		}
		
		lastOn = on;
	}
	#endif
}

I was previously doing this via OnValidate() callback, but that was unreliable. This new solution works like a charm!

Enjoy!