Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

Games Golod: A Dark Fantasy Dungeon Crawler

Discussion in 'Works In Progress' started by Skaggsoft, Aug 30, 2019.

  1. Skaggsoft

    Skaggsoft

    Joined:
    Aug 30, 2019
    Posts:
    12
    Last edited: Oct 8, 2019
    EVECTOR likes this.
  2. owlhowell

    owlhowell

    Joined:
    Jan 2, 2018
    Posts:
    82
    Love the concept art! I'm sure you wear many hats, but what is you primary role for this project?
     
  3. Skaggsoft

    Skaggsoft

    Joined:
    Aug 30, 2019
    Posts:
    12
    Thanks!

    I do the code, the environment models, rigging and animations. The other guy does the all the art, textures and story. I'm sure I've forgotten loads of things, but that's the basic division of labor.
     
    owlhowell likes this.
  4. Skaggsoft

    Skaggsoft

    Joined:
    Aug 30, 2019
    Posts:
    12
    I've uploaded a video which demonstrates some of the mechanics we're using for the skill tree. My video producing skills are still imperfect, but I'm definitely improving!


    I'm gonna start uploading regular videos to Youtube now. Consider subscribing to our channel if you're interested.

    If you're really interested consider backing our Kickstarter: https://www.kickstarter.com/projects/skaggsoft/golod-a-dark-fantasy-dungeon-crawler

    I'll come back in a day or two and post a little about how I'm making things work under the hood.Some of you might find that interesting. :)
     
    owlhowell and msamociuk88 like this.
  5. Skaggsoft

    Skaggsoft

    Joined:
    Aug 30, 2019
    Posts:
    12
    If you get into a fight on the world map you'll be fighting enemies on a screen like this:

     
  6. toastertub

    toastertub

    Joined:
    Oct 28, 2013
    Posts:
    24
    I love how much thought you've put into the skill trees and the way things are going to unlock. And the art looks really awesome so far! I might have missed it but did you say what you're releasing this on?
     
  7. Skaggsoft

    Skaggsoft

    Joined:
    Aug 30, 2019
    Posts:
    12
    Thanks!

    Right now our only planned platform is Windows. We might stretch to Mac and/or Linux at some point in the future but it would definitely be premature to say at this point.

    We expect to release on Steam Early Access initially followed by a DRM-free download once the game comes out of Early Access.
     
    toastertub likes this.
  8. Skaggsoft

    Skaggsoft

    Joined:
    Aug 30, 2019
    Posts:
    12
    Golod's development continues! We've created a Discord server where we post still images, gifs and some stuff you won't see anywhere else: https://discord.gg/XpzhpXW

    Discord Server Example Scroll.gif
    We try to post an update on the Discord at least every 48 hours.

    Dungeon Editing Tools
    Game development is a time-consuming process, but custom development tools can shave off endless hours of tedium in the long run. That's deadly important to us especially, as a team of two.

    I've spent a lot of time over the last few days learning more about editor scripting. My immediate goal is to make the process of dungeon building faster and easier.

    Early Dungeon Editor Inspector Preview.gif
    Early preview of the Dungeon Editor

    This is still rudimentary by comparison to what it's going to become over the next week or two but it's enough to paint dungeon tiles directly into the scene. The walls, floors, etc build themselves according to match their adjacent tiles, which is a real time-saver compared to our old system of just dragging in props by hand and duplicating them. Painting tiles back out is as simple as holding the control key.

    Dungeon Painting Example.gif
    Painting tiles saves a lot of time... it's fun too.

    Through trial and error I've found that the best time to actually re/build the painted tiles is when mouse0 is released rather than the moment every new tile is added. Until the re/build newly-painted tiles are represented using Handles.DrawAAConvexPolygon() so the developer can see what he's doing. It seemed like a compromise at the time, but it actually feels very intuitive in practice.

    I look forward to posting future updates here as I flesh out the Dungeon Editor!
     
    tylerguitar75 likes this.
  9. Skaggsoft

    Skaggsoft

    Joined:
    Aug 30, 2019
    Posts:
    12
    Still working on the dungeon editor; I hope to have a completely workable system by the weekend.

    Usability Improvements
    Dungeon Painting Guide Tile.gif
    The current tile is now highlighted for more accurate painting.

    Dungeon Painting Remove Tiles.gif
    When tiles are painted out a yellow X replaces them until the repaint.

    Height and Depth
    For both cosmetic and gameplay reasons it's important that some tiles have a higher ceiling and/or lower floor than others. The walls, floors and columns use different prefabs at different elevations.

    Dungeon Painting Height and Depth.gif

    Height and depth can be painted directly onto tiles.

    Other Improvements Since Previous Update

    • Tile painting now instantiates prefabs rather than clones.
    • HideFlags are adjusted on tiles and their children to prevent accidental direct editing.
    • Walls and other tile prefabs can be defined at every height/depth or fall back to defaults.
     
    RavenOfCode likes this.
  10. tylerguitar75

    tylerguitar75

    Joined:
    Dec 12, 2011
    Posts:
    41
    This is amazing!! Would love to see how you got the paintable tiles working.
     
  11. Skaggsoft

    Skaggsoft

    Joined:
    Aug 30, 2019
    Posts:
    12
    Thanks man. I'm only a couple days into developing the system right now, but when things are further along I might do a write-up or something.

    Some of the core concepts used in my tile painting system are inspired by a tutorial series I watched recently on Youtube. I'll link it here in case you find it as useful as I did.


    Sebastian Lague makes some of the best Unity tutorials on Youtube.

    I'll walk through the fundamentals of my system below. Remember though, this is still prototype code at this point so don't expect too much.

    Dungeon Tile Painting Prototype
    First I create a GameObject to act as the container for all the dungeon's tiles. To make things simpler this GameObject won't ever have any children except dungeon tiles. I place the Dungeon component on this GameObject.
    Code (CSharp):
    1. #if UNITY_EDITOR
    2. using UnityEditor;
    3. using UnityEngine;
    4.  
    5. public class Dungeon : MonoBehaviour
    6. {
    7.     public GameObject tilePrefab;
    8.  
    9.     public bool HasTileAt(Vector3 position) => Physics.Linecast(position + Vector3.up, position, LayerMask.GetMask("Dungeon Tile"));
    10.  
    11.     public void AddTileAt(Vector3 position)
    12.     {
    13.         GameObject addedTile = (GameObject)PrefabUtility.InstantiatePrefab(PrefabUtility.GetCorrespondingObjectFromOriginalSource(tilePrefab), transform);
    14.         addedTile.transform.position = position;
    15.     }
    16.  
    17.     public void RemoveTileAt(Vector3 position)
    18.     {
    19.         if (Physics.Linecast(position + Vector3.up, position, out RaycastHit hit, LayerMask.GetMask("Dungeon Tile")))
    20.             DestroyImmediate(hit.transform.gameObject);
    21.     }
    22. }
    23. #endif
    All the tile painting logic is simply run off the Dungeon's custom editor. When you drag the mouse through the scene it remembers the tile positions you've dragged through and creates tile prefabs there when you release the mouse, or removes them if control was down when you started dragging.
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.Collections.Generic;
    4.  
    5. [CustomEditor(typeof(Dungeon))]
    6. public class DungeonEditor : Editor
    7. {
    8.     private Dungeon dungeon;
    9.     private Vector3 tileUnderCursor;
    10.     private List<Vector3> tilesPaintedIn, tilesPaintedOut;
    11.  
    12.     private enum PaintingMode { Adding, Removing };
    13.     private PaintingMode paintingMode;
    14.  
    15.     private void OnEnable()
    16.     {
    17.         dungeon = (Dungeon)target;
    18.         Tools.hidden = true;
    19.  
    20.         tilesPaintedIn = new List<Vector3>();
    21.         tilesPaintedOut = new List<Vector3>();
    22.     }
    23.     private void OnDisable() => Tools.hidden = false;
    24.  
    25.     public override void OnInspectorGUI()
    26.     {
    27.         base.OnInspectorGUI();
    28.         EditorGUILayout.Space();
    29.  
    30.         EditorGUILayout.HelpBox($"There are {dungeon.transform.childCount} tiles in this dungeon.", MessageType.None);
    31.  
    32.         if (GUILayout.Button("Clear All Tiles"))
    33.             for (int i = dungeon.transform.childCount - 1; i >= 0; i--)
    34.                 DestroyImmediate(dungeon.transform.GetChild(i).gameObject);
    35.     }
    36.  
    37.  
    38.     private void OnSceneGUI()
    39.     {
    40.         if (Application.isPlaying) return;
    41.  
    42.         Event guiEvent = Event.current;
    43.         tileUnderCursor = MousePositionToTilePosition();
    44.         DrawOutlineAroundTileUnderCursor();
    45.  
    46.         Vector3 MousePositionToTilePosition()
    47.         {
    48.             Ray mouseRay = HandleUtility.GUIPointToWorldRay(guiEvent.mousePosition);
    49.             float drawPlaneHeight = 0;
    50.             float distanceToDrawPlane = (drawPlaneHeight - mouseRay.origin.y) / mouseRay.direction.y;
    51.             Vector3 mousePosition = mouseRay.GetPoint(distanceToDrawPlane);
    52.             return new Vector3(Mathf.Round(mousePosition.x), Mathf.Round(mousePosition.y), Mathf.Round(mousePosition.z));
    53.         }
    54.  
    55.         if (guiEvent.type == EventType.Repaint || Tools.viewTool == ViewTool.Orbit)
    56.             DrawPaintedTiles();
    57.         else if (guiEvent.type == EventType.Layout)
    58.             HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
    59.         else if (guiEvent.type == EventType.MouseDown && guiEvent.button == 0)
    60.             paintingMode = guiEvent.control ? PaintingMode.Removing : PaintingMode.Adding;
    61.         else if (guiEvent.type == EventType.MouseDrag)
    62.             MouseDrag(guiEvent);
    63.         else if (guiEvent.type == EventType.MouseUp && guiEvent.button == 0)
    64.         {
    65.             foreach (var tilePosition in tilesPaintedIn)
    66.                 dungeon.AddTileAt(tilePosition);
    67.             tilesPaintedIn.Clear();
    68.  
    69.             foreach (var tilePosition in tilesPaintedOut)
    70.                 dungeon.RemoveTileAt(tilePosition);
    71.             tilesPaintedOut.Clear();
    72.         }
    73.     }
    74.  
    75.     private void MouseDrag(Event guiEvent)
    76.     {
    77.         if (paintingMode == PaintingMode.Adding)
    78.             if (!dungeon.HasTileAt(tileUnderCursor) && !tilesPaintedIn.Contains(tileUnderCursor))
    79.                 tilesPaintedIn.Add(tileUnderCursor);
    80.  
    81.         if (paintingMode == PaintingMode.Removing)
    82.             if (dungeon.HasTileAt(tileUnderCursor) && !tilesPaintedOut.Contains(tileUnderCursor))
    83.                 tilesPaintedOut.Add(tileUnderCursor);
    84.     }
    85.  
    86.     private void DrawOutlineAroundTileUnderCursor()
    87.     {
    88.         Handles.color = Color.white;
    89.         Handles.DrawAAPolyLine(4f,
    90.             new Vector3[]{
    91.                 new Vector3(tileUnderCursor.x - 0.5f, 0, tileUnderCursor.z + 0.5f),
    92.                 new Vector3(tileUnderCursor.x + 0.5f, 0, tileUnderCursor.z + 0.5f),
    93.                 new Vector3(tileUnderCursor.x + 0.5f, 0, tileUnderCursor.z - 0.5f),
    94.                 new Vector3(tileUnderCursor.x - 0.5f, 0, tileUnderCursor.z - 0.5f),
    95.                 new Vector3(tileUnderCursor.x - 0.5f, 0, tileUnderCursor.z + 0.5f)
    96.             });
    97.     }
    98.  
    99.     private void DrawPaintedTiles()
    100.     {
    101.         if (paintingMode == PaintingMode.Adding)
    102.             foreach (var tile in tilesPaintedIn)
    103.             {
    104.                 Handles.color = Color.gray;
    105.                 float handleSize = 0.48f;
    106.                 Handles.DrawAAConvexPolygon(
    107.                     new Vector3[]{
    108.                         new Vector3(tile.x - handleSize, 0, tile.z + handleSize),
    109.                         new Vector3(tile.x + handleSize, 0, tile.z + handleSize),
    110.                         new Vector3(tile.x + handleSize, 0, tile.z - handleSize),
    111.                         new Vector3(tile.x - handleSize, 0, tile.z - handleSize)
    112.                     });
    113.             }
    114.  
    115.         if (paintingMode == PaintingMode.Removing)
    116.             foreach (var tile in tilesPaintedOut)
    117.             {
    118.                 Handles.color = Color.yellow;
    119.                 Handles.DrawAAPolyLine(4f,
    120.                     new Vector3[]{
    121.                         new Vector3(tile.x - 0.5f, 0, tile.z + 0.5f),
    122.                         new Vector3(tile.x + 0.5f, 0, tile.z + 0.5f),
    123.                         new Vector3(tile.x + 0.5f, 0, tile.z - 0.5f),
    124.                         new Vector3(tile.x - 0.5f, 0, tile.z - 0.5f),
    125.                         new Vector3(tile.x - 0.5f, 0, tile.z + 0.5f),
    126.                     });
    127.  
    128.                 Handles.DrawAAPolyLine(4f,
    129.                     new Vector3[]{
    130.                         new Vector3(tile.x - 0.5f, 0, tile.z + 0.5f),
    131.                         new Vector3(tile.x + 0.5f, 0, tile.z - 0.5f)
    132.                     });
    133.  
    134.                 Handles.DrawAAPolyLine(4f,
    135.                     new Vector3[]{
    136.                         new Vector3(tile.x + 0.5f, 0, tile.z + 0.5f),
    137.                         new Vector3(tile.x - 0.5f, 0, tile.z - 0.5f)
    138.                     });
    139.             }
    140.     }
    141. }
    142.  
    143.  
    That's enough to paint tiles directly into the scene. Of course there's more to my system than that (height, depth, rebuilding the tiles automatically, etc), but I'll write that stuff up a few days from now when it's more polished.

    I've attached a package to this post which contains the above code and an example scene.
     

    Attached Files:

    tylerguitar75 likes this.
  12. Skaggsoft

    Skaggsoft

    Joined:
    Aug 30, 2019
    Posts:
    12
    I spent yesterday rigging and animating the newest monster.

    I've decided to start recording timelapses of that process from now on:


    Just playing idle animations in a straightforward loop would get boring pretty fast so I decided to separate the animations into layers (eyelids, jaw, everything else) and update them via script. This really sells the idle cycle as a natural animation.

    Now I can get back to working on the dungeon editor!
     
    eaque likes this.