The Trials of Snowshoe Thompson Release

Hello all! I just wanted to make a quick post to give my site an update on what I’ve been up to! This past week, I finished my degree & graduated from USC with a BA in Interactive Entertainment. After being an undergrad student for 6 years, I am more than ready to enter the industry and begin to work & learn in a professional environment. I am very grateful for the experiences I gained from working on games at USC, and today I’m proud to show off the game that I worked on over the past year as a part of USC Games.

The Trials of Snowshoe Thompson is a game I worked on as the Lead Engineer, alongside a team of 5 other engineers. You can see posts here about the development process of Snowshoe, but in short: our goal as engineers on this project was to recreate the feeling & physics of realistic cross country skiing. I am very proud of how this project turned out, and greatly value the lessons I learned in the process. I most enjoyed being able to work on large scale Unity architecture, and working alongside very brilliant engineers.

I may eventually come back and write a more reflective post on this project, but for now I am going to leave just the link to the download, and hope you are able to enjoy it! You will need a playstation or xbox controller to play the game!

Download Snowshoe Here!

Detecting The Player’s Controller Type With the Unity Input System

Hello all, this is a walkthrough of my solution for detecting the device that the player is using in a single player “gamepad” based game. In my specific case, I’m using this information to have my UI constantly represent the correct “controls” UI for the type of device my player is using. At the time of writing this, my system is specifically built to sort between PlayStation & Xbox controllers, with Xbox being the default. With that said, this system is easily extendable, and I hope that will be clear through my code & explanations. This guide is meant to help those who have routed all of their input beneath the “game pad” umbrella in the Unity Input System, but still want the specific type of controller used by the player to be accessible.

This post is using the “New” Unity Input System, NOT the Unity Legacy Input

I ran into a lot of very interesting road blocks in my quest to create an abstracted UI Image system which would live react to the type of controller being used by the player…. It sounds funny, because you would think it would be simple to detect the type of controller being used by the player, but the way that the Unity Input System deals with game pad style controllers seems to do a pretty good job of burying this data.

There were 2 ways which I thought I could approach this. The first would be to go into my actual Input Map and specify control schemes by controller type, and then have a manager which detects input from any/all control schemes. and switches state based upon the most recent input. I chose not to do this because, in my opinion, one of the biggest appeals of the Unity Input System is that it supports the most common controller types all beneath the gamepad umbrella.

It’s important to note that in my project, I have my PlayerInput Behavior set to Invoke C# Events.

My first step in this system was listening in to the InputSystem.onDeviceChange, which must be assigned to a function which takes an InputDevice and InputDeviceChange. This event will fire off every time a change to device is detected. These include a controller being: added, disconnected, removed, & reconnected. InputDeviceChange represents which one of these events was detected. Here’s what those look like:

