Issues with Intellisense in Visual Studio in Unity

December 10, 2019

Unity and Visual Studio

Intellisense Issues

Good Solution Options for Unity / Visual Code Intellisence Issues

Link – Possible Solutions

For some reason Visual Studio 2019 does not want to use Intellisense properly on the HFFWS project when using Unity commands. It still autocompletes some general stuff that I assume is more generally C# focused, but methods like Start, Awake, OnCollisionEnter that are Unity specific do not complete. They still work and run fine, but the autocomplete feature is missing.

I tried circumventing this by going back to Visual Studio 2017 as the code editor and it worked totally fine. This points to it being a VS 2019 issue directly, but it could also be how it interacts with Unity in general. I have to use an older version of Unity (2017.4.13f1) so maybe that has something to do with the issues that come up.

People run into this issue all the time for various reasons, and I have tried a lot of their solutions to no avail.

Moving the Script into the Project (Out of Miscellaneous Files)

Sometimes when you create a new C# script, it gets sent to Miscellaneous Files intstead of into your actual project. This completely removes its connection to Unity, so the intellisence autocomplete tends to break here. I have fixed this and the files were either moved back to the C Sharp Assembly or are now automatically put there again, so that is not my current issue.

Have the Unity Dev Tools Installed in VS

It should be a given I have this since I have used VS 2019 on other projects before and recently without issue, but I double checked that I have this installed as well. This is indeed still there, even found when using it for the HFFWS project which it is not working for.

Nuget Packages

This is something I was unclear with and do not think I was successfully able to even implement this as a recovery method. I never directly dealt with them initially to setup VS with Unity, so I was unsure if this would even be helpful for me when I have these issues later down the road.

Delete Visual Studio Generated Files

I went to the root folder of my Unity project to find the Visual Studio generated files to delete them. These are the .csproj, .sln, and .user files found there. I only had 2, the general solution file and a single .csproj file. I deleted both of those and restarted Unity and VS but it had not changed.

Reimporting Files

The easiest way to attempt this large scale is to just reimport the entire project. For bigger projects, such as this HFFWS project though, this can take a pretty long time. I tried a smaller scale approach by just reimporting my scripts folder but this gave me no results either.

Unloading/Reloading the Project Files

I tried unloading the C Sharp Assembly file and reloading it. I also tried unloading and reloading a few of the individual scripts themselves. This can sometimes fix the connection, but this also did not work here.

Sebastian Lague A* Tutorial Series – Weights – Pt. 06

December 9, 2019

A* Tutorial Series

Pt. 06 – Weights

A* Pathfinding (E06: weights)

Link – Tutorial

By: Sebastian Lague


Intro:

Weights are exactly what I am looking for to influence the intelligence of the units in my project. They are an additional factor for moving in certain areas to make them more or less “appealing” to the AI to further influence their movement. This makes their movement more interesting than the simple “point A to point B” shortest distance.

When importing the Road object, I had to scale mine up (x5) to fit my scene like the tutorial. Unsure if they changed the size of their scene at some point, so this may impact the way the units travel so it is important to keep in mind.

This system is going to have the grid use a bunch of raycasts to see what they collide with to determine what type of terrain is in which area. The ray will return information on what terrain was hit, and this will relay the penalty information back to that specific grid location.

Node

This class just had an int field added to it to hold the movement penalty value. While small, this is really the main piece of information that will allow everything else to work properly.

AGrid

They added a new class, TerrainType, to hold information for the various terrains. This included a LayerMask field and an int field for the penalty value. The AGrid class itself then holds an array for these TerrainType objects so that the type and its corresponding penalty can be set in the Inspector. They noted that the LayerMask field here can have multiple layers set as usual, but make sure to NOT do this currently as it will mess up the current code.

(Much more code can be added to handle this, but they just wanted to do the simple setup for now)

They wanted to create a single LayerMask variable that held all the values of the masks within the TerrainType array. Unity uses bit masks for their layer mask system, so doing this required some weird syntax:

