Day 1: Design Document and Project Scope
Today, we defined our learning goals, specified the scope of the project, setup a unity project, class class library project, xUnit test project, and defined a few interfaces: ISkilledEntity
, ISkillNode
, and ISkillTree
.
Table of contents
Today’s Tasks
-
Define Learning Goals and Scope Document -
Setup Libs / Unity Project / Dependencies -
Start interface definitions
Learning Goals
We began by defining a “Learning Goals and Scope” document.
For those who are not fluent in chicken scratch, let me translate for you:
- Visualization for Graph Data Structure
More specifically, I would like to be able to generate a UXML file representing a defined Skill Tree that can then be modified in the UI Builder.
- Exploring Generics to Generalize the SkillTree library
More specifically, can we discover and define what the reusable components of a skill tree system exist. This is challenging because there are vastly different skill trees. In our version, we will be implementing a specific implementation.
- USS Variables
We have yet to use style sheet variables in our previous projects. It would be great to find a good spot to use one.
Project Scope
Once again, let me translate:
The primary goal of this project is to implement a re-usable skill tree system in 6 days! I estimate that we will have roughly 14 hours of “working” time while streaming.
The Skill Tree system we will implement will have the following properties:
- Nodes representing skills with names and descriptions
- Each Node has children which require the parent node to acquire
- In addition to the parent node requirement, they may specify additional requirements
- If a single node has two parents, both parents are required
With this in mind, the following scope was defined:
-
ISkill
- An interface representing the idea of a skill. A skill simply provides a name and a description. -
ISkillNode
- An interface which represents the idea of a skill within a tree. It contains methods for checking if a character meets the requirements for acquiring the skill as well as children information. -
ISkillTree
- An interface which has access to the rookISkillNode
. -
ISkilledEntity
- An interface which represents an entity that can acquire skills. This interface tracks the skills that a character has acquired thus far.
That’s it for this project! We intentionally kept the scope small to hopefully ensure that we can finish in the short time period.
Project Setup
With our learning goals defined and a scope in mind, it was time to set up the project so we could actually code.
In the crafting system we learned that we could utilize C# 11 (or another language version) in our non-unity related code by creating a project outside of Unity and adding in a compiled dll to the Unity project. Additionally, this speeds up Unity compile times and helps to keep our code organized for more general reuse purposes. With this knowledge available, we started by adding a submodule to our project referencing the CaptainCoder.Core that was created during the last project.
More specifically, we created a branch that we could use while working on the inventory system. At the time of writing, that branch was available here: grid-based-inventory. However, it should be merged in to the main branch after the inventory system is completed and the link may not work at a later date.
Another benefit gained by defining the non-unity portions of the project outside of Unity is that we can more easily utilize different testing frameworks such as xUnit. In Unity, the main (and only?) testing framework is nUnit which is fine but not my personal preference.
Lastly, we put together a simple build script that will build and add the compiled dlls to Unity when changes are made to the project code:
#!/bin/bash
dotnet build CaptainCoder.Core/ -c Release
CORE_PATH="CaptainCoder.Core/CaptainCoder/Core/bin/Release/netstandard2.1"
CORE="CaptainCoder.Core"
SKILLTREE_PATH="CaptainCoder.Core/CaptainCoder/SkillTree/bin/Release/netstandard2.1"
SKILLTREE="CaptainCoder.SkillTree"
UNITY_DLL_PATH="Unity Skill Tree/Assets/Plugins/CaptainCoder"
cp "$CORE_PATH/$CORE.dll" \
"$CORE_PATH/$CORE.xml" \
"$SKILLTREE_PATH/$SKILLTREE.dll" \
"$SKILLTREE_PATH/$SKILLTREE.xml" \
"$UNITY_DLL_PATH/"
Start Interface Definitions
With our project definitions ready to go, it was time to implement the interfaces that we would use for the ISkill
, ISkillNode
, ISkillTree
, and ISkilledEntity
:
/// Represents a skill
public interface ISkill
{
/// The name of this skill
public string Name { get; }
/// A description of this skill
public string Description { get; }
}
/// An <see cref="ISkilledEntity{T}"/> represents an entity that can acquire
/// skills of the specified type.
public interface ISkilledEntity<T> where T : ISkill
{
/// A HashSet of skills that this entity has acquired
public HashSet<ISkillNode<T>> Skills { get; }
}
public interface ISkillTree<T> where T : ISkill
{
/// The root node of this skill tree
public ISkillNode<T> Root { get; }
}
/// Represents a skill node within a skill tree.
public interface ISkillNode<T> where T : ISkill
{
/// A list of requirements that must be met to gain this skill
public IReadOnlyList<IRequirement> Requirements { get; }
/// A list of children skill nodes
IEnumerable<ISkillNode<T>> Children { get; }
/// Checks if the specified <paramref name="character"/> meets the
/// requirements to acquire this skill.
public bool CheckRequirements(ISkilledEntity<T> character)
{
foreach (IRequirement req in Requirements)
{
if(!req.MeetsRequirement(character)) { return false; }
}
return true;
}
/// A Requirement acts as a predicate on a character.
public interface IRequirement
{
/// Checks if the specified <paramref name="character"/> meets this
/// requirement.
public bool MeetsRequirement(ISkilledEntity<T> character);
}
}
And that was it for today! With these data types in place, we should hopefully be able to write a relatively straight forward implementation tomorrow and spend the remaining time focused on developing the UI interactions. Will we be able to do it? Only time will tell! See you tomorrow!
Join the Discussion
Before commenting, you will need to authorize giscus. Alternatively, you can add a comment directly on the GitHub Discussion Board.