Categories and Tags


For tag: 'Unity'

Unity: Simple state-save for pick-up objects in games

Sunday, December 14th, 2008

Now that I’m working with Unity full-time, I’m having a lot of fun learning the system, and it’s pros and cons. I’m still unsure of the best strategy to do big save-games, but I’m not too worried about that for my first game. But I want to make save/load data easy to use when building levels.

Unity’s PlayerPrefs allows you to save and load data using name/value pairs. It’s pretty general and reminds me of Director’s SetPrefs (Did Tom help them design this feature? :) ). One thing I have not been able to figure out though, is how to get a unique ID for a gameObject that I can turn into a name for PlayerPrefs. Let me walk you through an example:

You have a health pickup prefab, and it’s name is “HealthPrefab”. These prefabs are scattered throughout the level. When you pick them up, you want them to stay picked up, even if you leave the level and come back. This can be done with playerPrefs, but because you have multiple instances of the health prefab in the level, you need a unique name for each one.

This could be done by assigning a name to every instance of the prefab using the inspector, but this is time-consuming for the designer, and error-prone.

It can’t be done with GetInstanceID because while this number is unique per object, it changes every time you load the level.

The best solution I have come up with so far is to generate a unique name based on the position of the object in the scene. Here’s how I do it:

Object name + Scene name + Transform x + y + z

With this code, you can add prefabs to your level at your leisure without having to name them uniquely, and they’ll just work.

I actually use integers of X Y and Z to make the name shorter, and this just means you have to make sure your pickups are at least 1 unit away from each other. For most games this should not be a problem, but if it is, just modify the name-generator to use higher-res values. In my game, the name-generator is a static function that every object calls, but in my script here I stuck it in the same script. I’d love to know what people think of this, and if anyone knows of a better way to do this, let me know!

// Simple Pickup code -- .js -- for Unity

private var savename  = "";

function Start ()
{
savename = savename(this.gameObject, "pickup");  // Generate a Unique Savename.
if (PlayerPrefs.GetInt(savename,1) == 0 )
{Destroy(this.gameObject); }
}