Note: _currentController is just a basic enum meant to internally store the controller state

    private void GameManagerRegisterInput()
    {
        //Binds onDeviceChange event to InputDeviceChanged
        InputSystem.onDeviceChange += InputDeviceChanged;

    }

    //Method called  when a device change event is fired
    private void InputDeviceChanged(InputDevice device, InputDeviceChange change)
    {
        switch (change)
        {
            //New device added
            case InputDeviceChange.Added:
                Debug.Log("New device added");
                

                break;
               
            //Device disconnected
            case InputDeviceChange.Disconnected:
                controllerDisconnected.Invoke();
                Debug.Log("Device disconnected");
                break;
            
            //Familiar device connected
            case InputDeviceChange.Reconnected:
                controllerReconnected.Invoke();
                Debug.Log("Device reconnected");
                

                break;
                
            //Else
            default:
                break;
        }
    }//Method called  when a device change event is fired
    public void InputDeviceChanged(InputDevice device, InputDeviceChange change)
    {
        switch (change)
        {
            //New device added
            case InputDeviceChange.Added:
                Debug.Log("New device added");
                
                //Checks if is Playstation Controller
                if (device.description.manufacturer == "Sony Interactive Entertainment" && _currentController != CurrentControllerType.PlayStation)
                {
                    //Sets UI scheme
                    Debug.Log("Playstation Controller Detected");
                    currentImageScheme.SetImagesToPlaystation();
                    _currentController = CurrentControllerType.PlayStation;
                    controllerTypeChange.Invoke();
                }
                //Else, assumes Xbox controller
                //device.description.manufacturer for Xbox returns empty string
                else if(device.description.manufacturer != "Sony Interactive Entertainment" && _currentController != CurrentControllerType.Xbox)
                {
                    Debug.Log("Xbox Controller Detected");
                    currentImageScheme.SetImagesToXbox();
                    _currentController = CurrentControllerType.Xbox;
                    controllerTypeChange.Invoke();
                }
                break;
               
            //Device disconnected
            case InputDeviceChange.Disconnected:
                controllerDisconnected.Invoke();
                _currentController = CurrentControllerType.Other;
                Debug.Log("Device disconnected");
                break;
            
            //Familiar device connected
            case InputDeviceChange.Reconnected:
                controllerReconnected.Invoke();
                Debug.Log("Device reconnected");
                
                //Checks if is Playstation Controller
                if (device.description.manufacturer == "Sony Interactive Entertainment" && _currentController != CurrentControllerType.PlayStation)
                {
                    //Sets UI scheme
                    Debug.Log("Playstation Controller Detected");
                    currentImageScheme.SetImagesToPlaystation();
                    _currentController = CurrentControllerType.PlayStation;
                    controllerTypeChange.Invoke();
                }
                //Else, assumes Xbox controller
                //device.description.manufacturer for Xbox returns empty string
                else if(device.description.manufacturer != "Sony Interactive Entertainment" && _currentController != CurrentControllerType.Xbox)
                {
                    Debug.Log("Xbox Controller Detected");
                    currentImageScheme.SetImagesToXbox();
                    _currentController = CurrentControllerType.Xbox;
                    controllerTypeChange.Invoke();
                }
                break;
                
            //Else
            default:
                break;
        }
    }    private void GameManagerRegisterInput()
    {
        //Binds onDeviceChange event to InputDeviceChanged
        InputSystem.onDeviceChange += InputDeviceChanged;

    }

    //Method called  when a device change event is fired
    private void InputDeviceChanged(InputDevice device, InputDeviceChange change)
    {
        switch (change)
        {
            //New device added
            case InputDeviceChange.Added:
                Debug.Log("New device added");
                

                break;
               
            //Device disconnected
            case InputDeviceChange.Disconnected:
                controllerDisconnected.Invoke();
                Debug.Log("Device disconnected");
                break;
            
            //Familiar device connected
            case InputDeviceChange.Reconnected:
                controllerReconnected.Invoke();
                Debug.Log("Device reconnected");
                

                break;
                
            //Else
            default:
                break;
        }
    }

While this was the first step I took, I was working backwards a bit. With this event being listened to, we can react to new controllers being connected, to controllers losing connection, and a bunch of other events. These events usually represent a reason to re-evaluate the current images being displayed for controls.

I wrote a fairly simple Scriptable Object which holds all the textures we will be using in our “controls” UI. So this scriptable objects holds all the images used to represent xbox and playstation controls. Additionally, it has a set of private textures which hold the “current” image for that button. Through this abstraction, I can have the Scriptable Object flip it’s set of “current” images, and have all UI read from this ScriptableObject for the image it needs to display.

Now that I had the foundation, and a way to store/represent the “controller type” state, now I just needed to determine what type of controller was being connected/added, and pass that state on to my Scriptable Object. Using the API for the type Device, which is passed on this event as a direct reference to the Device that instigated the event, I was able to determine that the field description has sub fields which are used to define the specific type of controller, the manufacturer, and more. The field product is a string which would come out something like “Dual Shock 4” or “Xbox One Elite”. While this is certainly useful, I wanted things to remain as generic as they could be. The manufacturer proved to be the most abstracted I could get, while still distinguishing between the specific types of gamepads. However, herein lies the first issue I encountered. While the device.description.manufacturer field on a Playstation controller returns a nice & neat “Sony Interactive Entertainment”, that same field for the Xbox controller is entirely empty. Since I only have to support the 2 types, I wrote these conditions into an if/else, and called it a day. But as I extend the system to include more controller types, I would make use of the device.description.product and distinguish between the remaining types of controllers. Here’s what that same chunk from above looks like with these cases written in.

A note: currentImageScheme is my Scriptable Object described above. This scriptable object provides the texture to raw image prefabs in my UI. controllerTypeChange is an event which is listened to by the UI. The UI will react to this event by setting their texture to the “current” texture stored in the ScriptableObject

