Давай по порядку:
Чтобы передать пуле ссылку на игрока надо чтобы на пуле висел скрипт, который будет хранить эту ссылку. Скрипт можно повесить заранее, а можно во время создания пули. В первом варианте после создания объекта пули надо "добыть" скрипт этой пули и инициализировать ему переменную игроком. Во втором случае у тебя будет ссылка на скрипт при его добавлении.
Допустим скрипт пули
public class Bullet: MonoBehaviour
{
public Player player;
}
далее где-то в скрипте Player при стрельбе (первый вариант):
var bulletGameObject = (GameObject)Instantiate(bulletPrefab);
var bullet = bulletGameObject.GetComponent<Bullet>();
bullet.player = this;
второй вариант:
var bulletGameObject = (GameObject)Instantiate(bulletPrefab);
var bullet = bulletGameObject.AddComponent<Bullet>();
bullet.player = this;
Можно слать мессаджи объектам, с передачей параметров. Например при ударе о объект - можно послать ему сообщение Damage(countDamage). Если в скриптах объекта реализована такая функция, то она будет вызвана.
GameObject.SendMessage Правда сообщения поддерживают 0 или 1 параметр.
По поводу пустого объекта с функциями можно поступить по разному:
1. Создать объект в сцене, на него повесить скрипт с глобальными функциями. В Awake записать на него ссылку в статическую переменную. Через нее использовать функции этого объекта.
public class GlobalFunctions:MonoBehaviour
{
public static GlobalFunctions instance;
public void Awake()
{
instance = this;
}
public void ShakeCamera()
{
// тряска камеры
}
}
Тогда использовать функцию тряски можно так:
GlobalFunctions.instance.ShakeCamera();
2. Сделать instance из этого примера свойством, автоматически создающим такой объект в сцене (если интересно, то напишу пример позже)
3. Писать функции статическими, тогда их можно вызывать отовсюду и не обязательно вешать скрипт на объект:
public class GlobalFunctions
{
public static void ShakeCamera()
{
var cam = Camera.main;
// тряска камеры
}
}
Тогда использовать функцию тряски можно так:
GlobalFunctions.ShakeCamera();
PS: долго писал)