Flying Pickups

OK so as the title suggests, my pickups when the game start have no sense of gravity. How do I get them to fall to the ground by default, but also avoid them from falling underground? Here’s what I tried doing:

  1. Added a Rigidbody to the pickup, but… it ended up falling through the ground
  2. Added ‘ForceReceiver.cs’, but… that needs a Character Controller

What else can I try?


Another side problem: I can paint on my terrain plants, but whatever I painted does not show up. How do I fix this? Here’s a screenshot of what I mean:

Plants

These plants (I painted them. In other words, they’re 3D Models populated on the terrain) show up on my scene view, but when I test my game, they don’t show up… How do I fix this, and get them to show up in my game as well? (The same problem goes for me trying to put my Resource Respawner Empty GameObjects as a way for me to populate my game world with choppable trees and mine-able rocks)

One topic two problems…

Are you talking about pickups spawned by the PickupSpawner or also about pickups dropped by enemies?

Assuming that this is an issue where it’s the spawned pickups… it can be tricky gluing the pickupSpawner to the terrain…

This trick should do it, assuming that on the Pickup itself, the bottom of the item is at 0,0,0

        private void SpawnPickup()
        {
            var spawnedPickup = item.SpawnPickup(RaycastToTerrain(), number);
            spawnedPickup.transform.SetParent(transform);
        }

        Vector3 RaycastToTerrain()
        {
            Ray ray = new Ray(transform.position + Vector3.up * 2, Vector3.down);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, 10, LayerMask.GetMask("Terrain"))) 
            {
                return hit.point;
            }
            else
            {
                return transform.position;
            }
        }

This performs a Raycast from above the PickupSpawner down to the ground, looking for the terrain.
For this to work, it’s important that objects like bridges, or anything else you can walk on be on the Terrain level.

I shall give the test code a run (let’s talk about it after the terrain issue), but for the moment regarding the terrain settings, this is what I have currently set up (I never changed it by the way). Is this enough, or shall I increase or decrease it?

Once again, whilst it shows up on my scene view when the game is not working, it never shows up in my game view (at least not in the game engine. Haven’t tested on a build as of yet)

AND… I have an unexpected bug with the terrain trying to divide by zero or something, before I even try anything… let me reverse my project a few steps for the moment (basically going to the plants section right now is a disaster)

The only other thing I can think of is that you may be exceeding Max Mesh Trees (currently set to 50). Try increasing that.
That’s the sum of my knowledge on Terrain… if it’s still not working, you’ll need to enquire with the forums on Unity.com

welp, time to head to both Unity and the GAIA Developers. I’m sure someone out there will know something…

I’ll post the question there and then return to test the rest of our scripts out :slight_smile:

honestly, I just realized it was both

The code you provided did fix the issue with the pickups that drop from the enemy (thank you :slight_smile:). The fix was done in ‘PickupSpawner.cs’, BUT… The stuff that spawns when the game starts is still airborne…

I’m guessing we shall copy paste the function elsewhere, but… where does it go? :sweat_smile:

The stuff that spawns when the game starts is PickupSpawner… RandomDropper drops the stuff that the Enemy drops (or you drop when you drag and drop an item) and it should snap to the NavMesh, which should not be airborn.

Pickup Spawner way up off the ground…