//Method called  when a device change event is fired
    public void InputDeviceChanged(InputDevice device, InputDeviceChange change)
    {
        switch (change)
        {
            //New device added
            case InputDeviceChange.Added:
                Debug.Log("New device added");
                
                //Checks if is Playstation Controller
                if (device.description.manufacturer == "Sony Interactive Entertainment")
                {
                    //Sets UI scheme
                    Debug.Log("Playstation Controller Detected");
                    currentImageScheme.SetImagesToPlaystation();
                    controllerTypeChange.Invoke();
                }
                //Else, assumes Xbox controller
                //device.description.manufacturer for Xbox returns empty string
                else
                {
                    Debug.Log("Xbox Controller Detected");
                    currentImageScheme.SetImagesToXbox();
                    controllerTypeChange.Invoke();
                }
                break;
               
            //Device disconnected
            case InputDeviceChange.Disconnected:
                controllerDisconnected.Invoke();
                Debug.Log("Device disconnected");
                break;
            
            //Familiar device connected
            case InputDeviceChange.Reconnected:
                controllerReconnected.Invoke();
                Debug.Log("Device reconnected");
                
                //Checks if is Playstation Controller
                if (device.description.manufacturer == "Sony Interactive Entertainment")
                {
                    //Sets UI scheme
                    Debug.Log("Playstation Controller Detected");
                    currentImageScheme.SetImagesToPlaystation();
                    controllerTypeChange.Invoke();
                }
                //Else, assumes Xbox controller
                //device.description.manufacturer for Xbox returns empty string
                else
                {
                    Debug.Log("Xbox Controller Detected");
                    currentImageScheme.SetImagesToXbox();
                    controllerTypeChange.Invoke();
                }
                break;
                
            //Else
            default:
                break;
        }
    }

So remember when I said I was working backwards? At this point, my system detects and reacts to big controller events, but at the start of the program has no idea what controller is being used. This is where I encountered the majority of my hardship, but I’m very proud of the end result!

Something I learned quickly is that the Unity Input System stores all known input devices, regardless of them being currently connected or not. So if my player is playing on their xbox controller, it’s batteries die, and they switch to their PS controller, InputSystem.devices still stores both devices. Additionally, while the type Device has a property enabled, this returns true for all devices registered to the Unity Input System. So all of this results in perhaps the most notable roadblock I encountered with this System: I could not find a way in which the Unity Input System distinguishes between the currently connected/in use controllers and those which are simply known by the Unity Input System, ie not in use at all. Devices can easily be individually assigned, and switched between, and detected, but there is no property of the Type Device (that I could find) which represents whether an individual device is actively connected. I pray I’m wrong about that, but the closest I could get was InputDevice.lastUpdateTime, which InputSystem inherits from. Even that field returns extremely unreliable values, as on PS it counts gyroscopic data as input, every frame, and in my tests, was returning the same value for all my devices, connected or not.

TlDr; I could not find a way to distinguish between connected and non connected input devices.

My response to this, however, is where I’m most proud of this code! I found that if I remove all the stored devices on game start, the controller being used by the player instantly re-constructs itself, and is quickly the only device stored in InputSystem.devices[]. From here, it’s easy to just check InputSystem.devices[0].manufacturer, and we have the same check on game start as we do when a controller event happens. Here’s that code!

Once again, currentImageScheme is my SO

//Called in GameManagerGameStart() to set the UI initially
    private void UIImageSchemeInitialSet()
    {
        //Disables all devices currently read by InputSystem
        for (int rep = 0; rep < InputSystem.devices.Count - 1; rep++)
        {
            InputSystem.RemoveDevice(InputSystem.devices[rep]);
        }

        if (InputSystem.devices[0] == null) return;
        
        //Checks the first slot of the InputSystem devices list for controller type
        if (InputSystem.devices[0].description.manufacturer == "Sony Interactive Entertainment")
        {
            //Sets UI scheme to PS
            Debug.Log("Playstation Controller Detected");
            currentImageScheme.SetImagesToPlaystation();
            _currentController = CurrentControllerType.PlayStation;
            controllerTypeChange.Invoke();
        }
        else
        {
            //Sets UI scheme to XB
            Debug.Log("Xbox Controller Detected");
            currentImageScheme.SetImagesToXbox();
            _currentController = CurrentControllerType.Xbox;
            controllerTypeChange.Invoke();
        }
    }

