Forum begins after the advertisement:


[Part 6] Magnet problem

Viewing 8 posts - 1 through 8 (of 8 total)
  • Author
    Posts
  • #12585
    g Dni
    Level 18
    Participant
    Helpful?
    Up
    0
    ::

    I have followed all the tutorials, but i still found the problem about magnet: the experience gem fly away when player change the direction.

    View post on imgur.com

    #12589
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    Hi g Dni,

    Update 13 December 2023: The code below doesn’t work. I’ve posted a new one below.

    This is something that I will address in a future part. In the meantime, you can apply these changes to the PlayerCollector.cs script to fix this:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PlayerCollector : MonoBehaviour
    {
        PlayerStats player;
        CircleCollider2D playerCollector;
        public float pullSpeed;
        Rigidbody rb;
    
        private void Start()
        {
            player = FindObjectOfType<PlayerStats>();
            playerCollector = GetComponent<CircleCollider2D>();
        }
    
        void Update()
        {
            playerCollector.radius = player.Magnet;
    
            List toRemove = new List<int>();
    
            if(rb) {
                //Vector2 pointing from the item to the player
                Vector2 forceDirection = (transform.position - attractedRigidbodies[i].transform.position).normalized;
                //Applies force to the item in the forceDirection with pullSpeed
                attractedRigidbodies[i].AddForce(forceDirection * pullSpeed);
            }
        }
    
        void OnTriggerEnter2D(Collider2D col)
        {
            //Check if the other game object has the ICollectible interface
            if (col.gameObject.TryGetComponent(out ICollectible collectible))
            {
                //Pulling animation
                //Gets the Rigidbody2D component on the item
                Rigidbody2D rb = col.gameObject.GetComponent<Rigidbody2D>();
    
                //Vector2 pointing from the item to the player
                Vector2 forceDirection = (transform.position - col.transform.position).normalized;
                //Applies force to the item in the forceDirection with pullSpeed
                rb.AddForce(forceDirection * pullSpeed);
    
                //If it does, call the OnCollect method
                collectible.Collect();
            }
        }
    }

    The issue with the script is that the force to move the collectible is not updated if you change directions. By moving it to Update(), it will cause the collectible to constantly update every frame, so it always tracks the player.

    #12630
    g Dni
    Level 18
    Participant
    Helpful?
    Up
    0
    ::

    There is problem cuz we haven’t declare the “col” variable in Update().

    Assets/Scripts/Player/PlayerCollector.cs(25,60): error CS0103: The name 'col' does not exist in the current context
    #12632
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    Hi g Dni,

    Update 14 December 2023: Unfortunately, the code below doesn’t work as well. An edited version is available further down below.

    You are right that the code doesn’t work because col is undefined in Update(). I have made some corrections to the code. Let me know if it works.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PlayerCollector : MonoBehaviour
    {
        PlayerStats player;
        CircleCollider2D playerCollector;
        public float pullSpeed;
        List<Rigidbody2D> attractedRigidbodies = new List<Rigidbody2D>();
    
        private void Start()
        {
            player = FindObjectOfType<PlayerStats>();
            playerCollector = GetComponent<CircleCollider2D>();
        }
    
        void Update()
        {
            playerCollector.radius = player.Magnet;
    
            List<int> toRemove = new List<int>();
    
            for(int i = 0; i < attractedRigidbodies.Count; i++)
            {
                // Before we start doing anything, we check for null values in our array, which
                // is caused by our GameObjects being deleted when they are collected.
                // We also have to call continue, otherwise attractedRigidbodies[i] being null can cause
                // NullReferenceException errors.
                if(attractedRigidbodies[i] == null)
                {
                    toRemove.Add(i);
                    continue;
                }
    
                //Vector2 pointing from the item to the player
                Vector2 forceDirection = (transform.position - attractedRigidbodies[i].transform.position).normalized;
                //Applies force to the item in the forceDirection with pullSpeed
                attractedRigidbodies[i].AddForce(forceDirection * pullSpeed);
            }
    
            // Remove all null objects in our attracted rigidbodies.
            foreach(int i in toRemove) attractedRigidbodies.RemoveAt(i);
        }
    
        void OnTriggerEnter2D(Collider2D col)
        {
            //Check if the other game object has the ICollectible interface
            if (col.gameObject.TryGetComponent(out ICollectible collectible))
            {
                //Pulling animation
                //Gets the Rigidbody2D component on the item
                Rigidbody2D rb = col.gameObject.GetComponent<Rigidbody2D>();
                // Adds the collected object's Rigidbody to our list, so we can pull it in Update().
                attractedRigidbodies.Add(col.gameObject.GetComponent<Rigidbody2D>());
                //Vector2 pointing from the item to the player
                Vector2 forceDirection = (transform.position - col.transform.position).normalized;
                //Applies force to the item in the forceDirection with pullSpeed
                rb.AddForce(forceDirection * pullSpeed);
    
                //If it does, call the OnCollect method
                collectible.Collect();
            }
        }
    }
    

    Here’s my explanation for the code: If we want the collector to be accurate, we will need to run the code on Update() though, so we will need to create the List attractedRigidbodies in the class to track all the objects that are currently being attracted. Every time we get in range to attract something, its rigidbody will be added to attractedRigidbodies.

    In Update(), we simply update the velocity of all attracted rigidbodies. We also need to remove all rigidbodies in the list that are null, beacuse after an object is collected, the GameObject gets destroyed, and we have to update the list accordly.

    #12638
    g Dni
    Level 18
    Participant
    Helpful?
    Up
    0
    ::

    Hi Terence,

    Thank u for replying. Unfortunately,it still have problems. When player walked close to the gem, experience increased but the gem never been destroyed. And the animation still missing.

    View post on imgur.com

    #12642
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    Let me test this out when I find some time and get back to you.

    #12652
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    g Dni,

    I’ve made a couple of fixes to the code after testing it and it works. There were a few syntax errors and an issue where the pickup accelerated towards the player every frame. The changes are highlighted below.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PlayerCollector : MonoBehaviour
    {
        PlayerStats player;
        CircleCollider2D playerCollector;
        public float pullSpeed;
        List<Rigidbody2D> attractedRigidbodies = new List<Rigidbody2D>();
    
        private void Start()
        {
            player = FindObjectOfType<PlayerStats>();
            playerCollector = GetComponent<CircleCollider2D>();
        }
    
        void Update()
        {
            playerCollector.radius = player.Magnet;
    
            List<int> toRemove = new List<int>();
    
            for(int i = 0; i < attractedRigidbodies.Count; i++)
            {
                // Before we start doing anything, we check for null values in our array, which
                // is caused by our GameObjects being deleted when they are collected.
                // We also have to call continue, otherwise attractedRigidbodies[i] being null can cause
                // NullReferenceException errors.
                if(attractedRigidbodies[i] == null)
                {
                    //toRemove.Add(i);
                    continue;
                }
    
                //Vector2 pointing from the item to the player
                Vector2 forceDirection = (transform.position - attractedRigidbodies[i].transform.position).normalized;
                //Applies force to the item in the forceDirection with pullSpeed
                attractedRigidbodies[i].AddForce(forceDirection * pullSpeed);
            }
    
            // Remove all null objects in our attracted rigidbodies.
            //foreach(int i in toRemove) attractedRigidbodies.RemoveAt(i);
            attractedRigidbodies.Clear();
        }
    
        void OnTriggerEnter2D(Collider2D col)
        {
            //Check if the other game object has the ICollectible interface
            if (col.gameObject.TryGetComponent(out ICollectible collectible))
            {
                //Pulling animation
                // Adds the collected object's Rigidbody to our list, so we can pull it in Update().
                attractedRigidbodies.Add(col.gameObject.GetComponent<Rigidbody2D>());
    
                //If it does, call the OnCollect method
                collectible.Collect();
            }
        }
    }

    Can you try this again and see if it works?

    #13199
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    Found another problem with the code:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PlayerCollector : MonoBehaviour
    {
        PlayerStats player;
        CircleCollider2D playerCollector;
        public float pullSpeed;
        List<Rigidbody2D> attractedRigidbodies = new List<Rigidbody2D>();
    
        private void Start()
        {
            player = FindObjectOfType<PlayerStats>();
            playerCollector = GetComponent<CircleCollider2D>();
        }
    
        void Update()
        {
            playerCollector.radius = player.Magnet;
    
            List<int> toRemove = new List<int>();
    
            for(int i = 0; i < attractedRigidbodies.Count; i++)
            {
                // Before we start doing anything, we check for null values in our array, which
                // is caused by our GameObjects being deleted when they are collected.
                // We also have to call continue, otherwise attractedRigidbodies[i] being null can cause
                // NullReferenceException errors.
                if(attractedRigidbodies[i] == null)
                {
                    //toRemove.Add(i);
                    continue;
                }
    
                //Vector2 pointing from the item to the player
                Vector2 forceDirection = (transform.position - attractedRigidbodies[i].transform.position).normalized;
                //Applies force to the item in the forceDirection with pullSpeed
                attractedRigidbodies[i].AddForce(forceDirection * pullSpeed);
                attractedRigidbodies[i].velocity = forceDirection * pullSpeed;
            }
    
            // Remove all null objects in our attracted rigidbodies.
            //foreach(int i in toRemove) attractedRigidbodies.RemoveAt(i);
            attractedRigidbodies.Clear();
        }
    
        void OnTriggerEnter2D(Collider2D col)
        {
            //Check if the other game object has the ICollectible interface
            if (col.gameObject.TryGetComponent(out ICollectible collectible))
            {
                //Pulling animation
                // Adds the collected object's Rigidbody to our list, so we can pull it in Update().
                attractedRigidbodies.Add(col.gameObject.GetComponent<Rigidbody2D>());
    
                //If it does, call the OnCollect method
                collectible.Collect();
            }
        }
    }
Viewing 8 posts - 1 through 8 (of 8 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: