Blender – Custom Bevels

This week for my game called The Gap I’ve been doing some house components. The game is set in the suburbs and there will be a lot of house interiors. In what I envision to be the opening scene of the game your main character wakes in his or her bedroom alive with excitement and ready to explore the world. Which has little to do with cornices but it’s these details that make the game look like a world and adds to the immersion.

So here is an example of a cornice that I have made in Blender using the Bevel Modifier.

The Cornice using a Vector Group and Custom Bevel

This starts as a cube with about a quarter cut out of the form and a reduced height. But any straight edge will do. First use the edge select to assign all the relevant parts you want to bevel into a Vector Group. (Select the edge and in the object data panel use the “assign” button under the Vector Group section). Then you add the Bevel Modifier and as you can see in the image above you use the Limit Method by Vector Group and then add your new Vector Group you just assigned. Choose Custom Bevel and use either one of the presets or use the graphing tool window at the bottom to create your own bevel shape. There are a couple of nice cornice style presets in that section to get you started. (It helps to play round with the Amount and Segments section at the top to improve the look – also try Smooth Shading on the object).

Below is a Window frame I used the same technique on but with a different profile. I used ctrl+R to make some loop cuts around the inside of my window frame and used the edge select to assign the cuts to a Vector Group. Then again I used a Bevel Modifier to make a custom set of ridges around the window frame to make it look like the fittings of the aluminium framing around the glazing of the window.

Custom Bevel on a Loop Cut to make Window Mouldings

You can see I also added a normal Bevel Modifier to the edge of Window Sill to create the outer wall shape where the rain runs away from the window frame.

I did a quick mock up in Unity to see how they performed under the often difficult lighting environment of the game engine. As you can see below by the shadows on the walls and spot light on the floor it’s not an ideal set up and the cornices are looking pretty crap. At the top of the room on the back wall I have two longer cornice pieces and a corner piece is visible as well. The two at the back are picking up different light sources and one looks lighter than the other. They are clearly three separate objects and not one nice clean line. It might help to add some more surface geometry to the longer pieces so they are not just one long face (loop cuts or subdivisions). Alternatively I could measure them out to fit the room exactly and meet in the corners – but then I would have to make multiple lengths instead of a more modular re-usable approach.

Cornices under lighting conditions in Unity

Character Design

The other thing I did this week that was actually productive is some more character designs. This one is Hippo Boy catching a football and a couple of different shading styles (still playing with Clip Studio and still enjoying it). Next up I’m thinking about all the ways I can program a mugby style football game.

Hippo Boy
Pop Style Hippo Boy

Getting a Foot in the Door of Game Design

First of all – sorry about the misleading title – this post is about getting the doors working in the Endless Elevator game that we are currently developing. I thought it was a good pun and that as this post is all about our development process that it wasn’t too bad. The only career advice I got is just to start making games…any games.

You’d think making a door that opens and closes would be a pretty simple thing to do but surprisingly it wasn’t.

I designed and built some 3D models of building components in MagicaVoxel and exported them as .obj files. I use MagicaVoxel because it’s free and really quick and simple to use. When I model components I can be sure that they are all exactly the same scale and that all the different bits (no matter when I made them) are going to fit together without any hassle. But the models are not optimised for game engines as they have a reasonably high poly count due to the modelling process within the program. Most of the models come out with heaps of unnecessary triangles that need to be managed first. In most cases I will import the object into Blender and use the “decimate” modifier on the planes (with an angle of about 20 if you are interested). In the case of the door object it was pretty simple, it is just a door after all, and I didn’t need to optimise it.

Here is what the door looks like in MagicaVoxel:

Notice that the door object is sitting just forward of the enclosing frame and that when exporting the object the center is at the middle bottom plane of that frame. The door is off center because it’s modelled to fit exactly in a doorway that sits exactly in that position within the frame. This saves me a huge amount of time lining everything up when it gets to Unity as the position of the door (or any other object for that matter) is already in the right spot. The problem is that the point of origin for the door is in the wrong spot. It exports a few units behind the door and on the floor! This becomes important when you try and rotate that object (like you would when opening and closing a door) and the pivot point is not where the hinges should be.

To fix this I had to import the .obj file into Blender and reposition the point of origin for the model.

This is what it looks like in Blender when I did this:

To do it I selected the edge that I wanted the door to pivot on when opened.

Then in Edit Mode:
Mesh -> Snap -> Curser to Selected

In Object Mode:
Object -> Transform -> Origin to 3D Curser

So that puts the curser onto the correct position in the middle of that edge where the hinges would be and resets the point of origin (which is where it will pivot when rotated in Unity) to the right spot.

Once we were all imported into Unity and looking good I set up a prefab for the “Doorway” object with the door as a child object. The doorway object has a bunch of colliders to stop the player walking through the walls and a big sphere collider where the door would be to trigger the open / close function when the player walks into it.

This is what the doorway looks like in Unity:

Next I scripted up a few options for opening the door. I’ll post the script at the end of this article but basically there were three options of opening the door that I wanted to test. (Actually I tried it about six ways but whittled it down to the most simple methods – and just as an aside there is an actual “hinge” object type in Unity if you ever need it).

