Unity Learn Tutorials – Artificial Intelligence for Beginners and Intro to Optimization

February 7, 2020

Unity Learn Tutorials

Note: The AI tutorial require Unity Learn Premium to access
Artificial Intelligence for Beginners

Tutorial Series #1 – Link

By: Penny de Byl


Introduction to Optimization with Unity – 2019.3

Tutorial Series #2 – Link

By: Unity Technologies


Notes

These were both tutorial series I saw on Unity Learn that I wanted to note specifically to check out later. The Optimization tutorial is a very small series, so I can look into that rather quickly, but the AI series is a 15+ hour comprehensive class so that will take a large commitment to fully cover.

The AI series however is something I am interested in in general and even covers some topics I am specifically looking into at this time. Some of these topics include: Navigation Meshes, Crowd Simulation, State Machines, and Goal Driven Behavior. This would be very good to follow for my own personal interests as well as possibly being useful for some projects I am looking to work on.

GDC 2020 Talk – Cursed Problems in Game Design

February 6, 2020

Cursed Problems in Game Design

GDC 2020 Talk

GDC 2020: Cursed Problems in Game Design

Video – Link

By: GDC – Alex Jaffe (Riot Games)


Notes

Cursed Problem: an unsolvable design problem, rooted in a conflict between core player promises

Politics: competition through social negotiation, alliances, and manipulation

The main skill here is identifying cursed problems so you know to avoid them or navigate them so you do not waste time on “solving” them.

Examples from Talk: Hard or Cursed?

No Man’s Sky: Exploration game with millions of worlds
Hard: This was evidenced by the game becoming successful after significant time updating the game, but it easy to see this was just a hard problem and not an impossible one.

Diablo: Loot games with efficient trading
Cursed: Many loot experiences are just incompatible with efficient marketplace trading systems because the loot experience relies on the random drops themselves feeling unique or special to the player, but having a market to deal this loot for other loot just makes every type of loot “gold”, or currency, and the specialness of all drops is significantly hampered.
Commodified Reward Problem supports this idea.

Pokemon GO: always-on location-based games
Cursed: These games look to provide an augmented reality layer to real life for rewards, but the counteracting topic is just the general need for personal safety and convenience. The main core of it being cursed is that one is “play anywhere/any time” and the other to make them safe is to “only play when appropriate”.

4 Core Solution Techniques for Cursed Problems

The 4 techniques are: Barriers, Gates, Carrots, S’mores

Barriers

Cut affordances that break promises

This technique focuses on just preventing the player from performing actions that would break the design promise.

Exapmle: Free-For-All Politics (Fortnite, or any large battle royale game)
Approach: Limit player’s agency over one another
Sacrifce: Some of the PvP fantasy of control
The game is so large scale with so many players, high amount of missing information, and high lethality so the political game is not very feasible to develop. It is hard to create an alliance or single out a specific targeted player with all of these variables. This however removes the feeling of “I have outplayed you specifically” or the personal level of domination since the game is so large scale.

Gates

Hide bad states behind challenge

This technique aims to make it harder to find bad ways to play the game so that players will hopefully focus on the good ways intended.

Example: Free-For-All Politics (Playstation All Stars: Battle Royale (4 Player Brawler))
Approach: Limit visibility of players’ success
Sacrifce: Some of the tension of buzzer beaters
They hid the score of each player, and made the scoring system a bit convoluted (2 * kills – deaths) so it was harder to reason out in the middle of the high paced game. This was done to encourage every player playing their best with less fear of being targeted for being in the lead and reduce politics factors. Not being sure of the score however can reduce high tension moments near the end of the game sine no one is really sure who is in the lead and you do not even know who won until they game tells you.

Carrots

Incentivize avoiding the bad states

Provide incentives for players that do not go into the bad game states.

Example: Free-For-All Politics (Catan tournament)
Approach: Add meta-game effects
Sacrifice: Magic circle of an individual game
In a Catan tournament, players play many games and their standings are used to add to their total score for placement. This makes getting first less of a “be all, end all” scenario and incentivizes each player to just do as well as they can. They suggest this ends up reducing overall politics in the game since players are continually incentivized to do their individual best. The con however is that it just makes each individual game feel less special or “magical” to play.

S’mores

Make it fun

This technique leans into the bad states of the game and just make them fun to play as well.