Pickup on the ground when game runs
(You can still see the PickupSpawner’s icon in the air, but look at the Pickup itself

Well… in this case then we still have the flying pickup problem. Items are airborne, still where they are placed in the game world, neglecting the terrain completely

if it helps, I placed the RaycastToTerrain() function you helped me with earlier in ‘PickupSpawner.cs’, so the function now looks as follows:

using UnityEngine;
using GameDevTV.Saving;
using RPG.Core;
using Newtonsoft.Json.Linq;

namespace GameDevTV.Inventories
{
    /// <summary>
    /// Spawns pickups that should exist on first load in a level. This
    /// automatically spawns the correct prefab for a given inventory item.
    /// </summary>
    public class PickupSpawner : MonoBehaviour, IJsonSaveable //, ISaveable
    {
        // CONFIG DATA
        [SerializeField] InventoryItem item = null;
        [SerializeField] int number = 1;

        // LIFECYCLE METHODS
        private void Awake()
        {
            // Spawn in Awake so can be destroyed by save system after.
            SpawnPickup();
        }

        // PUBLIC

        /// <summary>
        /// Returns the pickup spawned by this class if it exists.
        /// </summary>
        /// <returns>Returns null if the pickup has been collected.</returns>
        public Pickup GetPickup() 
        { 
            return GetComponentInChildren<Pickup>();
        }

        /// <summary>
        /// True if the pickup was collected.
        /// </summary>
        public bool isCollected() 
        { 
            return GetPickup() == null;
        }

        //PRIVATE

        private void SpawnPickup()
        {

            var spawnedPickup = item.SpawnPickup(RaycastToTerrain(), number);
            spawnedPickup.transform.SetParent(transform);

            // Ensuring only dropped loot disappears in-game, not in-game world items:
            if (spawnedPickup.TryGetComponent(out DestroyAfter destroyAfter)) {

                Destroy(destroyAfter);

            }

        }

        private Vector3 RaycastToTerrain() 
        {
            Ray ray = new Ray(transform.position + Vector3.up * 2, Vector3.down);
            RaycastHit hit;

            if (Physics.Raycast(ray, out hit, 10, LayerMask.GetMask("Terrain"))) 
            {
                return hit.point;
            }

            else return transform.position;
        }

        private void DestroyPickup()
        {
            if (GetPickup())
            {
                Destroy(GetPickup().gameObject);
            }
        }

        /* object ISaveable.CaptureState()
        {
            return isCollected();
        }

        void ISaveable.RestoreState(object state)
        {
            bool shouldBeCollected = (bool)state;

            if (shouldBeCollected && !isCollected())
            {
                DestroyPickup();
            }

            if (!shouldBeCollected && isCollected())
            {
                SpawnPickup();
            }
        } */

        public JToken CaptureAsJToken() {

            return JToken.FromObject(isCollected());

        }

        public void RestoreFromJToken(JToken state) {

            bool shouldBeCollected = state.ToObject<bool>();

            // Delete the if statement below if you want your items to always be available when you return to the game:
            if (shouldBeCollected && !isCollected()) {
                DestroyPickup();
            }

            if (!shouldBeCollected && isCollected()) {
                SpawnPickup();
            }
        }
    }
}

Anything else we should be changing to get this to work?

Open the pickup itself in Prefab mode. Make sure the object (the rendered mesh) is at 0,0,0

that was already the case… :sweat_smile:

Ok, then I’m lost… I gorilla tested this with the added script.

Ok, looking at what you’ve shown me… the SPAWNER… When you run the game, show me a picture of the PICKUP.


is this what we’re looking for? (by the way, the hatchet is still flying. I’m just using the hatchet as an example, but it applies to pretty much all of them)

And the terrain is tagged “Terrain”???
I’m baffled at this point.

One more trick to try… On the PickupSpawner:
Add a Sphere GameObject to the PickupSpawner with it’s location relative to the spawner of 0,.1f,0, and make the Sphere’s radius .1f.

Add this script to the Sphere

using UnityEngine;
public class DestroyOnAwake()
{
    void Awake()
    {
        Destroy(gameObject);
    }
}

Now position your PickupSpawner so that the sphere is just touching the terrain.

The Sphere itself will disappear when the game starts. The PickupSpawner will be on the terrain.

umm… the code is searching for the Layer Mask, so I believe that’s what needs to be assigned to “Terrain” :stuck_out_tongue: - by all means, I accidentally unset the Layer Mask last night, I apologize for the mess this has caused

However, there’s one new little problem. Some of these items are half-buried underneath the ground (I believe the ‘default pickup’ bags is the only one suffering in this case). This is just an issue of item placement, right?

and the second problem is, this algorithm does not consider for any potential points where the item may fall. In other words, if I have a bridge or something equivalent between the terrain and where the item initially starts falling from, it’ll pass right through the bridge, aiming directly for the terrain :sweat_smile:

Yes, just adjust each of the pickups in Prefab mode so that the model’s base rests at 0,0,0
A trick to help with that is to add a Quad to the Pickup at location 0,0,0, then move the model so it’s sitting correctly on the Quad (then delete the quad or put that DestroyOnAwake script on it.

already tried doing that… still, they are getting half-buried into the ground for some reason during gameplay

(the reason the y is set to 1.07 is because I wanted the bottom of the bag to lay on the ground)

Move the Coinbag, not the Pickup. The Pickup is going to be pushed to the ground, the Coinbag will go with it. The Pickup’s location will be overwritten by the Instantiate when it sets the transform. It could be at any random position in the world. It’s the model (the bag) that needs to be positioned within the pickup.

Privacy & Terms