Gamasutra: The Art & Business of Making Gamesspacer
arrowPress Releases






If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 

The Wayfarer WIP Mega Post

by Jake Jollimore on 09/01/17 03:56:00 pm   Featured Blogs

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

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 look at the first point in the path and normalize that. Why bother normalizing the whole path if I’m only ever going to be moving to the first point in the path anyway?

After I did this and added a bit of extra logic to account for the locations and movements of other enemies, I was able to successfully have relatively large mobs moving in ways that (more or less) seem to make sense.

Check out this video of some menacing cubes following my player around:

After I got all of that mostly working, I decided that, although the game is still in a super early state, I owed it to myself to add a bit of polish and replace my cubes with one of the assets I acquired.

Check out the difference a couple of textures, 2 models and some animation configuration can make:

So there’s a lot going on in this video, so let me explain.

Firstly, here’s a list of the key features that you can see in the video:

  1. Grid based player movement and turning (thanks to the awesome iTween library for all of my grid movement and rotation animations)
  2. Mouse Look with rotational snapping (this was actually kind of fun to do)
  3. Dissolving enemies (I’m still experimenting with different effects as you can see. Let me know which one you like).

Secondly, here’s an explanation of what you’re seeing in the video:

The game view is on the left. This is what the player sees.

On the right we have a bird’s eye view courtesy of Unity’s Scene View.

Note that the game uses a true turn-based system. Enemies won’t perform an action until the player does. In the video it appears that the enemies sometimes take multiple turns, but I’m actually skipping my turn via keypresses in those cases. I guess I should also mention that if an enemy turns to face a new direction, it ends their turn, but the player can turn as many times as they want for free. I might change this in the future, depending on whether or not this becomes an ‘unfair’ thing to be able to do and tilts the odds too much in the player’s favor.

The blue overlay you see is the walkable area of Unity’s NavMesh. You’ll notice that when an enemy enters an attack state, it will carve out the square that it occupies, making it non-walkable so that other enemies avoid that cell appropriately. I had to do it this way because, although Unity’s NavMeshAgents will avoid one another if they’re in control of movement, they don’t actually take into account other NavMeshAgents when they calculate the path, and since I’m manually moving my enemies, I needed a bit more customization.

You’ll also probably notice that some of the skeleton’s animations are a bit off–the attack in particular. Unfortunately, I couldn’t allow the animations to apply root motion as it interfered with my grid based movement, and as a result, some of the animations are a bit wonky. This was a purchased asset, which I’m still happy with, but if everything goes according to plan, hopefully I’ll be able to spend some money to have the animations updated to align with my grid.

Anyhow–that’s pretty much it for now.

I think my next focus will be on starting my inventory system. Looting, buying and selling are going to be a core gameplay component, so I’m going to have to get it right.

MIGRATED POST 3: BRANCHING OUT, WORLD BUILDING

Originally posted on GameDev.net on June 26, 2017

Waaaay too long since my last update.

Since then, I’ve been working (not nearly as much as I should be) on outdoor environments and a skill tree.

I want this game to follow the classic RPG class formula of Mage, Fighter and Thief, but I didn’t want to constrain my players to a single class. Instead, I decided to go with a classless/multiclass concept where players are able to traverse a large skilltree which is implicitly divided into the three aforementioned classes.

Take a look at the prototype:

So this is still an early proof of concept, and all of the visual elements will probably change, but it’s going to function in pretty much the same way as shown here. You’ll also get a (very) small taste of the kind of skills you might see in the game. One more note: the three skill branches never merge in this example, but I think they will in the final version. Also, all parent nodes of a skill must currently be unlocked before unlocking a given child node. I’m not sure if this will persists, or if I’ll remove that constraint to give me freedom of traversal.

Other than that, I’ve been spending a bit of time building some outdoor environments to try to nail down what my worlds will look like.

This first screenshot is, quite honestly, pretty bland and generic, but it will at least give a sense of how villages will be laid out in the world:

After I made this scene, I procured a license for Gaia–a really powerful and full featured terrain generation tool for Unity.

Here’s what 15 minutes of work with Gaia looks like:

Pretty amazing huh?

So in the end, I think I’ll be using Gaia to build my world, and then I’ll refine the terrain manually and tweak the positioning of settlements and other points of interest to best suit the game’s story and gameplay.

That’s it for me.

Stay tuned for an update on NPCs and monsters!


Related Jobs

Naughty Dog
Naughty Dog — Santa Monica, California, United States
[01.18.18]

Web Developer
Naughty Dog
Naughty Dog — Santa Monica, California, United States
[01.18.18]

IT Help Desk Generalist (Temporary Assignment)
Trendy Entertainment, Inc.
Trendy Entertainment, Inc. — Gainesville, Florida, United States
[01.18.18]

Software Engineer - Game and Online Services
Naughty Dog
Naughty Dog — Santa Monica, California, United States
[01.18.18]

Scripting / Systems Designer (Single Player)





Loading Comments

loader image