Example: Free-For-All Politics (Diplomacy)
Approach: Give players tools for deep political play (e.g. secrecy)
Sacrifce: Emphasis on moment-to-moment action
The game of Diplomacy goes hard into the politics with secrets and deception along with the gameplay, which can make the political aspects more fun and interesting. This however generally makes the game itself feel like it is taking a backseat (in this case your plays with your units) and leaving players mostly focusing on the relationships they make or break along the way.

Summary

Do not think of these as solutions, but as a small design framework. These techniques were identified to help you approach difficult problems you find in the design process for making a game to help you navigate them more efficiently. It can also just be beneficial to understand some problems are not “solvable” and you will have to make sacrifices to accomplish some goals or mitigate some negative aspects.

Challenges

These were some challenges given as examples of problems so cursed that they really have not been approached very much.

These are the challenges:

  • Balanced player-generated content in multiplayer games
  • PvP games in which all players feel there was a just outcome
  • Mystery and discovery in the age of the internet

The last challenge really resonated with me as something I have investigated, specifically through the concept of procedural content generation.

As an avid Pokemon player I would always go into the new games knowing every new pokemon from information released before hand, whether it was from strategy guides back in the Johto days to the games in the Alola region. I however stumbled upon player made rom games and played them mostly blind and enjoyed them much more. The sense of discovery and figuring things out was so much more interesting and refreshing.

I then got into Pokemon randomizers where you can randomize as much or as little as you want, and that game fresh new life to old games I had played. This gave me the idea for using procedural generation, something akin to the rogue likes of today, but in a more exploratory or experimental way. I think you could look into procedural generation of the rules of the game as opposed to just specific content, and the player could have consistent ways to discover these rules playing the game each time. This way the player’s skill of discovery is really what is emphasized and rewarded as they get better, and they use this core skill to get better at whatever world they are put into.

Exploring NavMesh Capabilities

February 5, 2020

NavMesh

Unity Tutorials

Unity NavMesh Tutorial – Basics

Tutorial #1 – Link

By: Brackeys


Navigation Mesh Basics | Unity AI Pathfinding (Part 1) | Table Flip Games

Tutorial #2 – Link

By: Table Flip Games


Use Unity3D NavMeshAgent.Move to customize your navigation control

Tutorial #3 – Link

By: Jason Weimann


Crowd Behaviours on a Dynamic Navmesh in Unity Part 1

Tutorial #4 – Link

By: Holistic3d


Notes

I am looking to explore Unity’s NavMesh to see what features it has to compare with A* Pathfinding, especially my setup I worked on specifically. I want to see the benefits it readily provides over A* as well as see if I can find any useful features that could be implemented in some way into A*.

Tutorials 2 and 4 both are the beginning of series so they can be useful for exploring deeper into NavMesh. Jason Weimann in tutorial 3 is also generally a good source for exploring features more deeply at a more advanced level.

Thesis: Starting Table of Sources for Related Works and Background Section

January 27, 2020

Thesis Paper

Related Works and Background Table

SUMMARY

The newly named Related Works and Background section for my thesis paper contains a lot of references to my many sources and how they connect with my research and project. We are now looking to add a table to this section to help organize all of these sources and show the reader more clearly what each source did and how it was incorporated into my thesis. As of now there are slightly over 30 sources referenced in this section, so I have only started to create this table.

Since the table is still in the early drafts, it uses a bit of short hand. There are eight columns: Source, Title, Method, Game, Study, Results, Provide, Other Notes. This is the breakdown of what those sections each entail (the parenthetical is the general question that section looks to answer, and the following text is more description for clarification):

  • Source – (What is it?) This is my latex name for the source
  • Title – (What is it?) Title of the research paper, article, etc.
  • Method – (What is the interesting aspect?) Ex. PCG Technique, Theoretical Framework, etc.
  • Game – (What game did they use/develop, if any?)
  • Study – (How did they do their research?) What tests did they perform/how did they reach their conclusions?
  • Results – (What did they acheive?) Their findings and conclusions from their research
  • Provide – (What did it provide to our project/research?) How did this source influence our research or how the project was designed
  • Other Notes – Extra notes that won’t be in the final table but are useful to keep in mind when putting it together or may be used in the table instead of something else

The image quality is not very good but that was as good as I could get it for Blogger at this time.

Image of Table in Current State

