0
\$\begingroup\$

I am trying to make game objects, like a coin or ammo clip, gravitate towards the player when they are within a set radius. I have seen this implemented in quite a few old school 90's games; when the player walks near anything, I want it to move to the player for collection. I can already handle the collection.

This is what I have, so far:

using UnityEngine;
using System.Collections;

public class MoveCoinsTowardsPlayer : MonoBehaviour 
{
    public Transform target;
    public float speed;

    void Update() 
    {
        float step = speed * Time.deltaTime;
        transform.position = Vector3.MoveTowards(transform.position, target.position, step);
    }
}

How do I make game objects move towards the player, when the player is within a set range?

\$\endgroup\$
  • \$\begingroup\$ You may have already found these, but if you search online for "Unity3d attractor" a lot of examples come up. \$\endgroup\$ – Tartle Wizard May 12 '17 at 1:31
  • \$\begingroup\$ I can't write up a full answer but the best way (and the one that will have the least performance impact) is for both the player and the coins to have colliders. The player will have a collider for radius detection and while the coins are within that collider (detect that with the collider on the coin, with an OnCollision method), they will move towards the player. \$\endgroup\$ – John Hamilton May 12 '17 at 12:20
1
\$\begingroup\$

You could simply check the distance of the coin to the player, however, you would need to store a record of each coin and iterate through each instance during each Update() method, in order to check.

We will assume you have a static number of coins, and have pre-loaded them into an array. This is the most cost effective, in comparison to using a List. If you dynamically add coins to the level, you will have to use a List<MoveCounTowardsPlayer>, and add the coins to the list as they are created.

class MoveCoinTowardsPlayer : MonoBehaviour
{
    public Transform target;
    public float speed;
    public bool isMoving = false;

    void Update()
    {
        if(isMoving)
        {
            transform.position = Vector3
                .MoveTowards(transform.position, target.position, speed * Time.deltaTime;
        }
    }

    public void MoveToPlayer(Transform player)
    {
        target = player;
        isMoving = true;
    }
}

class Player : MonoBehaviour
{
    ///<summary>The array of coins available in the level.</summary>
    public MoveCoinTowardsPlayer[] coin;
    ///<summary>The range within which the player will pick up coins.</summary>
    public float pickupRange;

    void Update()
    {
        for(int i = 0; i < coin.Length; i++)
        {
            if(coin[i] != null && Vector3
                .Distance(transform.position, coin[i].transform.position) <= pickupRange)
            {
                // If the coin still references a valid object, and its distance to 
                // the player transform is within pickup range, 
                // start moving it towards the player.
                coin[i].MoveToPlayer(transform);
            }
        }
    }        
}

All in all, the above solution seems like a waste of resources, given that it iterates through all coins during a single update. I would personally add a kinematic sphere collider (circle, if your working in 2D). You can make this collider the size of your pickup radius, and use collision to determine collection.

You would also need a collider on the coins, as well as a tag to identify them as coins.

class Player : MonoBehaviour
{
    public string coinTag;

    void OnTriggerEnter(Collider other)
    {
        if(other.tag == coinTag)
        {
            other.gameObject.GetComponent<MoveCoinTowardsPlayer>()
                .MoveToPlayer(transform);
        }
    }
}
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ You're last solution is the better IMO, but you'd need to change it to OnTriggerStay. Currently they'll only move towards enemies the first frame the contact the trigger. \$\endgroup\$ – Zebraman May 12 '17 at 14:21
  • \$\begingroup\$ @Zebraman, much like the first, the second example should "turn on" the move towards. From then on, its handled by the Update method. \$\endgroup\$ – Gnemlock May 12 '17 at 22:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.