informa
/
Business
Featured Blog

The Wayfarer WIP Mega Post

Migrated posts from my official site discussing the development of the 3D dungeon crawler 'The Wayfarer'.

Note: This is content which has been migrated from fidelumgames.wordpress.com, simply to provide a history and reference point for posts to come.

SITE LAUNCH & WHAT IS ‘THE WAYFARER’

Originally posted on August 14, 2017 on fidelumgames.wordpress.com

I’ve been working on my first large project for quite some time now, and if I have any hopes of having it be successful, I figure I’ll need an official site.

So I've made one. Check it out: fidelumgames.wordpress.com.

I started blogging over on GameDev.net, but decided I needed a centralized place to put everything related to the game, so I migrated that content onto my official site as well

As I continue to add development blogs, I’ll be continuing to post the content over on sites like GameDev.net and IndieDB.com, along with any other locations that I think will help get a bit of exposure. If there are any you’re aware of, feel free to leave a comment and share it!

As for what ‘The Wayfarer’ is, let me give a bit of an overview:

The Wayfarer is the tentative title of my current game development project.

In a nutshell, it’s an open world quest driven dungeon crawler with a strong focus on storytelling, lore, exploration and looting.

Imagine Legend of Grimrock meets The Elder Scrolls II: Daggerfall.

I’m developing in Unity and deploying primarily on desktop platforms, with plans for mobile as a secondary platform.

I’ve got big plans for this one.

Check out the other migrated posts to get up to speed!

MIGRATED POST 1: ALL OVER THE PLACE, NAILING THINGS DOWN, FINDING MY WAY (MOVEMENT AND PATHFINDING)

Originally posted on GameDev.net on January 3, 2017

ALL OVER THE PLACE

In my last post I discussed an Action/RPG/Platformer/Diabloesque/JRPG game that I had started working on, and showed a short prototype video. As if the genre of this game wasn’t already all over the place enough, I’ve since dropped the project (for now at least), and started work on something else.

The main reason for this was simply the lack of assets available to me for the game I wanted to make. I wanted to have fully modular armor for my character, but I simply couldn’t find the assets that I needed, even paid assets, and I can’t afford to hire an artist to create the level of sophistication for the armor that I wanted. This aspect of the game was really important to me, and without it, it just wouldn’t have felt complete. However, I happened upon a large number of highly reusable, customizable, affordable and high quality assets during my search which inspired me to go a slightly different route. Thanks to the prepaid Visa cards I got for Christmas, I was even able to buy a decent number of them ;).

Ever since I was a kid, I’ve been a huge fan of First Person Dungeon Crawlers. The first that comes to mind is SSI’s 1991 game Eye of The Beholder which was awesome (somehow I thought that flipping through a book to find the copyright protection phrase actually added to the fun). Even writing this I get nostalgic thinking about similar games like Catacomb 3DArcanaUltima Underworld, and of course, Daggerfall. This is a genre I’m always returning to. Even with AAA titles like Skyrim and Far Cry sitting on my computer, I’ll find myself putting them down in favor of playing old Dungeon Crawlers that I’d never heard of (like Anvil of Dawn).

In the last few years, I’ve been delighted whenever I’ve found a new title in the same vein as these classics, and to see how well they’ve been received.

Legend Of Grimrock did an amazing job of remaining true to these old classics while providing the added bonus of beautiful modern graphics, and has done incredibly well in terms of reception and sales.

Star Crawlers (even though it’s still in Early Access) manages to hang on to the meat of the genre while spicing it up with Sci-Fi flavors and innovative new features.

The Quest HD , a lesser known 2016 re-release of an older game is a full fledged first person dungeon crawler in beautiful 2D with open world environments and a great story. I might even argue that it outclasses many of the above titles in many ways. Really worth a look if you’re into this kind of thing.

I digress.

The point is: I really love these kinds of games. I don’t know if it’s something about the atmosphere, the storytelling, looting and killing or just the nostalgia of it all, but I think they stand out as my favorite genre.

So I’ve decided to make one!

NAILING THINGS DOWN