By: Me – Table for Thesis Related Works and Background Section Describing Sources Referenced

Building Unity UI that scales for a real game – Prefabs/Scenes? by Jason Weimann

January 24, 2020

Unity UI

Scaling and Scenes

Building Unity UI that scales for a real game – Prefabs/Scenes?

Youtube – Link

By: Jason Weimann


Notes

UI is a big part of a lot of games, so it is something that is always good to learn more about. This also deals with using UI that works across multiple scenes, so this could possibly be another route to take when dealing with the new scene management techniques I have looked into.

Thesis – HFFWS Project Update – Finishing/Fixing Foundation of Pulley Scenarios

January 17, 2020

HFFWS Generation System

Fixing Pulley Scenario Foundation

Pulley Scenario Issues

Not Producing Designated Number of Scenarios

This was working before, so it was weird that the issue came up for all three pulley options after updating, including the original scenario I worked on, HeavyDoor. I found that the wheel positioning method was getting an array index error, so I focused around there.

Instances where just one wheel needed to be created seemed to actually work fine, so there was something about creating multiple wheels that was causing an issue. I looked into what was happening after the first wheel was created, and there is a method dealing with the list of weighted ranges that can remove a range without adding any new ones after choosing a position (this option exists for when a chosen position is within the buffer range on both sides of it to other taken positions, or ends).

It would make sense that we get an indexing error if we started with one range (which it always does), but then because of the chosen parameters, removed that single range from the list. This appeared to exactly be the case. The generated ropes weren’t long enough, so choosing a single position with the given buffer ranges was effectively taking up the whole rope, so there were no valid positions left, giving an error and ending the cycle of generating scenarios.

As a quick fix just to continue testing, I simply changed the parameters to only give longer ropes and this removed the error completely. To at least help notify the user of this problem in the future, I added a Debug.LogError if the range list is empty but the system tries to find a new position. This will be something I will need to come back to later to increase the intelligence of the system to so that it itself modifies either the length of the rope to fit the chosen number of wheels, or reduces the number of wheel options depending on the rope size (most likely the latter choice).

UnityLearn – Beginner Programming – Creating a Character Stat System – Pt. 01 – Overview and Creating Scriptable Objects

January 8, 2020

Beginner Programming: Unity Game Dev Courses

Beginner Programming: Unity Game Dev Courses

Unity Learn Course – Beginner Programming

Project Overview

General Overview of Creating Character Stat System Tutorials

  • Defining and Configuring scriptable objects
  • Accessing data inside of scriptable objects
  • Setting up helpful debugging items
  • Scriptable objects inside of monobehaviours

Creating Scriptable Objects

Scriptable Objects Explained

Scriptable objects are very effective for creating designer tools.

Systems Map: image showing the separate pieces of the game system and how they all connect, in a web-like design

SCriptable Objects: data containers of which, we can have multiplie instances

  • Defined by programmer
  • Treated as assets in Unity
  • Easy for designers to work with
  • CANNOT be added to gameObjects as components

The basic template for turning a script to a scriptable object is adding a [CreateAssetMenu()] header to the top of the script and having the class inherit from SCriptableObject. The CreateAssetMenu header is what adds the scriptable object as an option in Unity’s own Asset Menu at the top of the screen. This also holds the information on how it is displayed there.

Again, it is important to note that scriptable objects CANNOT be added to gameObjects as components. This is worked around in the tutorials however by adding them as a field to a Monobehaviour that is located on a gameObject.

Debugging the Aggro Radius

This segment mostly dealt with importing the project if you had not already, and doing some folder organization for these tutorials. They also added a bool to control showing aggro radius of enemies.

Building Your Scriptable Object

The first scriptable object they create is called CharacterStats_SO.
The CreateAssetMenu tag used at the top of the script is directly used to store this information in an item in the drop down menus of Unity itself. This is why there is a fileName and a menuName.

MenuName: This will be the string seen in the drop down menus directly. You can also add a “/” to create a chain of drop downs where the item will be located.

The fields used for CharacterStats_SO:

  • bool setManually: this will determine if the stats were created manually, or created dynamically
  • bool saveDataOnClose: this will determine if data should be serialized, or written to disk, on close
  • The rest are just general player stats fields (health, damage, resistance, etc.)

SUMMARY