From there, to complete my system, all I had to write was a MonoBehaviour which stores a reference to my SO, and listens to my controllerTypeChange event, reacting by just setting its image to the corresponding image stored in the Scriptable Object. Here’s that code, for those who are curious!

public class ControllerImageScript : MonoBehaviour
{
    public UIImageSchemeSO uiImageScheme;
    
    public enum buttonImage
    {
        southButton,
        eastButton,
        northButton,
        westButton,
        rightTrigger,
        leftTrigger
    }

    public buttonImage myButtonImage;

    private RawImage myImage;
    
    // Start is called before the first frame update
    void Start()
    {
        myImage = gameObject.GetComponent<RawImage>();
        SetButtonImage();
    }

    public void SetButtonImage()
    {
        if (myButtonImage == buttonImage.southButton)
        {
            myImage.texture = uiImageScheme.GetSouthButton();
        }
        else if (myButtonImage == buttonImage.eastButton)
        {
            myImage.texture = uiImageScheme.GetEastButton();
        }
        else if (myButtonImage == buttonImage.northButton)
        {
            myImage.texture = uiImageScheme.GetNorthButton();
        }
        else if (myButtonImage == buttonImage.westButton)
        {
            myImage.texture = uiImageScheme.GetWestButton();
        }
        else if (myButtonImage == buttonImage.leftTrigger)
        {
            myImage.texture = uiImageScheme.GetLeftTrigger();
        }
        else if (myButtonImage == buttonImage.rightTrigger)
        {
            myImage.texture = uiImageScheme.GetRightTrigger();
        }
    }
}

I spent all day on this code, and I found it a surprisingly underdocumented topic. I hope that this proves helpful to those who are in my situation, just as all the wonderful discussions/threads online helped me!

Splat-mapping Abstraction in Unity

Hello all! I’m posting today with a brief follow up on my post about terrain texture detection in Unity. If you haven’t checked that out, it will definitely be informing this post! I have been working further on getting this system to work with my current PlayerMovement system, and have come to a neat solution of abstraction which can be branched to communicate anywhere in your game what the current terrain texture is beneath the player.

Here’s what this solution solves:

Our player’s movement is effected constantly by what type of ground the player is on. So for example, braking power & amount of friction (2 separate variables in the PlayerMovement). Since we need these values to be dynamic, a layer of abstraction is helpful in allowing these values to be continuously modified by factors such as the terrain.

Our designers have not finalized the variables effecting movement at large, this solution allows for testing of multiple combinations of these movement variables as extreme ease to the design team. This will be used for AB testing in our playtests down the road.

The solution:

It’s very simple, but has helped a lot with working this data into my PlayerMovement in a clean and clutter free way. All I have done is created a new Scriptable Object type, MovementVariables, and moved all of the “designer variables” into this scriptable object. Additionally, I have created a simple class, TerrainType, which stores all of the variables that are dynamic and dependent upon the terrain the player is on. I’ve made this class serializable, and within my MovementVariables I have a public array of TerrainType that allows the designers to set each terrain type uniquely for each variant of the MovementVariable type.

MovementVariables has a public function, SetToTerrain(), that takes in an int representing the terrain texture the player is currently on (remember this is stored in an int by the Alpha map). Upon taking that int, MovementVariables will set the necessary variables to match those of the corresponding TerrainType in the local array. So, for example, terrainTypes[0] is created by the designer to have float frictionLevel = 1, and float brakingPower = 3. Once SetToTerrain() takes in an int 0, then MovementVariables will set the frictionLevel and brakingPower according to whatever is in terrainTypes[0].

From here, all that is necessary for setup (besides setting the designer variables) is to create a reference to a MovementVariables in both the PlayerMovement and the TerrainTextureGetter. The former will simply read the scripted values from this Scriptable Object, and the latter will pass the int representing the texture into SetToTerrain().

… and that’s it! It’s a super simple solution but really has helped me in passing these terrain settings into my movement, in making my PlayerMovement less beefy, and in aiding the design team with finalizing their movement variables… Here’s some code

[System.Serializable]
public class TerrainType
{
   public string terrainTypeName;
   [Range(0f, 100f)]public float stridePushPower;
   [Range(0f, 15f)] public float brakingPower;
   [Range(0f, 5f)] public float slidingFrictionPower;
   [Range(0f, 10f)] public float turningSpeed;
}

