We're creating an exciting chess crawler cRPG with souls-like atmosphere and card game combat mechanics!
Genres:
-
Dungeon crawler - core gameplay idea
-
Chess - world setting
-
Card game - combat mechanics
-
cRPG - combat statistics, lore
-
Souls-like - atmosphere
Inspired by games such as:
-
Book of Demons
-
Darkest Dungeon
-
Dark Souls
- Unity 2019.4.15f1
- ProBuilder 4.4.0
- Blender
There is a dev folder and various folders beneath it. While in development, work within these folders, where you'll have complete freedom. When a scene or prefab is ready to be brought into the main project, submit a Pull Request with the asset in the correct folder.
Make many small Pull Requests rather than packing too much code into one branch.
We want every prefab or asset to be able to be used in any scene. If there are steps needed to get it working (initializing variables, etc), document them here under the Mechanics section.
We plan to demo all features weekly.
To keep our code homogenous, we'll use camel case for our variables (fields etc), like so: private bool canAttack;
Variables for lists and lists should be pluralized, even if it makes the variable read awkwardly, like so: List<string> attackTypes
or IEnumerable<PlayerStatistics> playerStats
Of particular note, we learned in Week 1 that due to how Unity works with .meta
files, we should never commit an empty folder to source control. If we do, every other developer will have conflicts.
We are using Github Projects to track issues, which we were previously calling tickets. The link is found here. Each ticket is automatically given a number. When you start working on an issue, create a feature branch in git with the following syntax. You'll also need to assign yourself to the issue in the Issues
tab.
git checkout -b 10-short-description-of-issue
git push -u origin 10-short-description-of-issue
At this point, the branch is both local and is tracked in your fork. You can then freely make changes to the branch and your main
branch will be unaffected.
To keep your fork's main
branch up to date with the central repository, initiate a pull request on Github that brings the current code on sirjust:main
to your-fork:main
. When that is complete, pull the changes into your local main
branch and then merge the main
branch into your feature branch. There are more streamlined ways to do this, but this is the simplest way.
Once you're done working on an issue submit a pull request, and link it to that issue so it can be automatically closed after merging.
- GetVersion.cs - A script that pulls the current build version (We set that in Project Settings under Player tab) and puts it into a transparent text in the bottom left corner. It can for example indicate which version is a screenshot from.
-
Attach this script to the
GameObject
you want to highlight. -
Create a highlight prefab and assign it to the
GameObject
like so. Keep clone empty.
Main Cam
: The camera, whereby the player sees the scenePlayer
: The y-component if the position of this object will be used when generating the grid and instantiate thehighlight
objectTake Object Transform
: An option to take the position of the game object, which has the script, as the start positionDestroy
: An option to destroy thehighlight
objectsGridstart
The start position of the grid(lower right corner)GridSize
: The size of the gridLayer
: Every object with this layer will be ignoredSelectionKey
: The button that must be pressed so that the selected tiles are not destroyedClear SelectionKey
: The button that muss be pressed to delete all selected tiles
Note: The y-value of the Gridstart
variable will be ignored, because we using the y-value of the Player
s position, if the take object transform
option is false
Note: In sone function, you has to use a argument of the type TypesofValue
. This is a enum set, which contains two values:
relative
: the instantiatedhighlight
objects adapt to the rotation of the playerabsolute
: the instantiatedhighlight
object wont adapt to the rotation of the player
Once the scene is started, a grid is created from EditedInvisGridTile objects. Now the script checks whether the player presses a certain mouse button. If this is the case, a raycast is sent from the camera. As soon as this raycast hits an object, it checks whether it is an "EditedInvisGridTile" object. If so, a clone of the 'Hightlight' object is instantiated to the position of the EditedInvisGridTile object.
In this case, I am cloning a quad that is emissive (looks like a highlight).
A library of audio clips that we can call on demand throughout our game. By developing a strong audio manager, we should be able to control different sounds in various ways.
The Audio Manager
prefab should be placed in every scene. It comes with AudioManager.cs
preloaded.
To add your audio clip:
- Increase the size by +1
- Name the added audio element
- Drag your audio clip into
Clip
To play your audio clip on demand, use:
FindObjectOfType<AudioManager>().Play("INSERT_NAME");
We can alter the properties of each audio clip, such as Volume
, Pitch
, or Loop
. If necessary, we can add more parameters to each audio source to have more control. This can be done by altering the Sound.cs
script which displays the parameters in the inspector for each sound.
The battle menu contains several components, which can be used individually until a specific point. Each component adds a functionality to the Battle Menu
Display the Character information(name, picture, health, mana, strength, critRate, dodgeRate, armor) of the last selected character in the scene.
- Attach
CharInfo.cs
to theGameObject
you want to use as a display for the character informations - then assign the different components to the variables under the
Required
header
Display the name and description of the last played card in the scene.
- Attach
SkillInfo.cs
to the game object you want to use as a display for the card informations - Then assign the different components to the variables under the
Required
header
Display the players healthbar and manabar.
- Attach
GetBarInfo.cs
to the game object you want to use as a display the character's health and mana - Then assign the different components to the variables under the
Required
header
Used to draw, display and play cards objects
Note: There is a difference between cards and card objects.
- cards: ScriptableObject which is linked to a card object
- card objects: The whole game Object with additional game objects and scripts e.g UI elements or the
DragDrop.cs
- Attach
CardSystem.cs
to the game object you want to use as container for the cards - Then assign the different components to the variables under the
Required
header
Starting Card Count
: Specify the amount of card objects, which will be created at the beginningMax Card Count
: Specify the highest number of card objects in the handY_start
: Specify the y-coordinate of the instantiated card objects.Gap
: The distance between every card object on the handSelected Pos
: Specify the position which will add to the current Position of the card objects, if the card object is selected
Once the scene starts, the CardSystem.cs
instatiates empty objects. These empty objects (place
) are saved in a list. Afterwards the script spawn a specific amount of card object on the position of the empty objects in the list. In addition all card objects will receive a index which represent the index of the place
which the cards are children of. These place
object and the cards will be saved in a seperate list.
Note: All possible cards which can be played/drawed are saved in the scriptableObject of the player.
In order to use the unity drag and drop functionality, I have to import the different Interfaces( IPointerDownHandler
, IBeginDragHandler
, IEndDragHandler
, IDragHandler
). Each Interface add a new method into the DragDrop.cs
script, which will triggered in the different stages in the drag and drop process. Now I can modify the different methods and add new functionalities in it.
Once the card object is moved the drag and drop process begin and the position of the card object will be saved in a variable called lastPos
. Since the card object is always clicked and selected when moving it, I had to subtract the SelectedPos
from the position.
public void OnBeginDrag(PointerEventData eventData)
{
lastPos = this.transform.position - selectedPos;
}
Now the next stage begins and triggers the OnDrag()
method as long as the player hold down the mouse button. This method add a the delta mouse position to the position of the dragged object.
public void OnDrag(PointerEventData eventData)
{
this.transform.position += new Vector3(eventData.delta.x, eventData.delta.y, 0);
}
When the y-coordinate of the card object is higher than the variable height UI
, then the cast()
will triggered. If this method returns true, then a method named PlayCard()
is triggered in the CardSystem.cs
. Otherwise the position of the card object will be reset to the lastPos
. The PlayCard()
method destroys the card object and moves all other card objects one position to the left.
- Destroys the played card object
- Saves the next card object in a temporary variable called
old_cardObj
- Destroys the next card object
- Instatiated the next card object to position of the new place
- Decreased the index of the next card object
var old_cardObj = places[i].GetComponentInChildren<DragDrop>().gameObject;
Destroy(old_cardObj);
var new_cardObj = Instantiate(old_card.template, places[i - 1].transform);
This process goes through each card until all have been moved
In order to let the cast()
method returns the bool value true
, the player has to select the right tiles and there has to be at least one object which can be detected by a tile e.g a other character object.
After the player selected some tiles and played a card. A method called cast()
triggers. This method checks the currentMana
with manaCost
of the card first and if the user has enought Mana the method going on and compares the positions of the ranges
list with every positions of the selected tile list. Now if the compared tiles has the same position, then method of the skill will be triggered and the cast()
method returns the bool value true
. When there is no matches in the comparison, then the method will return the bool value false
.
As soon as the player presses on the DrawButton
, it is checked whether the maximum number of cards is exceeded or not. If this is not the case, then the PickRandCard()
method is called. This takes an list of cards and randomly picks one. This card is then returned. The linked card object of the returned card will then instantiated in first free place
object.
Note: "Free" means that the object hasnt any card object as a children
The range of every card are saved in the scriptableObject in a list. If the player only clicks on the card object and does not move, it will be selected. This selected card object then will trigger a method called GenerateTiles()
. This method read the saved relative positions in the list of the cards, add them to the current position of the user and adapt these based on the current rotation of the user. After the calculations the method instantiates the highlight
object to the calculated position and save them into another list called rangeTiles
. If the player deselect a card the method called DestroyTiles()
will be triggered, which clears all lists and destroy all highlight
objects.
- Attach the
GetObjectonTile.cs
to the game object which should detect object above him
The script will send a raycast upwards every frame and once the raycast hits a collider, the game object will be saved in a variable called gameObjectOnTile
.
In our case we using this script for the EditedHighlight Quad
object and the EditedInvisGridTile
object .
- In this project we are working with scriptableObjects
- Currently there are two types of scriptableObjects(Character, Card)
- ScriptableObject are containers for different values e.g health or mana cost
- These scriptableObject also contains some other scripts
Skill Name
: The name which will displayed on the skillInfo display(the name doesnt have to be the same as the name of the object)Mana Cost
: The amount of mana which will be consumed if the card Object is playedDamage
: The amount of basedamage. This number will be added to the strength of the userSkill Pic
: The picture which is displayed on the card objectTemplate
: The linked card objectSkill
: The skill which will triggered if the card object is playedMax Amount Of Targets
: The highest number of targets(If the player select more targets, only the first selected will be count)canTargetObjects
: A bool, which determines whether the user is able to select objects e.g enemies as targets or notRanges
: An list of the relative position of the user e.g (1 | 0 | -1) means the tile before the user on the left sideSkill description
: A short description, which will be displayed on the skillInfo display
-
Char Name
: The name, which is displayed on the charInfo display(the name doesnt have to be the same as the name of the object) -
Skill Pic
: The picture, which is displayed on the charInfo display -
Health Representation
: Specify the way how the health be showed in the game. Currently there are two options: None, Healthbar -
Realtion
: Specify the relation to the player. Currently there are three options: friendly, enenmy, neutral
- Game objects in the scene has to have specific scripts to work with the Card System or Combat System
Card
: The linked scriptableObjectheight UI
: The y-coordinate, which has to be exceeded to count the card object as played
Character
: The linked scriptableObjectHave Body
: If the Prefab has a Body like in this example then make a check mark. Otherwise theGetStats.cs
create the prefab, which is saved in the variablemodel
Normal Skills
: Collection of drawable cardsUnique Skills
: Collection of unique drawable cards, which can be only one time at the same time on the hand(has to be in theNormal Skills
list to)
Note: Every character object has to have a collider in order to be detected
- Be sure that you only have one game Object in the scene which the
EditedGridGenerator.cs
script is attached to - The same applies to the
allSkills.cs
- The name of the method and the name of the enums has to be the same e.g
strike()
andstrike
- This variable has to contain a scriptableObject, which was created with the
character.cs
- Be sure that you have one
GameObject
in the scene which theallSkills.cs
,EditedScriptgenerator.cs
,TurnSystem.cs
script is attached to - The name of the method and the name of the enums has to be the same e.g
strike()
andstrike
There is a script called TurnSystem.cs
which governs all player and enemy turns. They are currently divided into four sections which are kept in an enum datatype.
- Player Move
- Player Combat
- Enemy Move
- Enemy Combat
The TurnSystem.cs
script is referenced by the AllSkills.cs
script. When the player moves or strikes on their turn, it invokes the NextTurn()
method in the TurnSystem.cs
script, which increments the BattleStatus
enum.
The turns are cycled through step by step. Since we don't currently have enemy functionality, we log the Enemy Move
and Enemy Combat
steps in the console. When we get to the end of the last step in the enum, NextTurn()
brings us back to the beginning.
-
Attach this script to the game object which should be able to move
-
Be sure that you implemented the
TurnSystem.cs
and theEditedGridGenerator.cs
correctly
Main Cam
: The camera, whereby the player sees the scene
The movement system interacts with the TurnSystem.cs
and as soon as the status
variable is equal to the value PlayerMove
, almost the same thing happens as when selecting a card. The only difference is, that we use the relative position, which saved in the character, instead the position, which are saved in the cards. we using this movement system for the enenmies too, but we have to adapt some point. The enemies will use the same method to move, but the way how to trigger this method will be different.
To adapt the movement and the instantiated highlight
objects to the current rotation of the player, the Update()
method triggers a method called Rotate()
every frame. This method checks wheather the players press specific button, in order to rotate the character object and is this the case, the DestroyTiles()
in the EditedGridGenerator.cs
will be triggered and clears all list and destroys all hightlight
object. Afterwards the character object will be rotate based on the pressed button and the GenerateTiles()
will be method triggered again.