These tutorials were just the tip of getting introduced to scriptable objects in Unity. The rest of the tutorials in this set will delve deeper into the topic and how to incorporate them into other Monobehaviours.

A* Pathfinding: Debugging Special Cases

December 19, 2019

A* Pathfinding

Debugging Special Cases

ISSUES

Getting an Index Out of Bounds Error in EnemyBasicMovement Script

Error happening on this line:

Vector3 direction = (path.lookPoints[0] – transform.position).normalized;

Suggests that the very first point in a path does not exist, so somehow empty paths are being passed through the system.

Test 1: Increase A* Grid Size to Cover Entire Play Area and Spawn Points

Some of the spawn points are a bit off of the normal play area, so I made sure to cover anywhere the units could possibly exist with the A* grid so they always had a node to latch onto (even though I believe the clamping should cover this error). This did not end up being the issue as the error persisted.

Test 2: Increase Size of Walkable Plane Over Entire Play Area

Similar to the logic of Test 1, I just wanted to make sure the nodes were not not being created because the units were missing some usual piece of information they would have to make them. Turns out this was not the issue either.

Test 3: Make Sure Target is Set Before Instantiating the Enemy

I thought maybe a path was being created before the unit had a target, which could make sense for creating a path with size 0. I did this by having the pathing script disabled initially, and making sure the spawner passed in the target information BEFORE it activated the script. The error continued though.

Test 4: Do Not Move the Target to See if Error Exists

It seemed like most spawns didn’t get errors if the player did not move, so I moved the one spawn that basically did not have to move to reach the player’s x position and tested what happened without the player moving (The X position counted as “very close” to the player at this time since I still had some of the issues with converting between 3D and 2D coordinates). There were no errors at all when not moving the target during the game.

DETERMINED ISSUE

Something about the paths updating later in the units’ lives was creating these size 0 paths.

Test 5: Is Spawning Causing the Issue

I was not sure if spawning the units was somehow causing the problems still, so I just placed 4 of the unit prefabs randomly about into the scene initially and stopped the spawners. This did not get rid of the error, and had the units return to moving in big circles still.

Further Info

This was giving me a lot of trouble, so I went back to following the path of logic to see why it would be producing these 0 count paths.

  • OnPathFound method in EnemyBasicMovement is being passed an empty array of Vector3[] waypoints
  • PathRequestManager class calls this method through its own FinishedProcessingPath method
  • OnPathFound is the method assigned to the callback Action for the PathRequest object
  • PathFindingHeap is creating an empty waypoints array somehow

The zero count path is being created in PathFindingHeap somehow. This should be impossible as every path should at the very least have the start node and the target node, which would be a count of 2.

    Within PathFindingHeap

  • RetracePath takes in a startNode and endNode to create the entire path of nodes between them
  • In the problem case, a new path has been created when the target is only a single node away from the pathfinding unit’s current position
  • there is a while loop that runs until it hits the startNode, so in this case, it only runs a single time (since the only nodes are the startNode and the endNode), creating a single waypoint
  • this creates a path with a count of 1
  • then the SimplifyPath method takes in this path
  • SimplifyPath creates a new List of Vector3 to fill with only necessary waypoints
  • it does this by taking points from the passed in path, but it looks through this with a for loop which starts at i = 1 and ends at i < path.Count, because it needs a previous point to compare to since it is doing a directional check
  • since the path.Count is only 1 here, the for loop never runs, and we return an empty set of waypoints
  • Can possibly solve with a special case since a path of 1 node is also a most simplified case

Test 6: Add Case In Simplify Path to Deal with Receiving One Node

I just added a check case before the normal logic that if the input path for SimplifyPath was only 1 node, it would just use that node as the path. This reduces the number of errors significantly, but there are cases where even the base path passed into SimplifyPath has 0 nodes.

DETERMINED ISSUE

The PathFindingHeap RetracePath method is creating paths with 0 nodes when Unit is close to target. As a result, SimplifyPath also makes 0 count paths. The only way this can be the case is if the startNode == endNode, so this must be happening when a new path is being created even though the unit and its target are already considered to be on the same node. This leads me to believe it is an issue with the difference between the node size and the distance the target has to move before looking for a new path (pathUpdateMoveThreshold in EnemyBasicMovement).

Test 7: Reduce NodeRadius to Half (or Less) of Update Path Threshold