This is the TerrainType class which is key in allowing this abstraction to work. These are the variables in PlayerMovement which we want to be altered by the terrain type beneath the player.

//Variables set by terrain
[ShowOnly]public float turningSpeedMod;
[ShowOnly]public float slidingFrictionPower;
[ShowOnly]public float brakingPower;
[ShowOnly]public float stridePushPower;

public void SetToTerrain(int terrainNumber)
{
    if (terrainNumber == 0 && terrainVariableSets[0] != null)
    {
        turningSpeedMod = terrainVariableSets[0].turningSpeed;
        slidingFrictionPower = terrainVariableSets[0].slidingFrictionPower;
        brakingPower = terrainVariableSets[0].brakingPower;
        stridePushPower = terrainVariableSets[0].stridePushPower;
    }
    else if (terrainNumber == 1 && terrainVariableSets[1] != null)
    {
        turningSpeedMod = terrainVariableSets[1].turningSpeed;
        slidingFrictionPower = terrainVariableSets[1].slidingFrictionPower;
        brakingPower = terrainVariableSets[1].brakingPower;
        stridePushPower = terrainVariableSets[1].stridePushPower;
    } 
    else if (terrainNumber == 2 && terrainVariableSets[2] != null)
    {
        turningSpeedMod = terrainVariableSets[2].turningSpeed;
        slidingFrictionPower = terrainVariableSets[2].slidingFrictionPower;
        brakingPower = terrainVariableSets[2].brakingPower;
        stridePushPower = terrainVariableSets[2].stridePushPower;
    } 
    else if (terrainNumber == 3 && terrainVariableSets[3] != null)
    {
        turningSpeedMod = terrainVariableSets[3].turningSpeed;
        slidingFrictionPower = terrainVariableSets[3].slidingFrictionPower;
        brakingPower = terrainVariableSets[3].brakingPower;
        stridePushPower = terrainVariableSets[3].stridePushPower;
    }
    else if (terrainNumber > terrainVariableSets.Length - 1)Debug.LogError("Unsupported Terrain Type. Add to MovementVariablePackage");
}

This chunk of code above is located within my MovementVariables Scriptable Object. The top variables are what are being referenced within PlayerMovement, but they are being set below. SetToTerrain() is called every time a terrain texture change is detected. An important note is the [ShowOnly] editor attribute was written and made public by Stack Overflow user Lev-Lukomskyi. Huge thanks for that, as it keeps the designers from touching things they shouldnt ;). I’m just kidding… I hope that this post was helpful for anyone who needed a follow up from my last post about terrain texture detection! Until next time!

Detecting Textures Across Multiple Terrains In Unity

Hello all, I hope that as you read this, all is well in your world. The last week has been a truly fitting capstone on the crazy year that has been 2020, especially for U.S. citizens. I want to take your mind off the madness for a moment and talk about something I worked on over the last few days.

As you can read about in my October Update, I’ve been making a skiing game! It’s been awesome so far, and really enjoyable. Something that is crucial to the design of our game is different textures on the terrain beneath the player having differing effects on gameplay. For example, we have a texture that represents “heavy snow”, which will bring down the speed at which the player treks through the snow, as well as an “ice” texture, which would instead speed the player up at a much higher rate, and slow down at a much slower rate. The process itself is not complicated, it just involves getting the terrainData of terrain below the player, and using the player’s relative position to the terrain to calculate what the texture is that is present at that point on of the terrain, and in what strength. While these calculations are somewhat daunting (involving the 3D float array used to represent an alpha map), they’re actually not too complex when broken down.

Where my specific need for this process differs from a lot of what I’ve seen online is that our Unity scene involves upwards of 20 separate terrain objects (and therefore over 20 individual TerrainData data type). The solution here for me was to setup a function to work in tandem with the terrain splat mapping calculations above. This function takes the player’s position, and compares it to the center point of the terrains stored in the array Terrain.activeTerrains. The terrain returned is then interpolated on to determine what textures is beneath the player. Here’s the code return the closest terrain to the player! Just remember I use Scriptable Objects to store live values (such as player posisiton), hence the need for me to specify “.value” to get the Vector3.