foreach (TerrainType region in walkableRegions)
{
//walkableMask.value = walkableMask | region.terrainMask.value;
walkableMask.value |= region.terrainMask.value;
}

The commented out section is the general concept of what is happening, and the uncommented section is just a short hand notation of doing the same thing. It uses a bit-wise OR operator to “add” the values together into a single layer mask.

Finally, in an attempt to provide some optimization to this system, they created a dictionary to hold information on all of the layers in the walkable regions. As the TerrainType array was added to the overall walkableMask, they were also added into a dictionary where the first value is the layer number and the second value is the movement penalty. Then when the raycasts were run, they just had to check this dictionary with the layer number they received so they could return the proper movement penalty value.

Summary

While I am not sure if this is exactly how I will be looking to use weights in my own system, it was still very helpful to see one way of approaching it. This method focused on the movement penalty being an inherent property of the type of ground, where I am looking for something that can update in the same area over time depending on other factors (such as learned danger of an area). At the very least, the math for factoring in the new penalty costs will most likely remain pretty similar in most approaches.

HFFWS Generation System Overview Update

December 5, 2019

HFFWS Generation System

Overview Update

General System Overview

I have updated my thoughts on setting up the overall system to fit the demands for my thesis as well as to keep everything more organized and readable. I am sure as I go through building this I will find ways to cut out levels of inheritance or add scripts for readability, but this is the most recent view on everything. I want the highest level to be very general (DemoManager), the middle level should be where the majority of parameter ranges and interactive placement between objects should be (ScenarioManager’s), and the lowest level will be in charge of putting together the needed objects within the bounds dictated by the higher levels (Create classes).

This image just shows the general idea of the overall hierarchy (the actual number of ScenarioManagers and Create classes is not accurate). The DemoManager holds references to all of the ScenarioManagers, but only chooses one ScenarioManager at a time to develop its scenario. Each ScenarioManager is connected to specific Create classes within a large pool of Create classes, which will be the objects that specific scenario will actually possibly need to create. The Create classes referenced to can overlap as some objects will be used in multiple scenarios.

DemoManager (change to GenerationManager)

The name of GenerationManager was changed to DemoManager to fit its purpose better. Since the system will be mainly used for demonstration purposes, it will focus its functionality on generating any varied number of scenarios and allowing for real time resetting.

Goal:

Passes down highest level information to ScenarioManager level. This will include puzzle type, variation types within that puzzle type, and any other high level information such as overall positioning or how many scenarios in total to generate.

Needs:
  • Number of scenarios to generate
  • List to hold information on all scenario options
    • Customizable in editor to pin point certain scenarios if wanted
    • ScenarioManager level objects should be same type of object to help with this listing
  • Scenario spacing
  • Input to reset generation in real time
  • Seed information (may be better in scenario manager level)