Originally the values for pathUpdateMoveThreshold and the nodeRadius were both 0.5, which lead to a overall node size (nodeDiamater) of 1.0. I reduced the nodeRadius to 0.25 (which gives them a total nodeDiameter of 0.5), so this was at or below the threshold.

SOLVED

This completely removed the errors from happening (I add mostly because I am unsure if there exists a case where having the nodeDiameter exactly equal the threshold could cause an error).

SUMMARY

There was a lot of going back and forth to figure out where this error was coming from, and it was even harder since I was having some other issues since I had not fully converted the 3D system to the 2D system. As far as I can tell, this should cover most of the strange cases the pathing should run into even with an updating target (which should mostly be extra for my purposes anyway). I should add a check between the node size and the update threshold to make sure that issue does not happen again.

A* Pathfinding: Edit for 2D

December 19, 2019

A* Pathfinding

2D Conversion

ISSUES

Pathing In Circles Away from Target

They move in a large circle around the entire game area. They go in a half circle consistenly then stop in about the same place everytime (either directly above or below the middle of the play area).

Test 1: Tone Values Down

I tried toning all their numbers down since my game area is relatively small in case they were just constantly over shooting node targets, but this did not change the behavior.

I think the direction I am aiming and moving them must be incorrect with how I changed the Vector math from 3D to 2D.

DETERMINED ISSUE

They can only respond to the player’s X position. If the player moves, the properly oriented ones will move slightly to keep at the same X value, whereas those facing the other direction will travel in a large circle to reach the same X value (since I guess they cannot rotate very easily).

Test 2: Edit Rotation Calculation

I just needed to remove an extra (-90) that was being applied to the rotation vectors for aiming them at the target. This completely fixed the issue for their initial movement, but they only move in the x direction after that initial reaching of the target now.

DETERMINED ISSUE

The target position is not changing its Y value for some reason, only its X value.

Next Steps

Either their rotation is messed up (so moving right only moves them along x axis) or the overall translation is messed up and is only moving them left and right. It could be another z/y conversion error somewhere.

Test 3: Change NodeFromWorldPoint Method to Use worldPosition.y instead of z

It looks like PathFindingHeap was using AGrid NodeFromWorldPoint function to determine the proper node from world points, but this was using the z value of the Vector3 input as to determine the y coordinate in the overall grid. This is why it was constantly hovering at the same low Y value, because those were the nodes that correlated with a z input of 0.

SOLVED

These combined edits fixed the pathfinding logic completely. They now constantly followed the target position properly and it updated accordingly.

How Command & Conquer: Tiberian Sun Solved Pathfinding: War Stories: Ars Technica

December 18, 2019

War Stories

How Command & Conquer: Tiberian Sun Solved Pathfinding

How Command & Conquer: Tiberian Sun Solved Pathfinding | War Stories | Ars Technica

Link – Video

By: Ars Technica


Working on Pathfinding

Pathfinding, especially in a dynamic sense, is still a relatively expensive process to run. This is much more so when you are trying to apply it to a lot of units.

Tiberian Sun was running into a lot of issues they called “Artificial Idiocy”, which is when your AI just does really dumb stuff. Really illogical AI from a player’s game units very quickly make the player mad and aggitated. They say “If you spend more time making sure it doesn’t do something stupid, it will actually look pretty smart”. And to follow up, they didn’t need perfect pathfinding, they just needed “not stupid” pathfinding.

Some of their fixes included not accounting for the collision of other friendly units selected to move and wiggling stationary friendly units when encountered by moving friendly units. Not accounting for other selected friendly units made sense since most likely they would also be going to about the same place and would generally be out of each others’ ways. The wiggling was added as very simple to execute logic in hopes that it would “unlock” a path previously obstructed by the stationary units.

SUMMARY

This was just a cool video I stumbled upon pretty randomly. It was very interesting to see some of the “behind the scenes” for one of my first favorite computer games to play a long time ago. There are just so many things you take for granted that took a lot of hard work and were almost revolutionary for their time.

It is also interesting to see that some problems still exist to a degree, like the prcoessing intensity of dynamic pathfinding. I think my research in pathfinding recently is what brought this video recommendation to me on Youtube, so I have at least had a small taste of the pains they went through developing that. I also really like their thoughts on just minimizing the terrible choices of AI instead of maximizing its “smart” moments to make it nicer to work with and really look smarter in the end.