Tag Archive: narnach


Another weekend, another Unity hackathon. One of the nice thingies I created today is a simple script that tells me what object my mouse is pointing at.
The source code for Physics.Raycast offers examples that help with mouse-to-screen conversion and ray casting, but they don’t wrap it up into a plug ‘n play script.
This one should be just that.

I wonder if this is the right way to handle this or if there is a built-in function to do it, which I overlooked.

I’ve also attached a screenshot and demo level I’ve dubbed Neon City. It uses self-illuminated cylinders with a black/white texture for the borders. There are stacks of boxes with a brushed steel texture that uses the Reflective/Parallax Diffuse shader for shininess and for a reflection of the sky texture. Either way, it was fun playing around with baking lightmaps and seeing what you can do with Beast. It’s really, really easy to setup a scene that seems to have small lights every everywhere, even though there is only a single Directional light in the entire scene.

Another fun thing Gerard and me discovered today is how easy it is to place a camera in the scene and have it render its output onto a plane somewhere else, to create a security camera + monitor system.

One thing that bugged me about earlier demos is that almost every edge in the game appeared jagged instead of being smoothed by anti-aliasing. In order to render real-time shadows from point lights such as fireballs, the rendering path needs to use Deferred Lighting. The trade-off, as documented on the Unity3D site, is that there is no anti-aliasing in Deferred Lighting mode. The default Forward Rendering mode gives you anti-aliasing, but no real-time shadows from Spot/Point lights. Only from one Directional light.

Unity is very helpful that it lets you know that only directional lights have shadows in forward rendering, but according to Warwick Allison, you can create your own shader with the fullforwardshadows setting to enable shadows on your surface. After an hour or so searching and surfing, I did not manage to find a package with shaders that add this behavior to the default shaders, so I guess I’m looking for something that either people don’t find too bothersome or that’s too hard to do. For now, I hope that a future version of Unity will fix this.

Anyway, here’s the source code for the detector script and below that is a screenshot of demo 7.


#pragma strict;

/***********************************************************************************************

Usage example:

  public var cam : Camera;
  public var text : GUIText;

  // If the mouse points at a an object, display the name of that object on screen.
  function Update () {
    var obj = MousePointerObjectDetector.Detect(cam);
    if (obj) {
      text.text = "Hit: " + obj.name;
    } else {
      text.text = "No hit";
    }
  }

***********************************************************************************************/

// For the camera, return the Transform of the object that is pointed at by the camera.
// Returns null if nothing is pointed at.
class MousePointerObjectDetector {
  public static function Detect(camera : Camera) {
    var pos : Vector3 = Input.mousePosition;
    var ray : Ray = camera.ScreenPointToRay (pos);
    var hit : RaycastHit;
    if (Physics.Raycast (ray.origin, ray.direction, hit)) {
        return hit.collider.transform;
    } else {
      return null;
    }
  }
}

Screenshot of demo 7

Analysis of a movement script

Last weekend I experimented with various aspects of Unity 3D to get a feel for it and to see if I would like to learn more. I was convinced after less than an hour, so now I want to learn more. First, I’ll try to get an intuitive understanding of the basics.

The Tornado Twins have an excellent series of YouTube videos where they build a simple game and explain basic concepts like movement, having turrets shoot bullets at you and more.

I watched the first 11 episodes yesterday evening and decided to see if I could build something similar with what I remember and by using the documentation.

Movement was the first thing I stumbled over. The concepts are clear to me, but the details of how to do it remain blurry. In the documentation, I found the example for CharacterController.Move().

At first the example looked overly complex to me, so I started taking out most of the code until the Update() function only contained three lines. And my sphere happily moved through the area. I was not happy with using the arrow keys to strafe to the sides, so I adjusted it to use up/down to move forward/backward and left/right to turn to the sides. I now had four lines.

While running/rolling/floating/whatever around with my sphere, I found myself tapping the space bar every couple of seconds because I wanted to jump, but the sphere stayed on the ground. It was time to add jumping back to the script.

So I started adding bits of code back in and before long I had most of the example code back, but jumping did not work yet. Fiddling around with the gravity manipulation eventually made me realize I needed to divide gravity by Time.deltaTime to reduce the per-frame effect of gravity instead of applying it about 200 times stronger than intended.

After this, my script was working and the sphere happily races around in its playground. However, it seemed useful to dive back into the code and extensively comment it for posting on our blog, to help me understand how it works. They say that the best way to learn… is to teach.

Enjoy the source code!

// This script moves and rotates the character controller using the arrow keys.
// Space can be used to jump.

// Variables available from the editor to tweak how fast the character moves
public var speed : float = 6.0;
public var gravity : float = 20.0;
public var jumpSpeed : float = 8.0;
public var rotationSpeed : float = 1.0;

// Movement vector. It's stored outside of the Update() function to
// remember the vector while jumping and increase the pull of gravity
// on the character over time.
private var moveDirection : Vector3 = Vector3.zero;

// The character controller that we're manipulating.
private var controller : CharacterController;