Like all of the games I come up with and want to make (very few of which even see as much as a keystroke of development), I’ve been thinking about this game pretty much non-stop for a couple of weeks. I’ve got a ton of ideas for the game–some to do with how to ‘stay true’ to the genre, some to do with how to deviate to add something original and worthwhile.

A few things I know for sure:

  1. I’m doing this one right. No half-assed hacking just to get shit done. I’m going to need a proper outline and game design doc, and I’m going to have to establish a normal routine so the project doesn’t rust and atrophy. Regular refactoring as well. I can’t have the tangled messes I’ve let happen in other projects.
  2. Grid-Based movement with some kind of turn-based play (this could be either semi-turn-based or full-out ‘wait for player action’).
  3. Nice 3D graphics. I really want to take full advantage of Unity’s new PBR and Lighting to make something that really looks great, and as I’ve said, I just got my hands on some really top-notch assets.

I’m tempted to add more in the above list, but, to stay on the safe side, I’ll make a second list of potential features currently under consideration:

  1. Multiple Levels/Areas–I think it would be more fun to have the player have the opportunity to spelunk in a cave system, bushwhack in a jungle, pillage in a crypt as well as crawl in the good ol’ dungeon.
  2. Open-world–I know what you’re thinking. How is this possible in a Dungeon Crawler? Seriously, have a look at The Quest. It integrates dungeon crawling and open-worldedness perfectly. A part of this is having towns that can be visited where quests can be undertaken and loot can be bought and sold (a feature missing from many dungeon crawlers).
  3. Complex character development–If any of you have read my earlier journals and are familiar with the last game I completed, Pixel Zombie Shooter, then you’ll know I’m keen on upgrades. I’d like to have a nice multi-branched skill tree for my players to fill up as they adventure.
  4. Questing–I briefly touched on this in number 2, but I’d really like to have some non-linear questing in this one as well. I think it would offer a lot of opportunity to develop lore and give me a chance to do some good storytelling.
  5. Procedural Generation–Yeah, I know. Buzz word. But seriously, I really want to get into this. I’ve already got some ideas for randomized weapon implementations like those found in Diablo, as well as for infinite guild quests and random dungeon areas. On that note, I’m not sure if I’d be interested in all hostile areas (dungeons, forests, etc.) being procedural, or just special ‘grinding/looting’ areas.

FINDING MY WAY

Ok. You’ve listened to me rant about this new game idea I’m obsessed about, but talk is cheap. Here come a few things to look at as a reward for sticking through this post so far.

I’ve only had two development sessions on this game so far, and I think they both went well. In both cases, I spent a full day prior to my night-time dev session thinking on and off about how best to implement a feature, and in each session, I’ve been able to successfully implement at least a basically functional version of said feature in only a small amount of time.

The first of these is a simple movement controller.

The Code:

CharacterMovementController.cs:

using UnityEngine;
using System.Collections;

public class CharacterMovementController : MonoBehaviour {

    [SerializeField] //How long it should take to rotate or move the camera    
    private float animationTime = 0.35f;

    [SerializeField] //The amount to move the player by. Should be equal to the size of each level 'tile'    
    private float unitSize = 3f;

    [SerializeField]  //How much to rotate on each rotation (1 == 360?). This shouldn't change unless allowing diagonal movement    
    private float rotationAmount = 0.25f;

    [SerializeField] //How high off the ground the player sits.    
    private float playerHeight = 1.75f;

    [SerializeField] //The easeType to use for the iTween animation.    
    private iTween.EaseType easeType = iTween.EaseType.linear;

    [SerializeField] //This is used to determine appropriate positioning when climbing/descending uneven terrain.    
    private HeightProbe heightProbePrefab;
    private Hashtable iTweenArgs;
    private bool canMove = true;    //Initialize itween args    
    void Start() {
        iTweenArgs = new Hashtable();
        iTweenArgs["time"] = animationTime;
        iTweenArgs["oncompletetarget"] = this.gameObject;
        iTweenArgs["oncompleteparams"] = true;
        iTweenArgs["oncomplete"] = "ToggleMovement";
        iTweenArgs["easetype"] = easeType;
    }