Terrain GetCurrentTerrain()
{
    //Array of all terrains
    Terrain[] totalTerrains = Terrain.activeTerrains;

    //Checks on length
    if (totalTerrains.Length == 0) return null;
    else if (totalTerrains.Length == 1) return totalTerrains[0];
    
    //closest terrain, Initialized with totalTerrains[0]
    Terrain closestTerrain = totalTerrains[0];
    
    //Center of terrain at totalTerrains[0]
    Vector3 terrainCenter = new Vector3(closestTerrain.transform.position.x + closestTerrain.terrainData.size.x / 2, playerPos.value.y, closestTerrain.transform.position.z + closestTerrain.terrainData.size.z / 2);
   
    //will be closest distance between player a terrain. Initialized with totalTerrains[0]
    float closestDistance = Vector3.Distance(terrainCenter, playerPos.value);
    

    //Iterate through list of all terrains
    for (int rep = 1; rep < totalTerrains.Length; rep++)
    {
        //currently selected terrain
        Terrain terrain = totalTerrains[rep];
        terrainCenter = new Vector3(terrain.transform.position.x + terrain.terrainData.size.x / 2, playerPos.value.y, terrain.transform.position.z + terrain.terrainData.size.z / 2);

        //Check on distance compared to closest terrain
        float d = Vector3.Distance(terrainCenter, playerPos.value);
        if (d < closestDistance)
        {
            closestDistance = d;
            closestTerrain = totalTerrains[rep];
        }
    }
    //Returns the closest terrain
    return closestTerrain;
}

So now that we have the closest terrain to our player, we need to convert the player’s position in the game to their position on the specific alpha map. This process looks something like this, noting that currentTerrain has just been set to whatever is returned by GetCurrentTerrain():

void GetPlayerTerrainPosition()
{
//Player position relative to terrain
Vector3 playerTerrainPosition = playerPos.value - currentTerrain.transform.position;

//Player position on alphamap of terrain using offset
Vector3 alphamapPosition = new Vector3 (playerTerrainPosition.x / currentTerrain.terrainData.size.x, 0, playerTerrainPosition.z / currentTerrain.terrainData.size.z);

//Properly scales players x and z
float xCoord = alphamapPosition.x * currentTerrain.terrainData.alphamapWidth;
float zCoord = alphamapPosition.z * currentTerrain.terrainData.alphamapHeight;

//Casts as int and sets
xPos = (int)xCoord;
zPos = (int)zCoord;
}

We get out of this call with now our 2 xPos and zPos fields set to the player’s coordinates on the terrain. All that’s left is to take these coordinates and get the alpha map at the player’s position, and determine which terrain texture is applied at that location. One important note is how alpha maps store references to textures. the alpha map is a 3d array where the third value refers to the texture being checked for. For example alphaMap[0,0,0] will return the strength of the texture in slot 0 of the terrain texture layer. alphaMap[0,0,1] will return the strength of texture in slot 1. Hence, splatmapping! We are able to interpolate on various combinations of strength of textures, not just simply player is or isnt on ice. Instead, we can say 30% ice, 70% regular snow, and have our movement variables adjust to that specific combination…. I’m getting off track, but just know this:

textureValues[] is an array of floats representing the strength of each texture at the specified x & z pos. The length of this array is simply set to the number of textures in our terrain layers.

here, rep is used to tie the corresponding spot in textureValues to the value of the texture in that slot of the 3d array

SetPlayerMovementVariables() is currently where we are interpolating on the data gathered here, but essentially the value is clamped from 0 to 1, representing how much of the splatmap at that point is of the texture in the corresponding spot in aMap, and from there we are setting values in our PlayerMovement script. Take a look!

//gets the float (clamped between 0 and 1) of how much of each texture is present at the x & z coord
void CheckTextureBelowPlayer()
{
//Will store the alpha map of the current terrain
float[,,] aMap;

//Uses x position and z position to set aMap to correct alpha map
aMap = currentTerrain.terrainData.GetAlphamaps(xPos, zPos, 1, 1);

//textureValues stores the current stength of the texture stored in the corresponding slot in the alpha Map
for (int rep = 0; rep < textureValues.Length; rep++ )
{
//stores stength of values at that point
textureValues[rep] = aMap[0, 0, rep];
}


//Iterates through to check if any values are greater than 0
for(int rep = 0; rep < textureValues.Length; rep++ )
{
//If terrain is present, sets player movement values
if(textureValues[rep] > 0)
{
SetPlayerMovementVariables(rep, textureValues[rep]);
}

}
}

