When developing a game for mobile, it is beneficial to be able to test input on the computer before deploying to the mobile device. In the case of testing a single tap on the screen, the OnMouseDown function will work as a single tap on the mobile device.
In this way, you can test single taps on the computer through mouse clicks, and it will still work once it's deployed. For more complex touch inputs such as multi-finger and dragging, you'll want to use the Input.GetTouch functions.
Sunday, March 18, 2018
Saturday, July 8, 2017
Gaming Textures for Models
Adding textures for models is an important technique for adding a lot of detail to an object without using a lot of polygons. See my blog entry for how to achieve this in Blender: Texturing for Gaming Models
Static UI
Some basics with using UI in Unity 5. To get a static (non-interactive) UI element, go to GameObject > UI and either select Text or Raw Image.
Final note, if referencing these objects within code make sure you have the header:
using UnityEngine.UI;
Adding one of these will automatically create a Canvas and an EventSystem. For static purposes these two game objects can be ignored. Note that the order at which the child objects appear will dictate what is "in front" of what in the view. In this case CountBackground is behind the Text.
Final note, if referencing these objects within code make sure you have the header:
using UnityEngine.UI;
Global vs Local
There are times when it is beneficial to work either in what is referred to as Local or Global space. This manifests itself in a few places. In the editor, you may have seen these buttons. They toggle where the center point of an object is [Center/Pivot], and the transform reference [Local/Global]
As an example of the distinction, Center will place the transform marker at the average center of the object including the shape of its children. To the contrary, the Pivot will place the center at what I would call the "center reference" as defined in the original model.
In the same way Local and Global refer to the reference in space for the transform. This can be most easily seen in the available transform functions.
- eulerAngles/localEulerAngles
- position/localPosition
- rotation/localRotation
- scale/localScale
Specifically with child objects, using one or the other makes a significant difference in behavior. Making changes to the global transform of a child object will control it irrespective of what the parent is doing whereas local changes are relative to what the parent is doing.
List of Collided
As far as I can tell Unity doesn't have a mechanism natively that tells you all the objects that are currently collided (triggered) in your collider. The most common approach seems to be managing the list on your own using the OnTriggerEnter and OnTriggerExit:
void OnTriggerEnter(Collider other)
{
if (other.tag == "enemy")
{
allCollisions.Add(other.gameObject);
}
}
void OnTriggerExit(Collider other)
{
if (other.tag == "enemy")
{
allCollisions.Remove(other.gameObject);
}
}
One extra point to note, that this approach breaks down if your objects are "exiting" because they are destroyed. In my case, I wanted to destroy the entire list of objects via an event. At first I used List.Clear(), however I found that this only nulls all the elements, but doesn't actually clear the elements. Better was to blow away the list with a new instance.
if (Input.GetButtonDown("Fire1"))
{
foreach (GameObject enemy in allCollisions)
{
SeekToKill newBullet = (SeekToKill)Instantiate(bullet, bulletStart.transform.position, bulletStart.transform.rotation);
newBullet.SetTarget(deadbug);
}
// clear list including indicies
allCollisions = new List<GameObject>();
}
void OnTriggerEnter(Collider other)
{
if (other.tag == "enemy")
{
allCollisions.Add(other.gameObject);
}
}
void OnTriggerExit(Collider other)
{
if (other.tag == "enemy")
{
allCollisions.Remove(other.gameObject);
}
}
One extra point to note, that this approach breaks down if your objects are "exiting" because they are destroyed. In my case, I wanted to destroy the entire list of objects via an event. At first I used List.Clear(), however I found that this only nulls all the elements, but doesn't actually clear the elements. Better was to blow away the list with a new instance.
if (Input.GetButtonDown("Fire1"))
{
foreach (GameObject enemy in allCollisions)
{
SeekToKill newBullet = (SeekToKill)Instantiate(bullet, bulletStart.transform.position, bulletStart.transform.rotation);
newBullet.SetTarget(deadbug);
}
// clear list including indicies
allCollisions = new List<GameObject>();
}
OnTriggerEnter Re-entrance
This is more of a lessons-learned while developing a game, and I'm creating a post as a reminder for myself. In this scenario I was using the OnTriggerEnter function to determine when the object would be destroyed.
The issue I was running into was that in some rare cases, multiple objects would trigger this function simultaneously, causing this function to call multiple times before the object was actually destroyed.
Adding a class flag solved my issue, in my case I called it isDead:
private void OnTriggerEnter(Collider other)
{
if (other.tag == "Bullet" && !isDead)
{
Destroy(this.gameObject);
system.UpdateBugCount(-1);
isDead = true;
}
}
The flag prevents re-executing the function after the object should technically be destroyed.
The issue I was running into was that in some rare cases, multiple objects would trigger this function simultaneously, causing this function to call multiple times before the object was actually destroyed.
Adding a class flag solved my issue, in my case I called it isDead:
private void OnTriggerEnter(Collider other)
{
if (other.tag == "Bullet" && !isDead)
{
Destroy(this.gameObject);
system.UpdateBugCount(-1);
isDead = true;
}
}
The flag prevents re-executing the function after the object should technically be destroyed.
Multi-Player Input
In a multiplayer scenario, at times it is beneficial to distinguish between different input designations and assign them specifically to a player. In this case, I had a game where one player controlled the vehicle and another player controlled the gun turret on the back. In this scenario, I needed certain input to be dedicated to a specific player.
To do this in Unity for an Axis Input, set the Joy Num field to a specific player.
For a Button Input, add the term "joystick #" in the button field rather than just stating "joystick". Using just "joystick" actually allows all controllers to trigger that input.
Unity Asset Store
The Unity Asset Store is a great place to get useful assets for your game. Some are free, and many are well worth the money. As an example, I bought a Skybox package because I don't want to go through the trouble of making skyboxes, and I also love the Detonator Explosion Framework.
To get to the store click Window > Asset Store, or as shown the shortcut key is [CTRL + 9].
Detonator Explosion Framework
The Detonator Explosion Framework is an excellent free package that can be acquired through the Asset Store. It does have some quarks to get it to work with Unity 5, and the following is what I've observed needed to be done to get the Tiny Detonator to work.
Saturday, December 17, 2016
Control an Animation Transition
This post covers transitioning an animation with a software event. This post builds upon Importing an Animation into Unity. The example below is based on having imported a model from Blender that already has two animations embedded in it (swim and idle).
This post will show how to setup a transition condition, and how to trigger it in code.
Looking first at the Animator Controller view, you'll see I've already added transitions between the Swim and Idle state.
Import Blender Animation
This post details how to get an animated model into Unity. This post is built on post on a different blog which can be found here (if using blender): Multiple Animations in Blender. Once you've created your model with built in animations, bring it into the Unity project. In this example my model is called "TestRig".
The first step is to add an Assets > Create > Animator Controller. When you double click on it, you'll see a node-editing type view.
Friday, December 16, 2016
Google Cardboard Input
Successfully setting up input for Google Cardboard has a lot to do with applying scripts to the right place. This post will cover what I've found to be the minimal set to get this working.
Please follow the setup steps in this Post as a prerequisite, as you'll need to have loaded the SDK package into your project, and added a GvrMain to your scene.
Please follow the setup steps in this Post as a prerequisite, as you'll need to have loaded the SDK package into your project, and added a GvrMain to your scene.
Setup the Scene
- On the GvrMain
- Add the GvrPointerManager script
- On the Main Camera under the GvrMain
- Add the GvrPointerPhysicRaycaster script
- Add a GvrReticlePointer prefab as a child of the Main Camera
- Add an EventSystem to the scene
- Remove the StandaloneInputModule script
- Add the GvrPointerInputModule
Tuesday, December 13, 2016
Adding Background Sound (or Music)
Adding background (ambient noise) or perhaps music to your scene is a simple of matter of adding an Audio Source to your Main Camera.
If you camera object does not already have an Audio Listener, then you will need to add one.
In this way the sound will always be prevalent instead of based on how far or near you are to the source.
If you camera object does not already have an Audio Listener, then you will need to add one.
In this way the sound will always be prevalent instead of based on how far or near you are to the source.
Add a Spatial Sound
Making use of the Google Cardboard SDK, you can add spatial sounds to your scene that react to head direction changes.
You can add a spatial sound in two ways:
You can add a spatial sound in two ways:
- Drag a GvrAudioSource prefab into your scene
- Add the GvrAudioSource script to your object
Ensure that your project settings have the Audio value of Spatializer Plugin set to the GVR Audio Spatializer.
Edit > Project Settings > Audio
You also may have to enable the GvrAudioListener script that resides on the GvrMain > Head > MainCamera game object. This is provided as a part of the prefab.
At this point, when you play your game, you should hear the sound (assuming the source is in range), and as you turn your head, you should hear the sound move accordingly.
Saturday, December 10, 2016
Google Cardboard Integration
Integration with Google Cardboard was not trivial, and I ran into several hiccups, but here is the process of getting Google Cardboard building and deployed with Unity (5.5.0f3)
- First install the Android Studio to get the Android SDK on your computer
- Next, download the Google VR SDK for Unity
- Create a new Unity Project
- Assets > Import Package > Custom Package
- Navigate to where you downloaded the Google VR SDK, select package
- Deselect the following
- Google VR > Demos
- Plugins > Android > gvr-permissionsupport-release.aar
- Plugins > iOS
- Click Import button
- Go Ahead with "API Update Required"
- There is at least one script with a compilation error
- Find the script error in the console, or just open GvrVideoPlayerTexture.cs
- Line 595 - add a "yield" before the "return false;"
- Allow extra import packages to be loaded "GVRBackwardsCompatibility"
- Delete the Main Camera
- Add a GvrMain prefab to your scene (this is your VR camera)
- Add other elements to your scene as desired
- File > Build Settings
- Select Android
- Player Settings > Identification > Bundle Identifier (update this field)
- Build
- When asked about Android 6.0 Platform requirements, click Continue
- If it complains about "Merging Android Manifests", you'll need to find the gvr-permissionsupport-release.aar file and manually delete it.
Friday, December 9, 2016
Debug and Deploy to Android
I'm excited that Unity's business model changed and now it is free to deploy to Android.
They have some very good Setup Instructions for debugging and deploying.
Some things to note:
They have some very good Setup Instructions for debugging and deploying.
Some things to note:
- In installing the Android Studio, my SDK was installing here:
- C:\Users\**username**\AppData\Local\Android\android-sdk
- Create a new project
- Make sure to set the Bundle Identifier in:
- Update Player Settings > Other Settings > Bundle Identifier
If you want to Debug with your device, ensure it is connected via USB and click Build & Run.
If you want to deploy your game, just click Build. This will produce an APK file which you can transfer to your device.
On your device, find the file in a file browser, select it, and when Android asks you if you want to install, say yes. The game will launch and a generic icon will be added to your apps list.
Saturday, February 6, 2016
MonoDevelop WhiteSpace
White space drives me nuts in an IDE. Here is how to set the whitespace in Mono:
To change it for all future instances of projects go to Tools > Options and set the fields below.
To change the whitespace for the current project (if the prior step hasn't been done), go to Project > Solution Options, and set the following fields.
If you want to apply those changes to open files you can go to: Edit > Format > Format Document, and it should apply the changes to the current document.
To change it for all future instances of projects go to Tools > Options and set the fields below.
To change the whitespace for the current project (if the prior step hasn't been done), go to Project > Solution Options, and set the following fields.
If you want to apply those changes to open files you can go to: Edit > Format > Format Document, and it should apply the changes to the current document.
Delegates or Callbacks
Here is an example for using Delegates to achieve a callback capability.
In the class that is going to call the callback function:
public class PointBasketManager : MonoBehaviour
{
public delegate void GameOverEvent ();
private GameOverEvent game_over;
public void SetGameOverCallback (GameOverEvent newCallback)
{
game_over = newCallback;
}
public void BasketTriggered (uint points)
{
// trigger game is over
game_over ();
}
}
The using class calls the function SetGameOverCallback() and passes in the function that should be called when game_over() is called.
public class GameSystem : MonoBehaviour
{
void Start()
{
point_mgr.SetGameOverCallback(OnGameEnd);
}
public void OnGameEnd ()
{
// end game stuff
}
}
In the class that is going to call the callback function:
public class PointBasketManager : MonoBehaviour
{
public delegate void GameOverEvent ();
private GameOverEvent game_over;
public void SetGameOverCallback (GameOverEvent newCallback)
{
game_over = newCallback;
}
public void BasketTriggered (uint points)
{
// trigger game is over
game_over ();
}
}
The using class calls the function SetGameOverCallback() and passes in the function that should be called when game_over() is called.
public class GameSystem : MonoBehaviour
{
void Start()
{
point_mgr.SetGameOverCallback(OnGameEnd);
}
public void OnGameEnd ()
{
// end game stuff
}
}
Quick Prefab Creation
- Create the object in the scene (Hierarchy)
- Modify all desired attributes and components
- Drag the game object from the Hierarchy view to the Project view
Friday, February 5, 2016
Add Bounce
To add bounce to an object, first you need to create a Physic Material, and this can be done in the Assets > Create > Physic Material menu. Note that upon creation, you should name the material.
Attach the material to the Collider component on your game object.
Subscribe to:
Posts (Atom)