    void Update() {
        /* Uncomment to allow these values to be manipulated via the inspector at runtime for testing        
         * iTweenArgs["time"] = animationTime;
         * iTweenArgs["easetype"] = easeType; 
        */

        //Move or rotate the player based on input.        
        if (canMove) {
            if (Input.GetKey(KeyCode.W)) {
                Move(transform.forward);
            } else if (Input.GetKey(KeyCode.S)) {
                Move(-transform.forward);
            } else if (Input.GetKey(KeyCode.D)) {
                Move(transform.right);
            } else if (Input.GetKey(KeyCode.A)) {
                Move(-transform.right);
            } else if (Input.GetKey(KeyCode.E)) {
                Rotate(Vector3.up);
            } else if (Input.GetKey(KeyCode.Q)) {
                Rotate(Vector3.down);
            }
        }
    }

    /* Move the player in the appropriate direction. First initialize newPosition based on direction, then create 
       a HeightProbe to determine the appropriate y value for newPosition. This allows easy vertical movement along both
       even and uneven terrain. HeightProbe destroys itself after FindFloorHeight() is called.    */
    private void Move(Vector3 directionVector) {
        Vector3 newPosition = transform.position + directionVector * unitSize;
        HeightProbe heightProbe = Instantiate(heightProbePrefab, newPosition, Quaternion.identity) as HeightProbe;
        newPosition.y = heightProbe.FindFloorHeight() + playerHeight;
        iTweenArgs["position"] = newPosition; ToggleMovement(false);
        iTween.MoveTo(this.gameObject, iTweenArgs);
    }

    private void Rotate(Vector3 rotationVector) {
        iTweenArgs["amount"] = rotationVector * rotationAmount;
        ToggleMovement(false);
        iTween.RotateBy(this.gameObject, iTweenArgs);
    }

    private void ToggleMovement(bool allowMovement) {
        canMove = allowMovement;
    }
}

HeightProbe.cs:

using UnityEngine;
using System.Collections;
public class HeightProbe : MonoBehaviour { 
      [SerializeField] 
      private float destructionDelay = 0.25f; 

      [SerializeField] // This should be set to only detect the floor in the future 
      private LayerMask layerMask; 

      public float FindFloorHeight() { 
            StartCoroutine(SelfDestruct()); 
            RaycastHit hit; 
            Physics.Raycast(transform.position, -transform.up, out hit, Mathf.Infinity,                   
            layerMask); 
            if (hit.transform) { 
                  return hit.point.y; 
            } else { 
                  return Mathf.NegativeInfinity;
            } 
      } 

      private IEnumerator SelfDestruct() { 
            yield return new WaitForSeconds(destructionDelay); 
            Destroy(gameObject); 
      }
}

Both of these scripts are super simple and will need some updating, but they give a nice final effect:

Basically, when the user gives input, I spawn a HeightProbe in the appropriate neighboring space, which simply finds the height of the floor/ground in that location. The PlayerMovementController will then add playerHeight to this value and use that as the y position to move to. The reason I did it this way, rather than having a set step height was because I wanted the potential to have my player move on uneven terrain while maintaining the grid-based movement. This will be particularly useful for outdoor areas and will give me greater freedom in my level design.

Right now there are no checks to see if the player is trying to move through a wall, and I rely on iTween to do all of the heavy lifting in animating my player’s rotation and translations (who wants to manually code that stuff? Not me). Obviously I’ll have to do some checking for movement through walls. Also, based on what I’ve read, iTween is pretty inefficient (I do love working with it though), so I think I’ll have to rework the code to use DoTween instead (also free, but apparently performs way better).

Also, I might get rid of the HeightProbe class altogether and put the logic right inside the PlayerMovementController.

Lastly, I don’t like having my input hardcoded, so that’ll have to change. I’ll also want a bit of a mouselook functionality so the player can observe the environment more fully.

And yes, that was a baby dragon :wink:.

What I did in my next development session was implement a bit of pathfinding. Like I said, I thought about this all day, and I came up with my own algorithm. I have no idea what you would call it technically, but in demonstrations I’ve seen, it performs similarly to a concurrent Dijkstra implementation. e is an enemy, p is the player:


I’ve never done any pathfinding before (aside from using Unity’s built in AI stuff), so this is a first for me. And I think I did pretty good coming up with a solution completely by myself. I won’t need a ton of pathfinding in the game (since most enemies will probably only move toward the player if they can see him, or move to a last known location), but I thought this would be fun, and it was.

Not to mention I really like watching my code solve a maze :P. There’s something hypnotizing about these gifs.

The Code:

Pathfinder.cs:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Pathfinder : MonoBehaviour {

    [SerializeField]
    private Color color = Color.red;

    [SerializeField]
    PathProbe pathProbePrefab;

    [SerializeField]
    private float unitSize = 3f;
    public float UnitSize {
        get {
            return unitSize;
        }
    }

    [SerializeField]
    private LayerMask layerMask;

    [SerializeField]
    private Vector3[] directions;
    public Vector3[] Directions {
        get {
            return directions;
        }
    }

    private List probedCells = new List();
    public List ProbedCells {
        get {
            return probedCells;
        }
    }

    private List pathToTarget = new List();
    public List PathToTarget {
        get {
            return pathToTarget;
        }
        set {
            pathToTarget = value;
            foreach (PathProbe pathProbe in GameObject.FindObjectsOfType()) {
                if (pathProbe.Master == this) {
                    Destroy(pathProbe.gameObject);
                }
            }
        }
    }

    void Start() {
        InitiatePathFinding();
    }

    private void InitiatePathFinding() {
        probedCells.Clear();
        pathToTarget.Clear();
        probedCells.Add(transform.position);
        foreach (Vector3 direction in directions) {
            CreateProbeAtNeighboringCell(transform.position, direction);
        }
    }

    void Update() {
        if (Input.GetKeyDown(KeyCode.F)) {
            InitiatePathFinding();
        }
    }

    public PathProbe CreateProbeAtNeighboringCell(Vector3 position, Vector3 direction) {
        Vector3 cellPosition = position + (direction * unitSize);
        if (!probedCells.Contains(cellPosition)) {
            RaycastHit hit;
            Physics.Raycast(position, direction, out hit, unitSize/*, layerMask*/);
            Debug.DrawRay(position, direction * unitSize, color);
            if (!hit.transform) {
                PathProbe newPathProbe = Instantiate(pathProbePrefab, cellPosition, Quaternion.identity) as PathProbe;
                newPathProbe.Master = this;
                newPathProbe.Color = color;
                probedCells.Add(cellPosition);
                return newPathProbe;
            }
        }
        return null;
    }
}

PathProbe.cs:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class PathProbe : MonoBehaviour {

    private Pathfinder master;
    public Pathfinder Master {
        get {
            return master;
        }
        set {
            master = value;
            StartCoroutine(PathFind());
        }
    }

    private Color color = Color.red;
    public Color Color {
        set {
            color = value;
        }
    }

    private List pathPoints = new List();
    public List PathPoints {
        set {
            pathPoints = value;
            pathPoints.Add(transform.position);
        }
    }

    private List myProbes = new List();
    private IEnumerator PathFind() {
        if (master) {
            yield return new WaitForFixedUpdate();
            if (master.PathToTarget.Count <= 0) {
                foreach (Vector3 direction in master.Directions) {
                    PathProbe newPathProbe = master.CreateProbeAtNeighboringCell(transform.position, direction);
                    myProbes.Add(newPathProbe); if (newPathProbe) {
                        newPathProbe.PathPoints = this.pathPoints;
                    } else {
                        RaycastHit hit; Physics.Raycast(transform.position, direction, out hit, master.UnitSize);
                        //Debug.DrawRay(transform.position, direction * master.UnitSize, Color.green);                       
                        if (hit.transform && hit.transform.tag == "Player") {
                            master.PathToTarget = pathPoints;
                            Debug.Log("Path to player found in " + Time.time + " seconds!");
                            foreach (PathProbe probe in GameObject.FindObjectsOfType()) {
                                Destroy(probe.gameObject);
                            }
                        }
                    }
                }
            }
            Destroy(this.gameObject);
        }
    }
}