This flow of operations effectively allows my team’s PlayerMovement script to iterate as usual, but be fed different live values decided by the terrain type. So far this works really well for me, but if I find more to change and tweak, I absolutely will update it here! I hope this helps anyone who is setting out to do this themselves, much like I was a few days ago! Hope you enjoy the code!

October 2020 Update

Hello All! I’m deep in the semester currently (my second to last), but wanted to pop in here to try and share what I have been working on game wise! Firstly, if you haven’t checked out Liquidators yet, please please do! The game can be found on Steam and Itch.io, and you can read a little bit about the mission here. I worked as the Lead Producer and Designer of this project over the last year, and am SUPER proud of it. This has been taking up a fair amount of my time lately, as I have learned more about the “post-production” process. It has been amazing experience seeing our game played by so many online, and being received so well in reviews. We just passed 14,000 units today, and taking part in this awesome team has been one of the most fullfilling experiences in my life. Here is a video of Tomato Gaming playing Liquidators in a livestream… One of my favorite playthroughs so far!


Aside from post-production work on Liquidators, I have also been working on a new full year project. I have been working as the Lead Engineer on The Trials of Snowshoe Thompson. The game emphasizes a unique movement mechanic, and realistic skiing physics, to take players through a narrative experience based around the famed mail delivery worker, John “Snowshoe” Thompson. This is by far the largest project I have ever taken part of, with over 20 team members, and we hope to be finished with Alpha sometime in January. The project has truly tested me as an Engineer, and I have loved every second of it. I lead a team of 5 other Engineers, and so far the most rewarding part of the game is working with such hard working individuals. Communication is something I think is most valuable in a game development environment, and being entirely remote has presented me with some unique challenges, but having a hard working and dedicated team has really made these issues non-existent.

So far, our Engineering team has conquered a lot of ground… I’m not sure how much I should really be showing of this, but ANYTHING for my website… (and I’ll keep it pretty concise for now). We have almost completed the movement system which is meant to simulate a realistic skiing experience. Furthermore, we have implemented a unique style of map meant to entirely replicate how a traditional map would be used to triangulate one’s position. The mechanic utilizes a compass, and a functionality which aligns the Map’s north with the World’s north. Obviously there is a lot more at work, but these are the most unique systems that we have (and the easiest to show off here). If I had to highlight any specific code chunk as my favorite from the project so far, I would have to say it is how we are handling the Player movement state. The Player is currently under the control of a finite state machine, which has 3 states: Moving, Not moving, and Map. But the movement state contains a sub-state enum which allows us to pretty seamlessly (and realistically) play with the player’s ability to move in certain scenarios. For example, a substate in the Movement State is “Right Stride Window”, which allows us to track (from within our Movement State tick) when the window for another stride opens up, and then expect/adjust behavior accordingly. And then based on this behavior, the Player Script (not to be confused with the state tick) will operate and adjust the active substate, which is then fed back into the Player Movement State Tick… Here’s a clip of some of our skiing movement!

And then a clip of the Map in action!

I’d like to emphasize that this has been a team effort for all of what we have accomplished, and I don’t in any way mean to take credit for this. These have been a product of the hard work of my team, and I’m just lucky to have people who care enough about a good product.

The final project that I’m currently working on is for a class, and the production takes place over about 6 weeks, but we plan to take this to a full vertical slice, by working through the month of December. So far, we are about 4 weeks in. The game currently has a working title of Wicker. The basis: You are being pursued. You must run through a storm of cubes to escape. The closer the pursuer gets to you, the faster the storm moves. Running through the storm slows you down. Left clicking clears a tunnel infront of you, right clicking places a light for you to see…. I’m not sure if that makes sense, but hopefully images and clips will help you understand!

I’m working on this project with the same team as made Boomer & Zoomer!
I have been writing all of the code, and have really enjoyed my first venture into a “pursuer” style horror game. While we are still working on a lot of the horror aspects, we have finished a fairly comprehensive sound system which plays a pivotal role in one of our core mechanics. Essentially, players are following their ears, trying to reach an objective, while evading an ever pursuing AI. Here’s a clip of some gameplay we have:

Thanks for checking in guys! I really appreciate the continued support on my site! I’ll hopefully have something playable for you in the next post from both Snowshoe and Wicker.