function OnTriggerEnter (hitby : Collider)
{

{// Put some code here to check to see if the item that triggered you can pick you up

PlayerPrefs.SetInt(savename, 0);
Destroy(this.gameObject);
// do some "you picked me up!" sound effects, etc
        }

static function savename (object : GameObject, ilabel : String)
{ // Call this to get your unique save name!
// this builds a unique savename by stringing together the object's level name, X, Y, and Z locs (interegers of), and a prefix that is defined
// by the object itself. The idea is that this is a uniqueish enough key for saving the status of an in-game object.
// Ideally this function is a master function somewhere, rather than in every type of pick-up script you have.

return ilabel + "." + Application.loadedLevelName + "." + parseInt(object.transform.position.x) + "." + parseInt(object.transform.position.y) + "." + parseInt(object.transform.position.z); // this makes a unique name for this object. Kinda.
}

Simple 3rd Person Camera Controller in Unity

Thursday, November 27th, 2008

Someone in the Unity Forums asked for help with a 3rd person camera controller. I decided to post my code there for him/her, and so I’m going to post it here, too. This is a javascript that will track an object in the world and move the camera towards it if the object gets too far away.

I like code examples that are simple and easy to read, and while this code could be even more stripped down, it’s pretty simple. I included comments for every line.

// Put this script on a GameObject with your camera and a character controller on it.

var target: GameObject;  // Assign this to your player
var maxDist = 20.0; // distance before triggering follow
var minDist = 10.0; // distance before untriggering follow
var speed = 6.0;  // Should be set to the same speed as your character
private var acc = 0.0; // Amount of movement on the camera. this starts at 0 and builds until it reaches speed.

function LateUpdate () // Had to be late update becuase it was studdering otherwise.
{
var myDist = 0; // This variable is a (changing) threshhold to determine whether or not our camera should be moving or not.
// when the camera is not moving (acc==0), it is asigned to maxDist.
// Once the camera starts moving, we set myDist to minDist. This means the camera needs to get even CLOSER to the player before it stops
// moving than it took to trigger it in the first place. this behavior does 2 things:
// When the camera is stopped, it lets the character walk around a bit before the cam starts to move.
// When the camera is moving, it prevents studdering as the character walks in-and-out of threshold.

if (acc == 0) // If the camera is not moving
{
myDist = maxDist; // Set our threshhold to Max
}
else // else the camera IS moving
{
myDist = minDist; // set threshold to min
}
transform.LookAt(target.transform);  // Aim at the character

var idist = Vector3.Distance(transform.position, target.transform.position); // Get distance between the cam and the player

if (idist > myDist) // If distance beyond our current threshold
{
acc = Mathf.Min(acc + 2, speed); // accelerate by a fixed amount (+2) until we're at max speed (speed)
}
else  // Else the distance is inside our threshold
{
acc = Mathf.Max(acc - 2, 0);  // deacclerate by (-2) until we're at stopped (0).
}

if (acc > 0) // If we're moving
{
    //transform.Translate(0, 0,  acc * Time.deltaTime); // Old way without collision;

//--VV-- This turns the local angle into a world coord that can be passed to the Move command
var iangle = transform.TransformDirection(Vector3(0,0, acc * Time.deltaTime));
//--AA--
var controller : CharacterController = GetComponent(CharacterController); // Get controller
var flags = controller.Move(iangle);// Move with collision but without gravity.
}
}

Creating elevators in Unity

Monday, November 17th, 2008

Unity’s Character Controller is an example of what makes Unity great. It’s a part of Unity’s engine that is specifically designed for creating moving characters in video games. It has built-in support handling slopes, walls, and steps, all rolled into a single component so that you don’t have to (re)write this for every game, like you would in most general purpose 3d engines. But all that built-in functionality comes at a price: if you want to make your character do something that the built-in stuff doesn’t support, then you gotta roll it yourself. Still, it’s better than having to roll everything yourself.

One of the limitations of the Character Controller is that it does not support elevators and moving platforms very well. The Character Controller will work fine with platforms when they’re not moving, but if they are moving, the character controller will not stick to them. This was the first real shortcoming I’ve run into while using Unity, so it was really my first hurdle I had to jump. After a bit of Googling around I confirmed that it indeed was a shortcoming of the Character Controller. Some suggested workarounds, but I couldn’t find a good solution with code snippets posted anywhere. In one of the posts I found about it, someone suggested building platforms with triggers above them that would parent the object to the elevator itself.

I liked the idea of using parenting, but I wanted a solution that was built into my character itself, and didn’t require triggers placed above surfaces on the elevators themselves. So I wrote one.

My Elevator Solution


Note: As I’m just getting started with Unity, I’m attaching code snippets here that should be complete, but I may have left out variable declarations. I stripped out all the unrelated code to make reading this example easier.

This solution is part of a script that you’d attach to your character GameObject. Your character should have a character controller attached to it. The code will parent itself to any object it touches that has the tag “elevator” on it. It will unattach itself when you move off of it. You don’t need to add a trigger to your elevator; you just need to make sure it has a non-trigger collider on it. I’ve used a bit of code taken from the Unity docs to check to see if the object is below the character, so that it won’t attach itself if it bumps into the sides of elevators and whatnot, but that shouldn’t be a big problem anyway if your character has gravity applied to it.

How to implement it
The heart of it is two functions: one is the OnControllerColliderHit function, and one that should be called immediately after every Move you make with your character.

Declare these at top of your script:
private var onelevator = 0; // this st used to keep track of whether or not you're parented to the elevator
private var touchingelevator = 0; // this is a flag used to determine whether or not you're actually touching the elevator (regardless of parented state).

Here’s the code to call whenever you move a character:

touchingelevator = 0; // Set this to zero before EVERY character controller Move() you make.
var charcon = GetComponent(CharacterController); // You don't need to do it this way; it's just the way I tend to do it
var flags = charcon.Move(moveDirection * Time.deltaTime); // Here's your character Move()
postMoveCheck();  // call this after EVERY Move() you make.

Here’s functions you need to include in the script:

function OnControllerColliderHit (hit : ControllerColliderHit)
{// This function gets called every time your character collides with an object, before Move() returns.
//We use this to check to see if we're touching the elevator.
var body : Rigidbody = hit.collider.attachedRigidbody;
  if (hit.moveDirection.y > -0.3)
return;
if (hit.gameObject.tag != "elevator")
return;

// At this point we know we're sitting on top of an elevator. :) 
      touchingelevator = 1;  // This is used to track whether or not we touched the elevator THIS UPDATE.
      // We do it this way because this function doesn't get called when we are not touching the elevator, and we need some
      // way to know that so that so we can unparent once we're not touching it anymore.

if (!onelevator)
{ // this moves the character into the elevator's hiearchy
// should only happen once, after collision.
transform.parent = hit.gameObject.transform;  // Make us a parent of the elevator. Nach.
        onelevator = 1;
}
}


function postMoveCheck ()
    {// This checks to see if we're on an elevator anymore, and if we aren't, we clear the parent.
    // Call this immediately after moving the character.
    if (!touchingelevator && onelevator)
    {
    transform.parent = null;
    onelevator = 0; // We're not on the elevator anymore! ;) 
    }
    }

Comments and suggestions are always welcome. Additionally, if you have a different solution to this problem, I’ve love to hear about it. Contact me or post in the comments below.

More Lightwave and Unity

Sunday, November 9th, 2008

Unity logo[see all of my Unity posts] I’m past the point of the Unity trial, and it was simple enough, powerful enough, and (most importantly) fun enough for me to buy it, with the goal of eventually making a commercial game with it. Although, for the time being, I’m just using it as hobby -- that is, using it for fun to learn it, as opposed to diving in and methodically developing a commercial game with it.

Importing models and animations from NewTek Lightwave 3D to Unity


I’ve been using LightWave 3D version 9.3.1 for all my modeling, and so far it’s been going fine -- with one little problem: the models import into Unity rotated so that the object is laying on it’s side. It’s odd because when the model is dragged into the scene, it appears right side up, but Unity sets the object’s rotation to 270,270,0 -- as if Unity knows the object is rotated incorrectly, and fixes it for me (I assume that in a normal situation, an object with rotation set to 0,0,0 should appear right-side-up in the world). It all seems like a minor detail until I went to use something like LookAt to point the object towards a destination, and the object returns to it’s un-normal sideways position.

The solution was to create an empty game object that the object is a child of, set the Parent to [0,0,0], and fix the child’s rotation [270,270,0]. It means all the scripts get attached to the parent GameObject instead of the model itself, and that meant I had to rewrite all the little scripts I had written to target the child object. No big deal at this point, but I’m glad I discovered this early. I hadn’t noticed it earlier since all my scripting tests were done with primitives.

I have yet to see if you can use this same trick for objects (trees) in the Terrain engine. I wonder how much processing overhead there is in adding a GameObject to an object, esp. if it’s going to be mass-populated via the Terrain engine. I hope to have some more to report on soon.

Unity day 11: Terrain overview and Scripting

Tuesday, September 30th, 2008

Unity logoNOTE: If you’ve not seen my posts on testing out Unity, check them out here. It’s been a lot more than 11 days since I started my Unity test, but most of those days I didn’t get a chance to play around with it.

Executive Summary


Here’s my executive summary of my most recent Unity exploits.

Terrain: I’ve messed with the Terrain engine a bit and found it pretty easy to use. Feature-wise it’s a bit on the simple side; but overall I cannot imagine trying to build a game world solely in a 3D modeling tool, and this is much simpler and more interactive. It seems to feel a lot like the terrain in Oblivion (which is a good thing!).

Scripting: I also took a stab at scripting. So far I’ve been able to write my own 3rd person camera system (total time: one evening), a Diablo-style point-and-click character controller (total time: another one evening), and try my hand with Unity’s coroutines.

I found scripting to be pretty straightforward and it was easy to do just about everything I tried. The point-and-click character controller had me a bit daunted at first, but I was able to get it working in a single evening. The scripting reference came in pretty handy.

Coming from Director, coroutines are definitely the most exciting aspect of Unity scripting. It seems to simply all the problems of execute-over-time scripting without having to do complex case statements. I’ll try to explain more about this in a later blog post if anyone is interested.

More on terrain


After reading up on the terrain engine in Unity I got pretty excited, since it appears to handle large maps and vegetation built right in. In an evening I was able to create a height map in Photoshop based on a scan of an island I designed in a previous game, and import it into the editor. It took me several attempts to get it right, which is to be expected, since heightmaps are always trial-and-error process. a few things I learned: use 16bit-per-channel images for heightmaps, and blur the hell out of them, otherwise you’ll get major jaggies in your import and (on my wimpy G4) the terrain will grind to a halt. This makes me wonder how graceful it would scale -- the world seems to render quite nicely when it’s all smooth hills but after adding ridges and rough edges Unity appears to not LOD them as aggressively when they’re far away, which is why initial heightmap tests choked the framerate. Is it possible to make the terrain too detailed? From my initial tests I feel that it’s something that I could work around. I took a new approach. My strategy was to use the heightmap as a rough guide and fill in the details with Unity’s built in terrain editor. This seemed to work pretty well.

Unity’s terrain engine is impressive and automates a lot for you. It has built in tools for modifying land height, adding trees and grass, and texturing the terrain; not to mention rendering them with LODs, billboards, and clipping automatically. In some other engines, you’d need to write all this yourself, but you get it all for free in Unity. Of course that’s a double edged sword: the terrain editing tools, while acceptable, are pretty basic. For example, it’s very tricky to use the tools to build controlled sloped paths. I keep bouncing between pits and bumps when trying to create slopes. In one evening I felt like I had gotten a lot better at it though, and started to find some tricks for building terrain conducive to gameplay.

Current wishes


While overall I am quite excited about Unity’s performance in my tests, I do have my own set of wishes, which currently are:

More examples in the scripting reference: There’s still some things I’m trying to wrap my head around conceptually, and often times I use examples to help with that, but the Unity scripting reference is missing examples in some areas. I was able to find Scroll Wheel support in the documentation, but can’t actually figure out how to use it yet. There’s no example, and I’m still learning the ropes of Unity, and I was not able to get the syntax correct.

Script editor: The Unitron script editor that comes with Unity doesn’t work on my old PPC PC (but they’re aware of it) so I don’t get any color-coding, etc. On top of that, I’m not 100% sure there’s a way to do step-by-step debugging. I really have come to rely on having IDEs with built in editors that are “aware” of your project.

Capitalization: This is less of an issue with Unity as it is an issue with Javascript, but I really am frustrated with having case sensitive parsing, and the capitalization standards functions and classes use. I’m going to bitch about it because it causes a lot of stupid errors. It’s easy to remember names, but tricky to remember when they’re capitalized and when they’re not. “camera” isn’t. “ScreenPointToRay” is. But here’s the thing that irks me the most: it would be considered bad design to have an object named “Max” that did one thing, and an object named “max” that did something different, so why allow it? What I’d love to see is a script editor that automatically capitalizes, so I don’t have to.

Overall Game Techniques: I’m also interested in seeing high-level descriptions of how to do common game-related scripting architecture. I’m not looking for pre-written code; just concepts. I am sure some of this may be covered on the Unity site, but I’ve not found them yet. Topics I’ve love to see addressed:

  • Save Game/Load game: a quick writeup on how to crawl the hierarchy and save off gamedata for instantiation later. Techniques for making this scalable so that you’re not going back and changing the savegame code every time you change properties of the world.
  • Building large worlds: the terrain engine has built in support for clipping trees and grass, but what about all the other objects you want to stick in your world? Can you just add objects to your world without worrying about it? or are there tricks that need to be used?
  • Writing core functions: I want to write some functions that can be called from any script. How do I do that?

More to come soon …

Unity: Day 5

Wednesday, September 3rd, 2008

Unity logo I’ve now spent a few days with Unity (see my initial reactions here). I’m still only about 1/2 way through the Lerpz tutorial, but I have an update:

Unity Support


As I mentioned in my previous post, I had experienced a few crashes. Let me provide you on a few details about them. Every time Unity crashes, a simple Bug Report app fires up which encourages you to submit a bug. The app is so easy to use, I’ve filed bug reports every time the app crashed on me. I’m happy to report that every bug I submitted was replied to by a Unity representative. In both cases, I was able to narrow down the crashing to two known bugs that Unity is aware of. Additionally, both bugs are pretty easy to work around.

While crash bugs are never welcome, it’s nice to know that the bug reports didn’t fall into a black hole, and that the developers were aware of them.

Unity and Lightwave: first results


One of my biggest questions about Unity, not to mention every other 3d engine I’ve messed with, is how well does it play with Lightwave. Lightwave is a great modeler but not quite the industry standard, and I never had great success importing Lightwave scenes into Director, which ultimately kept me from ever using Director’s 3D capabilities for a project. When I started to test Unity, Tom Higgins (Unity Product Evangelist) told me it should work just fine, but I still like to qualify my tools via testing before truly sinking my teeth into them. The executive summary of my initial Lightwave testing is everything’s working great so far. Here’s a bit more detail, though:

Importing models from Lightwave into Unity

First off, I had to install the FBX exporter to Lightwave 9.3. Pretty straightforward, and it was covered in the Unity documentation. I loaded up a character from my previous game development follies, and exported him.

This is where I learned that the Lightwave FBX exporter requires all texturing to be done with the UV projection, as opposed to other projections. I normally don’t apply UVs when modeling in Lightwave since all my models are pretty basic, designed for pre-rendering, and using UVs in Modeler adds extra steps.

For this first test, I exported the model anyway. the FBX exporter still worked, it just left off the textures. Additionally, the FBX model froze the subdivision cages that the model had, and turned them into triangles. Pretty cool.

The model imported into Unity and showed up in the game world just fine, outside of it’s missing textures.

Importing animation from Lightwave to Unity

My next test was to import a walk cycle from Lightwave and see how it showed up in Unity. I exported a character with a bone-enabled walk cycle to FBX and pulled it into Unity. Again, it worked great. Here I ran into a bit of short-lasting confusion: It appeared that with Lightwave models you only get one animation per model. After a bit of playing around I discovered the “Settings” button in the Project pane. In Settings it allows you to manually break the imported animation into pieces, specifying a name, beginning frame, ending frame, and whether or not it loops. So the process is to do all your character’s animations in a single timeline, export it, then break them up in Unity using the Settings panel. Once I figured that out, I was very happy.

Textures
I then soldiered forward and decided to import a model with proper UV maps. I quickly made a crate and textured it on all sides, and exported it. The import into Unity looked great.

To Do: animation with textures
So my next test will be to combine the above: import a character animation with textures and see if it looks right in Unity. At this point I feel like it’s just a formality, but I still want to make sure it all works during this trial process.

Hanford’s Unity FAQs


Here’s a running list of open questions I have about Unity. As I find the answers, I hope to update this.

Q: Does Unity have native SaveGame and LoadGame support or do you have to hand-roll this?

A: Unity has support for saving and loading data, but as far as tying that data to the state of the world, you’ll need to roll your own. Specifically, you’ll want to use the PlayerPrefs class which works both in standalone and Unity Web Player targets. (Source: blog comments).

Q: Does Unity have native PathFinding built into it’s terrain? If not, is it easy to implement given an A* routine?

A: No native pathfinding built in. It is possible to create your own, and there are third party implementations. Specifically, there’s an article in issue 1 of Unity Developer Magazine in how to do so, and a free A* implementation by Angry Ant. (Source: blog comments)

Q: How much support is there for permanently modifying a scene via scripting? Can I write my own level editor tools that change the Scene permanently?

A: Via scripting it’s possible to edit the scene realtime, and using this with a combination of saving the worldstate (like a saveGame script would do) would give you the results you’d want.

However, there’s also support for using Editor commands via scripting described in the Editor section of the Unity Manual. However, the strategy for using these classes to modify the scene is still unclear to me. (Source: blog comments)

Checking out Unity

Saturday, August 30th, 2008

Unity logoYesterday I dusted off my old G4 and set it up in order to mess around with Unity. Unity is a high-level 3d game creation engine that many ex-Director users have switched over to. Games made in Unity can play on Mac or Windows, but the authoring environment is Mac only.

I hope to be able to post my thoughts here on Unity as I explore it’s capabilities.

Day 1: Installing the trial


I downloaded and installed Unity 2.1, and immediately ran into a problem: the app was booting to a completely blank dialog box with just an OK button on it, then freezing. OTEE (the makers of Unity) support was quick, but their best suggestion was to re-install. The next day however I solved the problem: it turned out my date/time on my old Mac was not set correctly, and this was playing havoc with the DRM. I set up my date correctly and now Unity is working fine.

First Impressions


LerpzSo far Unity looks pretty cool. It’s apparent that it is optimized for making games compared to Director (which takes a more general approach). That is, there’s a lot of primitives and built-in game-oriented options that don’t require scripting, or even using pre-written scripts. That’s a breath of fresh air compared to Director, which pretty much requires you write your own systems for just about everything. The way the editor interacts with scripts reminds me a lot of Leia, which was LucasArt’s in-house level editor originally written for Jedi Knight (which I did level design for).

I’m about 1/3 through the Lerpz tutorial, which is a combo PDF and Unity project file that takes you though the basics of creating a 3rd person platformer using pre-written component scripts. It all seems pretty straightforward so far. My first few nitpicks: I’ve had a few crashes when switching viewport layouts, and the undo/redo seems a bit sketchy. Still, I’m impressed.

More to come here as I continue to play with it ….