Notes:
  • Will have some bool list of scenario types to include in its random generation
  • For testing, have “GenerateSpecific” bool to allow for creating a single specific scenario
  • ScenarioManager

    I think it makes sense to commit to setting up an internal hierarchy setup within the ScenarioManager level at this point. This allows the DemoManager to just deal with ScenarioManager type objects, but I can break each scenario type down into its own class to help keep the scripts manageable and more organized.

    Goal:

    Will take DemoManager information and use it to determine which “Create” type classes will need to be used (or have the option of being used), how many times to use each, and what other information needs to be passed on to them (the “Create” type classes) to properly build out the desired scenario.

    Needs:
    • Hold Parameter Ranges
      • will need to be moved over from current Create classes
    • References to Create type classes
    Example for Possible Inheritance Pattern
    • ScenarioManager
      • PulleyScenarioManager
        • HeaveyDoorPulley
        • PlatformPulley
        • HookPulley
    • Information for all general scenarios
      • Information for a general type of scenario
        • Specific information for a specific type of puzzle in a specific type of scenario

    This shows the inheritance setup within the ScenarioManager level from the overall system setup.

    Create Classes

    I have not worked with these enough yet to fully update them, but I am looking at creating a base Create class that holds general data that any of those classes will need. Then each type of object will have its own Create type class that derives from this class detailing all of the specifics for altering the parameters of that overall object.

    Sebastian Lague A* Tutorial Series – Units – Pt. 05

    December 4, 2019

    A* Tutorial Series

    Pt. 05 – Units

    A* Pathfinding (E05: units)

    Link – Tutorial

    By: Sebastian Lague


    Intro:

    This tutorial focuses on passing the Pathfinding information to units so that they can actually use it to move.

    PathRequestManager and Updating Old Classes

    Having many units use this logic at once would be a bit too costly and could cause slow downs, so this needs to be managed and spread out in order to keep the game from slowing down or stopping.

    This was done by creating the PathRequestManager class. This was created to ensure only one request would be processed at a time. Requests were added to a queue, which are then popped off one at a time to fulfill. A simple bool check was used to ensure one request was being done at a time (isProcessingPath).

    A new struct named PathRequest was created within this class as well to make managing the data much easier. These PathRequest objects would hold a Vector3 for the start position, another Vector3 for the end position, and then a bool named callback. This just helps keep all the data together in a nice package when processing through the request manager.

    Once this was setup, the Pathfinding class (PathfindingHeap) needed updated to work with this. As I expected, the FindPath method was changed to a coroutine, and a method was added within PathfindingHeap simply to start this coroutine (as well as pass in the needed parameters for starting and ending positions). Next was getting a unit to actually use all of this to inform its movements.

    All of the nodes used for the path are effectively used as waypoints for an object to move through. Bigger and higher resolution grids would be creating a lot of waypoints this way, so to reduce this they created a SimplifyPath method that only creates waypoints at nodes where the direction changes. A Unit class was then created for the actual moving objects that simply requests a path and then follows the waypoints generated by the path.

    Visualization

    Finally for visualization purposes, they used some more OnDrawGizmos methods. They drew a cube at each waypoint, and then drew a line between each of these waypoints. The lines were then removed as the unit traversed them to show their remaining path. This was a really neat and effective way to show their pathing logic.

    Summary

    This setup for a request manager seems very simple, but effective enough for lower scale cases. I think some of my recent work with overall event systems in Unity could be used to really improve this overall system. The visualization was a nice touch and worked really well. This is definitely something I want to look into more to help show how logic behind the scenes works to others.

    Sebastian Lague A* Tutorial Series – Heap Optimization – Pt. 04

    December 2, 2019

    A* Tutorial Series

    Pt. 04 – Heap Optimization

    A* Pathfinding (E04: heap optimization)

    Link – Tutorial

    By: Sebastian Lague


    Intro:

    This tutorial focused on converting the pathfinding setup over to a heap system to help speed up the process, especially for larger scaled environments and node grids. There is some useful theory at the beginning, and then it gets into heavier code work, so I again break down the classes later in the tutorial.

    General Heap Theory

    One of the first places to optimize this A* pathfinding is in the Pathfinding class where it searches through the entire open set every time it tries to determine the next lowest F cost node. Heap optimization will be used here to reduce the load of the process.

    A heap is basically a binary tree where each node branches out to two more nodes. The general rule of this tree is that the parent value is less than that of the children nodes. When placing a new node, it is placed at the end (on a “leaf of a branch”) initially. It is then checked with its parent and if it is less, it swaps positions with that parent. This continues until it reaches a parent with a lower value, or the node moves all the way to the top.

    For the A*’s needs it will constantly be removing the node with the lowest value. This will always be the node found at the top of the heap. To fill the space when that is removed, they take the last value added to the tree and place it in the opening (at the top). They then compare this with the children nodes and swap it with whichever value is lower. This continues until it reaches a point where none of the children are lower value (or it has reached the end of a branch).

    Some basic integer math can be used to locate the array index of an element that is the parent or a child of any given node. A parent can be found for any index with the formula:

    parentIndex = (index – 1) /2

    This works with both children as “half” values will round down in integer math.

    Then this can similarly be used to get the children of a node, with the minor caveat that each child has its own unique formula. The formulas for these are:

    leftChildIndex = 2 * index + 1
    rightChildIndex = 2 * index + 2

    Heap Class

    They created an entirely new class named Heap. This was a generic class that would take in a type, T, so that it could also be generically used for various different types of objects. This started with some basic fields for an array of items (of type T) and an int for currentItemCount. There was then a constructor that simply took in an int as a parameter which dicated the size of the items array.

    They then created a new interface, IHeapItem, within this same script. It implemented the interface IComparable (which is part of the System namespace). It was initially created with just an int named HeapIndex, which will be used to hold the index value of that item within the heap. This was important to note as the Heap class then used a “where” keyword to dictate that T implemented the IHeapItem interface. I assume this means that the type T used for the Heap class MUST implement the IHeapItem interface.

    They create a few key methods here in the Heap class. The Add method takes an item of type T and adds it to the heap by setting its heapIndex to the currentItemCount and then adding it into the items array at the end (in index currentItemCount). It then uses the SortUp method to properly position that element in the heap, and increases the currentItemCount.

    SortUp is the basic logic for continuosly comparing a new element to its parent until it is properly positioned. It uses the CompareTo method within to compare the items with their parents, which can return a value of 1, 0, or -1 depending on how the comparison priority is determined.

    Then a simple Swap method was created to properly swap the items in two index array positions. It also has to separately change their heapIndex values to match their new index positions. This is done by also swapping the two items heapIndex values.

    Then a method is also needed to remove items from the heap. This was named RemoveFirst. It returned the top element of the heap (items[0]), and then replaced it with the last element in the heap, with index (currentItemCount – 1). It then has to run a similar sorting algorithm to properly place this newly moved item.

    The method to sort this newly moved item was named SortDown. This took an item as a parameter and constantly compared it with its children items and swapped their positions until it either reached the bottom of the heap or did not find children with higher priority than the actively sorted item. It checked if there were any children, then which child had higher priority, than compared the higher priority child to the current item. If the child was higher priority, they swapped. Otherwise, end the loop.

    Update Node Class

    They then move to the Node class to update it with the new Heap class. This starts by implementing the new IHeapItem with type Node. Because of this implementation, they need to add an int field for HeapIndex, and because of that interface implementing IComparable, they also need a method named CompareTo.

    HeapIndex just gets and sets the value of heapIndex. CompareTo uses compareTo methods to compare the fCost and Hcost values to determine which node has higher priority. Integers can use the CompareTo method as well, and will similarly return 1 if the value it is compared to is greater, 0 if they are the same (equal), and -1 if it is lower.

    So their approach creates an int named compare that is set equal to the CompareTo value between the fCosts of both nodes. Then, if it is 0 (which means they are equal), it sets compare equal to the compareTo value between the hCost values of the nodes. Finally, it returns the opposite value of compare (-compare), since they want it to represent higher priority, which actually corresponds with the lower cost values in this case.

    Finally they just needed to update the Pathfinding class to use the heap instead of a list. I made a separate class called PathfindingHeap just to archive both versions of the code for myself. They then showed how to use the System.Diagnostics namespace to create a StopWatch to keep track of time as a measure of performance. This helped show that the new heap method is much faster for larger scale searching and grids.

    Summary:

    The heap optimization clearly appears to work from the several tests I ran and they ran in the tutorial video, especially as you scale up the environment. While this is clearly very useful for pathfinding, the general theory behind heaps also just seems to be useful knowledge for generic programming practices. This makes it very nice that the tutorial sets it up in a very generic way, so I can possibly use this for other logic later on.

    Check:

    I need to look into the syntax used for the Heap class setup. The initial line for the class is:

    public class Heap where T : IHeapItem

    This is syntax I have not come across before. I assume this means that the type of objects used for the Heap MUST implement the interface IHeapItem, but I want to look into this just to make sure.