This is how the script looks in the editor:

Notice the slider at the bottom to control how far I want the door to open. It’s really handy to have this when playing in the editor and getting your settings right. If you want to know more about using it see this post

The three tick boxes are for testing the three different ways of opening the door.

Snappy was a quick simple transform of the position from open to closed with no “in betweening”. It looks a bit unnatural as the door magically goes from closed to open but it’s not too bad and most people are pretty used to similar behaviour in video games.

The active line in the code is:
the_door.transform.Rotate(-Vector3.up * 90 * Time.deltaTime);

The next method works more like a door should. In that it swings open and closed the whole way in a steady fashion. But the big problem with this method was that it was OK when the character was going into the doorway and with the swing of the door but when it was time to come back out of the doorway the door was in the way. There was not enough room to trigger the door opening from the other side without being hit by the door as it opened. Plus if the player enters the collider from the wrong trajectory the character gets pushed through a wall by the swinging door which is sub-optimal. I called this method InTheWay!

The active line here is:
the_door.transform.rotation = Quaternion.Euler(targetPositionOpen);

In an effort to combat this I chose to do a hybrid method that opened the door to a point that wouldn’t hit the player and then do the magic transform to get all the way open. I call this one aBitBoth. It looks a little weird too. Like there is an angry fairy pulling the door closed with a snap after the character enters.

Here are all three to compare.

Snappy

In The Way

A Bit of Both

I’m not too sure which one I’m going to use at this stage as the Snappy method works best for now but I like the In The Way method better. I looks more normal and I like that you have to wait just a few milliseconds for the door to swing (adds tension when you are in a hurry to escape a bullet in the back). I could do something like halt the player movement from the rear of the door when it triggers to open from the closed side or maybe play around with the radius of the sphere. Neither solutions seem like great ideas to me right now but something like that will need to be done if I’m going to use that method. Maybe I could just have the door swing both ways and open to the outside when he is behind it but that’s probably a bit weird for a hotel door.

Here is that script that I was testing with:

using UnityEngine;

public class OpenDoor : MonoBehaviour {

    public bool openMe;
    public GameObject the_door;
    public bool snappy;
    public bool inTheWay;
    public bool aBitBoth;
    public Vector3 targetPositionOpen;
    public Vector3 targetPositionClosed;

    [Range(0F, 180F)]
    public float turningOpen;

    void Start ()
    {
        targetPositionClosed = new Vector3(0f, 180f, 0f);
        targetPositionOpen = new Vector3(0f, turningOpen, 0f);
    }

    void Update()
    {

        if (openMe)
        {
            OpenMe();
        }
        else
        {
            CloseMe();
        }

    }

    private void OpenMe()
    {

        if (inTheWay)
        {
            if (the_door.transform.rotation.eulerAngles.y > turningOpen)
            {
                the_door.transform.Rotate(-Vector3.up * 90 * Time.deltaTime);
            }
        }

        if (snappy)
        {
            the_door.transform.rotation = Quaternion.Euler(targetPositionOpen);
        }

        if (aBitBoth)
        {
            if (the_door.transform.rotation.eulerAngles.y > turningOpen)  // 144f
            {
                the_door.transform.Rotate(-Vector3.up * 90 * Time.deltaTime);
            }
            else
            {
                the_door.transform.rotation = Quaternion.Euler(targetPositionOpen);
            }

        }

    }

    private void CloseMe()
    {
        if (inTheWay)
        {
            if (the_door.transform.rotation.eulerAngles.y <= 180)
            {
                the_door.transform.Rotate(Vector3.up * 90 * Time.deltaTime);
            }
        }

        if (snappy)
        {
            the_door.transform.rotation = Quaternion.Euler(targetPositionClosed);
        }

        if (aBitBoth)
        {
            if (the_door.transform.rotation.eulerAngles.y <= turningOpen)  // 144f
            {
                the_door.transform.Rotate(Vector3.up * 90 * Time.deltaTime);
            }
            else
            {
                the_door.transform.rotation = Quaternion.Euler(targetPositionClosed);
            }
        }
    }

        void OnTriggerEnter(Collider col)
    {
        string colName = col.gameObject.name;
        Debug.Log("Triggered OpenDoor!!! : " + colName);

        if (col.gameObject.name == "chr_spy2Paintedv2" || col.gameObject.name == "BadSpy_Package(Clone)") 
        {
            openMe = true;
        }
    }

    void OnTriggerExit(Collider col)
    {
        if (col.gameObject.name == "chr_spy2Paintedv2" || col.gameObject.name == "BadSpy_Package(Clone)") 
        {
            openMe = false;
        }
    }

}

The Five Games in Ten Weeks Challenge!

Some months back I went to a local presentation by the Unity champions at The Arcade (a collaborative workspace specifically for game developers and creatives) in Melbourne.  It was one of those “learn about others and gain insight into one’s self” moments.  One thing I picked up from one of the presenters from Hipster Whale (makers of Crossy Road) was that when they were developing a new game they tried to keep the proof of concept to a two week period.  Some time later with this in mind I presented to myself the “Five Games in Ten Weeks Challenge!” to see if I could really push out five different games in ten weeks.

Five Games in Ten Weeks

Continue reading