Adding collectible lemons
Published 6 months ago
Use a 3D Lemon for John to collect
Hi, today we will add a new feature to the game, we will import a new 3D model in the game, and use that as a collectible item for John to pickup.
The item I prepared can be found here on my SketchFab here. This lemon is a retopology of another lemon I also found on SketchFab. You can download the model from the link or you can use your own model.
Now that you have a model we can import it in Unity. Create a Collectibles folder below the Model folder and import the lemon.obj file. You can drag and drop it or use the Right Mouse button menu following the Import New Asset option.
Once you have imported the model, you will notice that it will be grey. Select the model and navigate to the Materials tab in the inspector.
The model has 1 material exported called "defaultMat". We need to create a Material to use with these model. Create a new folder Collectibles inside the Materials folder. Then use the Right mouse button menu to create a new Material called Lemon.
The material is looking greyish and not very lemony. If you have downloaded my lemon, you will get two textures with it.
  • diffuse.png - A diffuse texture outlines the base colors for the mesh. In the lemon case, it is mostly yellow with a bit of green
  • normal2.png - A normal map texture defines the bumpiness of an object. It gives the object a sense of high finish without needing triangles (The bumps you see on the model are not created by triangles but by light reflection). A normal map will alter how the lights reflects on the object, creating bumps.
Create a new Collectibles folder inside Textures and import these two textures. Rename them as well so we can find them easily later.
The textures are called "Lemon_diffuse" and "Lemon_normal". Select the Lemon_normal and, in the inspector change the Texture Type to "Normal map"
Go back to the Lemon material and assign these two textures to Albedo and Normal Map. To do so, select the material and look into the inspector
Click on the Albedo highlighted button to open a selector, type lemon in the search box and select the diffuse texture. Click on the Normal Map highlighted button top open a selector, type lemon in the search box and select the normal map texture.
Go back to the Lemon model, and assign this material to it. After selecting the material remember to click on the Apply button. Your model should now look like this
You can now drag and drop the lemon model in the scene view, and you should immediately notice something...
It's massively huge. This is an issue that can happen if you do something with the wrong scale or you are using model from different sources. If you go to the Model Main Tab in the Inspector you will find a Scale Factor property. Change that to 0.1 and click apply.
You should see the lemon shrinking to an acceptable size
Now we have a model, we can create a Prefab for it. Drag the lemon object from the Hierarchy to the onto the Prefab folder into the Project View
Now we have a prefab, which means that every changes to it will be reflected to any other instance of the prefab. The first thing we are going to do is to make the lemon collectible, so when John walks over it, the lemon will disappear and John lemon's count will go up 1. Collision between game objects in the John Lemon project has been mostly handled by using the John Lemon object and dragging and dropping it in the various prefab. We are going to use a different method. We are going to create a new Layer and assign the Collectible to that layer. Then in the collision we are going to check if the object we collided with is in that layer. We create a new Layer by selecting the lemon gameobject and, in the inspector click on the Layer dropdown and select Add new layer
Add a new layer called Collectibles
Select the lemon gameobject again and set the layer to the new one we created
The Layer word is bold because it changed the current gameobject but not the prefab. Open the Overrides dropdown and click the Apply All button to apply all changes to the Prefab. This happened because we worked on a gameobject instance of a prefab instead that on the prefab itself. From now on we will work on the Prefab, to open the Prefab view, you can double click on the Prefab from the Project View, or click the small arrow next to the lemon gameobject in the Hierarchy.
Let's discuss what we need to add to our lemon prefab
  • We need a trigger collider to allow the player to collect the object
  • We need a cool visual effect to make it more appealing for the player to collect
  • We need a sound effect for the item so the player know that a lemon is close
  • We need a sound effect for when the item is collected
  • We need a visual effect for when the item is collected
Even a simple collectible object can be serious challenge if it needs to be appealing to the player. We could just add the trigger collider and let the object collect it, but would you collect something that is not appealing? I'm sure anyone wouldn't.
Enter Prefab mode for the lemon and add a sphere collider, set the radius to 0.25 and set the IsTrigger checkbox.
For the visual effect, something simple yet effective, we will have a yellow blurry circle image with some particles going towards the ceiling. This is the circle image I use
Import it into Unity and set the Texture Type to Sprite