function Awake() {
  // Since we're not going to swap the CharacterController on a character,
  // we'll look it up once and store it in a variable.
  // In theory this should save a few nanoseconds every frame.
  controller = GetComponent(CharacterController);
}

// Update gets called every frame, so remember to multiply all numerical
// effects with Time.deltaTime to make them framerate-independent.
function Update() {

  // Rotate based on the left/right arrow. Since we spin around the Y-axis,
  // we only need to use the up direction of the Vector3.
  transform.Rotate(Vector3.up * Input.GetAxis("Horizontal") * rotationSpeed);

  // When on the ground, move. Otherwise, don't re-create a new moveDirection,
  // but let gravity do its thing on the old one to drag us back down.
  if(controller.isGrounded) {

    // First create a local space vector to describe our intended movement
    // and its speed.
    var localDirection = Vector3.forward * Input.GetAxis("Vertical") * speed;

    // Take the local movement and transform it to world space, this is because
    // CharacterControler.Move wants a movement in world space.
    moveDirection = transform.TransformDirection(localDirection);

    // Force our upward momentup to jumpSpeed when we press space.
    if(Input.GetButton("Jump")) {
      moveDirection.y = jumpSpeed;
    }
  }

  // Apply gravity to the current moveDirection object, no matter if we decide
  // to move or not. Gravity is modified by Time.deltaTime to smooth it out over
  // time. Note that it's outside the if block and thus also triggers in the
  // air.
  // This is why jumps are so smooth: we have an upward momentum from the
  // jump and now we are reducing the positive momentup each frame until it's
  // zero (at the top of the jump) and then each frame the character is
  // pulled down faster because the momentum becomes more negative.
  // When we hit the ground, the block above kicks in to reset momentup to zero.
  moveDirection.y -= gravity * Time.deltaTime;

  // Actually perform the move. Note that this is modified by Time.deltaTime to
  // make it framerate-independent.
  controller.Move(moveDirection * Time.deltaTime);
}

// Ensure we have a CharacterController component included in our character.
@script RequireComponent(CharacterController)


Screenshot of demo 6
Demo 6

Day two with Unity3D

This morning I set out to expand the last demo I created yesterday. The result is Demo4.

Demo4

20110711-di13npqhrbek9j52ffs2x1wepn.png

20110711-d522ud152bnw3snkqtrydy2s3j.png

In Demo3, the fireballs were duplicates of the same tree of objects. In demo4, they are in a new prefab that replaces the old fireballs. This proved useful when I wanted to update the look, feel and behavior of all fireballs.

The behavior change to the fireballs is in how they handle their patrol route. Demo3 remembered their starting point and I supplied a Vector3 with the X/Y/Z coordinates they would move to. Once they reached their goal, they would compare their position with their starting point and endpoint and they would pick the one they were not at to move to next. This worked, but it was limited and it resulted in fireballs attacking walls when I duplicated my room and moved the copy 10 units to the side. Oops.

So the Demo4 version of the fireball patrol route uses waypoints for navigation. The waypoints are instances of a simple PatrolNode prefab with an attached script called DisableMeshRendererOnAwake, to show the nodes while developing, but not when playing.

The fireball patrol script exposes a collection of GameObjects and the index for the current target. Each PatrolNode added to the collection is moved to in order. I ensure constant movement speed by using Vector3.ClampMagnitude on a diff between the current and target node position and multiplying it with Time.deltaTime to scale it down based on frame render time.

Once the fireball patrol code was done, I could easily add bigger patrol routes, so I did and most fireballs now chase after each other in the room.

The number of rooms I increased one-by-one until there were four.

Room one is the original room of Demo3, but the fireballs patrol in a square instead of up and down a line. There’s a corridor to room two, which is identical to room one except that there are no spotlights. The fireballs are stronger point light sources now, so they illuminate the room rather well. Next is a connection to room 3, which has no more inner wall and no spotlights and has each fireball patrol around its own pillar. Next is a connection to room four.

Room four is 20×20 instead of the 10×10 of the other rooms, but it has a 10×10 area in the center that’s a copy of room three except that there are no walls. The walls are half height and placed at the edges. Instead the floor is covered in grass and most of the room looks up to a skybox.

Since all solid objects are basically cubes that have been stretched to non-cube shapes, I’m making a new Material for each aspect ratio of wall or pillar I need. I’m sure there’s a better way to do it. I could look at turning one big 20×0.1×3 wall into a collection of 0.1×0.1×0.1 cubes and stacking them. Since the texture is seamless, this should work well, but there’d be a lot of different objects and lots of textures on sides you can’t see. It seems rather inefficient. The alternative is to figure out how I can create a texture that fits my wall’s dimensions exactly.

Demo5

20110711-bjx1xuj2kus41r6bxa5bpnh2ad.png

Tonight, I created Demo5 to get a better grasp on collisions and the physics model. It’s a simple bowling game built on top of the roof of Demo4 🙂

The player holds (via a FixedJoint) a heavy sphere, the ball. The BreakVelocity and BreakTorque are set to infinite, so the ball will stay glued to the player.