Basically, I raycast in all four directions from the enemy’s position, at a distance equal to my grid size. If my rays don’t hit anything at those locations, I spawn a PathProbe at the appropriate place and repeat, adding each cell from which rays were cast to a probedCells list, and omitting those cells from future checks. Because each probe performs iterations at the same time as all of the others, the first path to reach the player is always the shortest, so I didn’t even need to take that into consideration, and as soon as any path is found, I can stop the search.

Currently, my coroutine’s yield is no good and it makes the whole process take a relatively long time (waiting for a new frame before performing another iteration). Essentially, only a single set of cells for each probe can be checked per frame, which can become a problem, particularly in long narrow paths. I need to allow a greater number of checks before yielding to speed up the whole process, but I also have to be careful not to overload it or things tend to crash.

Currently, both of the searches you see above take about 0.75 seconds each. Again, this has nothing to do with complexity, and more to do with how my coroutine operates. In fact, having multiple paths calculated at the same time has had zero impact on frame rate or calculation time so far (though I’ve only tested 3 concurrent paths to date).

However, I really need to rework this as .75 seconds is not acceptable. Presumably, to be safe, I’ll have to recalculate the path each time the enemy moves to a new cell, just in case something has blocked the path or the player has moved. But like I said, I don’t think I’ll need a lot of pathfinding. I think most of it will be linear movement along a line of sight.

Again, I might remove my logic from PathProbe and put it right in Pathfinder to avoid Instantiate calls.

I was also considering using Unity’s NavMeshAgent to calculate a path, and then writing some code to normalize that path to align with my grid (I assume Unity’s pathfinding would be more efficient than anything I’ll write). Another approach I’m considering is generating an array based on my level when it loads, and then traversing the array based on whether the given index is walkable or not. This would save on raycasting at least.

Anyhow, that’s it for now!

Stay tuned for more, including the launch of an official website for Fidelum Games!

MIGRATED POST 2: MENACING CUBES METAMORPHOSIZE

Originally posted on GameDev.net on March 4, 2017

In my LAST POST, I talked mostly about some of the pathfinding options that I came up with. One of these solutions involved relying on raycasting to determine a path to my player, which was a fun exercise and yielded some really entertaining gifs. However, I decided to scrap that system in favor of using Unity’s built-in pathfinding system via the NavMesh and NavMeshAgent components.

However, because my game uses grid-based movement, I wasn’t going to be able to use said system out of the box.

My first solution to making Unity’s pathfinding play nicely with my game was to have the NavMeshAgent generate a path, and then overwrite that path by normalizing each of its points to align with my grid (whose cells are 3x3x4).

This would have been fine, but I soon realized that would have had to account for inserting points along lengthy straight paths, as the NavMeshAgent only calculates the corners, or turning points, along the path.

I could have done this, but after a bit more thought, I realized this would require unnecessarily complex logic, and that I could accomplish the exact same end result with a simpler, but similar solution.

Basically, I just decided that, each time my enemies move, I would have the NavMeshAgent generate a new path. Then, instead of normalizing the entire path, I would just lo

Latest Jobs

Sucker Punch Productions

Bellevue, Washington
08.27.21
Combat Designer

Xbox Graphics

Redmond, Washington
08.27.21
Senior Software Engineer: GPU Compilers

Insomniac Games

Burbank, California
08.27.21
Systems Designer

Deep Silver Volition

Champaign, Illinois
08.27.21
Senior Environment Artist
More Jobs   

CONNECT WITH US

Register for a
Subscribe to
Follow us

Game Developer Account

Game Developer Newsletter

@gamedevdotcom

Register for a

Game Developer Account

Gain full access to resources (events, white paper, webinars, reports, etc)
Single sign-on to all Informa products

Register
Subscribe to

Game Developer Newsletter

Get daily Game Developer top stories every morning straight into your inbox

Subscribe
Follow us

@gamedevdotcom

Follow us @gamedevdotcom to stay up-to-date with the latest news & insider information about events & more