Now create a new empty gameobject below the Lemon prefab and assign the effect-1 sprite to it. Rotate it 90 degrees on the X axis, set the scale to 0.5 on each axis and move it at the base of the lemon.
Now for the particle effect, you can notice that I have already created it, so I will show you the settings I have and the results, but you can play with it and have an effect that is of your liking
To make the prefab feel more alive we add a Point Light below the lemon. Create a Point Light from the menu. Set the range to 0.5 and move it below the lemon. Set the color to a bright yellow and the Intensity to 5. Remember to enable light in the prefab window to see the effect.
Last thing for the appereance we add a small animation. We can make the lemon slowly rotate. In the project window, in the Animation folder, there are two other folders, Animation and Animators. In the Animation folder we create an animation: "Lemon@Idle" and set its Loop Time property. In the Animators folder we create a new Animator: Lemon.
Now double click on the animator, to open the animator window. Drag and drop the Lemon@Idle animation into it to create it as a default state. We don't need to do anything else on the animator.
Select the lemon prefab and add a new Animator component. In the controller property select the new Lemon animator
Open the Animation window (not Animator). I usually have it as a Tab where the Project and Console windows are. (You can see it in the previous image)
This window allow you to create keyframes for your animation. If you have a gameobject with an animator selected, a dropdown in the top left will show you the list of animation for that game object. In our case you should only see "Lemon@Idle".
With this window we can click record and then move the object to animate it. This is how we do it.
In the previous image we added the keyframes for the rotation, not on the entire gameobject but just the gameobject that contains the mesh. That is because we only want to rotate the mesh. The animation at this point will probably feel wrong and too fast. We can slow it down by editing the Samples property in the Animation window. Move it down to 10.
There is still something wrong with the animation. The reason why is because by default Unity creates an interpolation with an ease-in ease-out between two keyframes. If you open the Curves panel in the Animation window (at the bottom) you will be presented with something like this:
This window needs specific commands to be navigated properly. You can edit the zoom of each axis by using the Mouse Wheel and a button from your keyboard. Use the Mouse Wheel with no button to zoom-in and out on every axis. CTRL will zoom-in and out on the X axis. SHIFT will zoom-in and out on the Y axis. Try to manage to get the same view I have to get confident with the View. When you are done, you can notice that the curve between the two keyframes is not linear, but we want it to. Open the Rotation property and select the Y property to focus the Curves View. To make it linear right click on the first key frame and select Both Tangents -> Linear, do the same for the other keyframe.
This should result in a smoother animation
We can now position the lemon in the world to see how it looks
I'm positioning the lemon near the entrance where John is, but, the light is not showing on the floor! This might happen because Unity will try to remove some lights, to tell Unity that this light needs to be rendered, select the light in the lemon and change the Render Mode to Important. Now the light should appear
We can also play the game to see how the particle effect looks with all the post processing.
We still have to add an Idle sounds, a Particle Effect for when we pick up the lemon and a Sound for when we pick up the Lemon. We will create the script to collect the object first.
We will create a new Script on John that will allow him to walk over the Collectibles and pick them up. To start with we will create three new scripts
  • JohnPickup.cs - This script will allow John to interact with The collectible objects
  • Pickupable.cs - This script will serve as base class for every pickup object
  • LemonPickupable.cs - This script will contain the specific Logic for the Lemon
We start with the Pickupable. This will be an abstract class, that extends from MonoBehaviour. The class will have an abstract method Pickup and a private BasePickup method. An abstract class in C# is a class that cannot be instantiated but, contains base logic for all the classes that inherit from it.
using UnityEngine; public abstract class Pickupable : MonoBehaviour { /// <summary> /// Classes that extends from this /// can specify their logic here. /// </summary> protected abstract void Pickup(); /// <summary> /// This function can be called from /// the player to pickup this object. /// </summary> public void PickupObject() { Pickup(); Destroy(gameObject); } }
Now the LemonPickupable will extend from Pickupable and will have an empty Pickup method for now.
public class LemonPickupable : Pickupable { protected override void Pickup() { } }
Last script is the JohnPickup. This script will keep track of the Lemons John currently has, and when we encounter one, will call the PickupObject function from it.
using UnityEngine; public class JohnPickup : MonoBehaviour { /// <summary> /// The number of lemons. /// </summary> int m_Lemons; /// <summary> /// The collectible layer. /// </summary> int m_CollectibleLayer; private void Start() { // Initialise the number of lemons to 0 m_Lemons = 0; // Initialise the layer using the name we gave it m_CollectibleLayer = LayerMask.NameToLayer("Collectible"); } // This is called when John enters ANY Trigger collider private void OnTriggerEnter(Collider other) { // If John touched an object in the Collectible layer if (other.gameObject.layer == m_CollectibleLayer) { // Get the LemonPickupable component on the game object we touched var pickupable = other.gameObject.GetComponent<LemonPickupable>(); if (pickupable != null) { // Call the PickupObject method pickupable.PickupObject(); // Increase the number of lemons John has m_Lemons++; } } } }
We can now drag the JohnPickup script on John and the LemonPickupable on the Lemon object.
Test it out, try to pickup the Lemon.
Since this tutorial is already very very long. We'll have another one for just adding the finishing touches to the Lemon (Particles, Sound and UI)
Thank for reading, if you still are!
Leave a comment if you like!
Pietro Carta
Developer - Programmer