The player has an Update function that checks Input.GetButton(“Fire1”) to see if the left mouse button or Ctrl is pressed. If so, it starts adding Time.deltaTime to a counter and the ball is forced to face the same way as the player. Once the button is released, the square root of the counter value is multiplied with an arbitrary value of 300 and applied as forward force on the ball. The ball’s BreakVelocity and BreakTorque are set to 0, so the ball immediately snaps loose and is propelled in the direction the player is looking.

The pins are instances of a simple cylinder prefab. They have a script that checks if their rotation is still (0,0,0). If any of the dimensions change more than 0.5 degrees, assume the pin has fallen and marke it as not standing.

There’s a GUIText element in the top left corner. Because all pins have been tagged with ‘Pin’, I can simply use GameObject.FindGameObjectsWithTag(“Pin”) to find all pins and check if they are still standing. Count the standing ones and display it in the GUIText.

The thing that took me longest to figure out was which collision detection method to use for these objects. I read through the docs a bit and it looked like ContinuousDynamic was the best option, as it checked against just about everything. Pins and ball used it, but the ball just bounced off the pin without making it move a hair. I lifted the ball in the air above the pin to drop it, and it did push the pin over. After an hour of fiddling and trying to write custom OnCollisionEnter() handlers I started flippiing the collision detection method and found that Continuous did what I wanted without requiring scripts. Lesson learned.

Fiddling with mass and drag taught me that a ball does not necessarily have to keep rolling forever.

The player is still set to be Kinematic, so it is not affected by physics at all. This also seems to mean that it does not make a pin fall over when the player pushes against the pin. Disabling Kinematic turns the standard FPS Controller’s jump action into a jump that keeps going on forever. Not quite what I intended.

Random lessons learned

  • Prefabs are very useful to base repeatable objects on, it makes it so much easier to change them all later on.
  • Using empty GameObjects is a very useful method for grouping objects.
  • Using objects as nodes for defining patrol routes beats manually typing in coordinates: they move along when duplicating a room.
  • Abusing cubes to create walls is easy to get results, but it’s not the prettiest solution when using a one-sided texture that’s repeated on each side of the ‘cube’.
  • The physics system in Unity3D is nice, but it takes a while to grasp the subtleties.

And that’s it for today. Perhaps I’ll create more demos during the week at night. Otherwise next weekend is likely going to be another hackfest with Gerard. He’s making progress on his demos, (though I need to bug him about posting his demos here) so it’s not going to be long before we’ll start working on tech demos/tools that can be useful for our first real game.

My first day with Unity3D

Today I sat down for my first day of Unity3D. Gerard was nearby to answer questions, but since he was working on expanding his own demo, I looked up more things than I asked him. By the end of the day we were helping each other troubleshoot our problems, so I guess I learned a couple of things 🙂

Demo 1

20110711-q8qy8ccr73eccs39mykiujxi22.png

 

This is a room built out of cubes that have been stretched and textured. I created textures using FilterForge. The construction worker guy comes with the 3rd Person Controller created by Unity, but his reaction is a bit iffy.

The fireball is two particle emitters inside an empty GameObject container that handles global positioning and movement. It does not cast light, but it does do collision detection while moving. Earlier versions of the fireball calculated the new position for the fireball each frame and set the transform.position instead of issuing a collision-detection Move order. Adding a CharacterController and replacing my Lerp-based transform with a Move order did the trick. The code also became a lot shorter.

There are Spotlights in the four corners of the room and an inner wall and pillar to see the effect of dynamic and static lights on real-time shadows. One thing to remember here is that the Rendering Path needs to be set to Deferred Lighting, otherwise only Directional Lights can cast shadows. Since I want to create mainly indoor locations (dungeon crawlers don’t have windows or sunlight) this was kind of useful to figure out.

Demo 2

20110711-pt1mxrinyxtyg165sgtxj4kj2c.png

 

I got annoyed with the iffy controls, so I tried to do something different: a first-person view with mouselook.

I generated some more textures with FilterForge and started looking into the available shaders for Materials. The ceiling is shaded with a Parallax Diffuse, which uses a base texture, a Normal Map and a Height Map that were all generated with FilterForge.

There are now four fireballs that patrol through the room and four pillars. The spotlights in the corners have been moved and re-oriented. All of this creates a nice interplay of shadows.

The new floor texture is also created using FilterForge.

I’m not quite happy with the fireballs: the smoke’s billboard shows as squares against a bad backlight, which is ugly.

Demo 3

20110711-nrg95aba14iirt6d8en4k7wte.png

 

This demo changes the fireballs to use the Particles/Additive (Soft) shader instead of the ~Additive-Multiply shader for both the flames and the smoke. No more billboards! I also tweaked the texture, number and size of particles for fire and smoke to give a nicer look. Enabling Simulate in Worldspace for the Particle Emitter makes the flames trail after the moving fireball.

I’m not quite happy with the bricks: compared to the other textures they look a bit bland and poorly stretched.

Conclusion

All in all this was a very productive first day. I learned the basic workflow of how to create Game Objects, how collision is handled and how to write my own scripts and make them run each frame. Before today, I knew nothing of shaders and lighting/shading. Now I at least understand what they’re about and how to use them.

Design a site like this with WordPress.com
Get started