All posts in "C#"

Build a 3rd person shooter in Unity – Part 2

By Jason Weimann / February 3, 2018

Build a 3rd person shooter from the ground up. Part 2 of this series covers weapon use (firing a gun in Unity) with raycasting to hit the correct targets.  We’ll also setup a reusable health system for our bad guys, player, and even props.  Then we’ll drop into particles for muzzle flashes and sound effect basics.



Get the Third Person Control Code

Download The Muzzle Flash Particle – —>>> HERE <<<—


Get the Gun & Health Code

Continue reading >

Build a 3rd person shooter in Unity – Part 1

By Jason Weimann / February 1, 2018

Build a 3rd person shooter from the ground up. In this series we’ll put together all essentials for a 3rd person shooter game in Unity3D. We’ll do character control, shooting, exploding, animating, making loud explosions, and more! If you want to build a third person shooter, follow along 🙂




Get the Third Person Control Code

Continue reading >

SOLID Unity3D Code Architecture – The Open Closed Principal

Are you ready to start using the SOLID principals in your Unity3D Project?  Learn how the Open Closed Principal (the O in SOLID) can make your game easier to develop, extend, and maintain.  By using simple interfaces and separating out some code, we’ll convert a solution that’s destined for messiness into a clean and SOLID Unity3D project.


What to Look Out For

  1. Adding new functionality requires you to modify your existing classes
  2. Your class is handling different inputs in different ways to the same method.
  3. You start to see if & else if statements cluttering your code.

Ways to Implement The Open Closed Principal in Unity

  • Have your classes act on interfaces, not discrete implementations
  • Use base classes and override their functionality
  • Add events to your class and have other components on the gameobject register for those events instead of the class calling them directly


Continue reading >

Unity3D Machine Learning – Writing a custom Agent – Create your own AI Bot

I’ve been playing with the new Unity3D Machine Learning system for a few days now and made a little progress.  I wanted to share the steps I found to get a newly created agent setup and trained to complete a basic task.  In this post, you’ll see how to setup a basic agent with the goal of reaching a randomly chosen number using nothing but reinforced machine learning.  We’ll use the new Unity ML Agent system and tensorflow to create and train the agent to complete the task and discuss ways to extend this into a real game AI.

Setup Tensorflow and UnityML

If you don’t have tensorflow setup yet, you’ll need to follow the steps outlined here:

Video Version

Want to see this all in video?  Here ya go:

AgentML Scene Setup

Once you’ve gone through that process, open the Unity project and create a new scene.

The first thing we need is an academy.  Create a new gameobject, name it “NumberAcademy“.

Add the “TemplateAcademy” component to the “NumberAcademy“.  Our setup doesn’t need the academy to do anything special, so we can start with the basic blank academy provided in the template.

Under the Academy, create another child gameobject.  Name it “NumberBrain“.

Add a Brain component to it.

Set the State & Action size variables to 2.

Set the Action Space Type to Discrete.  We’ll be using 2 discrete actions (up or down) in our project.  We use discrete because these are represented as integers.

Set the State Space type to Continuous.  We’ll be tracking two floats, for state, so we use continuous.

Set the Brain Type to “Player

Add 2 actions.  Choose any 2 keys you want (I went with A & B), but set the Values to 0 and 1.  The key bound to value 0 decrements the #, the key bound to 1 will increment it.

The NumberDemoAgent Script

Create a new script named NumberDemoAgent.cs

Set the base class to Agent (replace the : MonoBehaviour with : Agent)

Add the following fields:

The currentNumber and targetNumber fields are the most important here.  Everything else is just for debugging and visualizing.

Our agent will pick a random targetNumber and try to get the currentNumber to our target using our increment and decrement commands.

Next we need to override the CollectState method like this:

Here, we’re returning our two floats for current and target number as the state of our agent.  Notice how this matches up with our 2 state variables on the brain and they’re floats which is why we have it set to continuous state instead of discrete.

For our agent to train, we need to select random target numbers.  To do that, we’ll override the AgentReset() method like this:

The final and most important part we need is the AgentStep() method.  This is where we take in actions (aka input), perform some tasks (respond to the actions), and reward our agent for successful choices.

The first thing you’ll see is our text update.  This is only for debugging / visualizing.  It allows us to see the current #, the target, and the # of times we’ve successfully solved the problem (reached the target number).

Next up is the switch where we look at the action and perform our task.  In this case, we either respond to action 0 by decrementing the current number, or to action 1 by incrementing it.  Any value out of that shouldn’t happen, but if we get one, we just ignore it and return.

Then we move our cube based on the currentNumber (using it for the x offset).  This cube again is only for visualizing, it has no impact on the actual logic or training.

We then check the currentNumber against some known limits.  Since we choose a random number between -1 & 1, if we reach -1.2 or +1.2, we can consider it a failure as it’s definitely going in the wrong direction.  In that case, we set the reward to -1 to denote a failure, then mark done as true so the agent can reset and try again.

Then finally, we check to see if the currentNumber is within 0.01 of the target.  If so, we consider that a match, set the reward to 1.0 for a success, and mark it as done.  We also increment the solved counter for debugging purposes (it’s nice to see how many times it’s been successful).

Here’s the complete script:

Setup The Agent

With the script ready, we need to create a new gameobject and name it “NumberDemoAgent”.

Attach the NumberDemoAgent script to it and assign the brain.

Next create a Text object and place it where you can see it (ideally big in the middle of the screen).

Assign the text object to the NumberDemoAgent.

Create a Cube and a Sphere and assign them to the NumberDemoAgent as well (these will help you see what’s going on, much easier than reading #s).

Testing in Player Mode

Now press play.  You should be able to move the cube left and right with your two hotkeys (remember I went with A & B for the hotkeys).

When you get the box to the sphere, it should increment the solved count and reset.  If you go too far the wrong way it should also reset (remember that 1.2 limit).


Once it works in player mode, select the brain and change the “Brain Type” to “External

Save your scene and build an executable where the scene is the only thing included (with debug mode enabled).

For your output folder, choose the python subdirectory of your ml-agents project (included when you downloaded or cloned the source project).  For example, mine is located here: C:\ml-agents\python.

Remember the name you give it, you’ll need that in just a minute.

Anaconda / Jupyter

Launch an anaconda prompt.

Change directory to the python folder you just built into.  ex. “cd c:\ml-agents\python”

Enter the command “jupyter notebook” (you may need to hit enter a 2nd time btw)

You should be prompted with a web interface shortly after that looks like this:

Change the highlighted parts to match.  On the env_name, don’t just put in “numberdemo”, use the name that you built your executable with.  Buffer_size and batch_size you can copy though (it’s important to note that these #’s were only found by testing/trying, even after getting it working, I still barely understand what’s going on with them).

Once you’re done editing the hyperparameters, run the steps in order.

Start with step 1 & 2.  (the * disappears and a # appears in the [*] when it’s done.

When you run step 3, you should see a window appear for your game (a small window though).  The first time, you’ll probably also get a windows permissions dialog, make sure to allow it.

Once you start step 4… WAIT.. and watch the results come in (first one may take a minute so be patient)

Once it’s saved a couple times, hit the stop button.  Then move on to step 5 and run it.  This will export your training data to a .bytes file in the “python/models/ppo” subfolder.

Copy the .bytes file (again it’ll be named to match your executable name) and place it in your Unity project somewhere.

Select the brain and set the “Brain Type” to “Internal”.

Assign the .bytes file to the “Graph Model” field.

Save and press play!


This is a pretty simple sample, meant to just help get a basic understanding how how this system works.  I’m excited to see where it goes though and build bigger more interesting projects to control game AI and make interesting gameplay / bots.



Unity ML Agents GitHub –

HyperParameters Doc –

Machine Learning Playlist –


Continue reading >

Simple System for Passing Balls in Unity

By Jason Weimann / October 12, 2017

Ball Passing System for Unity

This is a simple system I’ve used to pass soccer balls, hockey pucks, and anything else you can imagine in a sports game from one player to another.  The passing script contains everything needed to make something like this work and the logic for calculating the closest angle to your aim is pretty straightforward (and included in the project source below)



Project Download

Continue reading >

VR Dash movement / locomotion with SteamVR and Unity3D

Ready to add dash locomotion to your game?  It’s pretty simple to setup, but there are some important things to consider before you start. In this guide, I’ll show you how to set it up, what to watch out for, and a trick to minimize motion sickness.  All you need is SteamVR and Unity3D to get started.

Before you get started, you’ll want to have some sort of environment setup.  Ideally you want something where it’s obvious that you’re moving.  The locomotion is FAST, and if you just have a flat white area or single repeated texture, it’s gonna be a whole lot harder to tell what’s going on.

Here’s what my test scene looks like.

SteamVR / Oculus SDK

Once you have an environment setup, you’ll need the SteamVR plugin.  The code here is setup for SteamVR but could definitely be ported to Oculus with minimal effort, all we really care about in code is the button click.

After importing SteamVR, drop the [CameraRig] prefab into the middle of your scene.

Select the right controller and add the SteamVR_LaserPointer component to it.

We’re only using the laser pointer to visualize where we’ll dash, there’s no requirement to use the pointer for things to work, you can use it if you like or choose any other visualization of your choice.

Set the color of the pointer to Green.


It’s time to add a little code.  This is the only code you’ll need for dashing to work, so take a good look at it.

The Code

RequireComponent- The first thing to notice is we’re requiring a SteamVR_TrackedController component to be on the GameObject.  We’ll be attaching this component to the “Controller (right)” and the tracked controller will get added automatically.

Serialized Fields – We have 4 fields that are editable in the inspector.

  • MinDashRange & MaxDashRange – We have a  minimum and maximum dash range so we can prevent people from dashing across the entire map or ‘dashing in place’.
  • DashTime – This is the amount of time it will take the player to move from their position to the end point.  In this setup it’s always the same time, no matter how far you go.
  • MaskAnimator – Here we’re storing a reference to an animator.. we’ll be creating this animator soon.  It’s used to add an effect that will minimize motion sickness.

Private Fields

  • trackedController – We’ll be using the tracked controller reference in a few places, so we’re caching it here to avoid calling GetComponent more than once.
  • cameraRigRoot – The same situation applies here, we’ll use the cameraRigRoot to move the player around, and we don’t want to call GetComponent multiple times.

Start() – Here we do the caching of our private fields, and we register for the PadClicked event on the controllers.  If you wanted to use a different button, you’d register for some other event, like GripClicked or TriggerClicked.

TryDash() – This is what we call when the player clicks the trackpad.  The method performs a raycast from the controller’s position aimed in it’s forward direction.  This is exactly what the laserpointer we added earlier does, so if the laser pointer hits something, we should hit the same thing.  And our RaycastHit named “hit” will have a reference to the thing they both hit.  If it does hit something, and the distance of that hit is within our allowed ranges, we start a coroutine called DoDash().

DoDash() – The DoDash method does the actual work here.  First, we set a bool on our maskAnimator named “Mask” to true.  Then we give it 1/10th of a second for the animation to play.  Next, we take note of the cameraRig’s current position and save it off in startPoint.  We then go into a while loop.  This loop will execute for the amount of time specified in our ‘dashTime’ field above (editable in the inspector).  In the loop, we use Vector3.Lerp to move the cameraRig from it’s startPoint to the endPoint (where the user aimed the laser).

Vector3.Lerp returns a vector at a point between two other vector3’s.  The 3rd value (elapsedPct) determines how far between them it should be.  A value of 0 is right at the start point, a value of 1 is at the end, and a value of 0.5 is right in the middle.

Once we leave the loop, we set the “Mask” parameter on our animator back to false and we’re done.

Back to the Inspector

Attach the DashController to the Controller (right)

Play & Test

You should be able to play now and dash around.  Put on your headset, aim the controller and click the trackpad!

The Mask – Reducing motion sickness

Dashing around usually feels okay for most people, but motion sickness is still possible.

To help remove some of the sickness, we can add a cool masking effect.  And if you have some artistic skill, you can make it look much better.

Download this DashMask.png image

Select the Camera (eye).  Right click and add a Quad.

Drag the DashMask.png image onto the quad, a new material will be created automatically.

Select the quad and change the material’s render mode to “Fade”

Move and resize the quad to match this.  We need it close to our face as it’s going to be used to mask out the world.

Animating the Mask

If you play now, you’ll have a mask sitting in your face (or not depending on where you drag the alpha of the albedo color on that material)

What we want though is for the code above to be able to toggle the mask, with a smooth animated fade that we can customize later.

To do this, let’s create a simple animation for the alpha channel of our quad.

The Animation

Select the Quad

Open the Animation window.

Click create animation, name the animation FadeMask

Click record.

Open the Color picker for the Albedo of the material.

Slide the alpha around and settle it at 0.

Drag the Animator red line to the 1:00 mark.

Open the color picker again.

Slide the alpha to the far right.

The Animator

The animator will control our animations.  It handles the state of our animations and does the transitions between them.

Create a new animator for the quad.

The Mask Parameter

In the parameters section, add a new Boolean parameter and name it “Mask

Adding the Animations

Drag the FadeMask animation you just made onto it.

Do it again, but for the second FadeMask, rename it to “FadeMask Reverse“.

Add transitions between the two and use the “Maskparameter to control them.

Set the FadeMask speed to 5.

Select the FadeMask reverse and change the speed to -1.

We’re playing the animation in reverse here to fade the mask back out.  We could have a separate animation for this, but we don’t need it when we can just set the speed to -1.

Attaching the Animator

Add an animator to the Quad.

Assign the new Animator Controller to your animator.

The last thing we need to do is assign the MaskAnimator field of the Dash Controller.

Select the controller, drag the quad onto it, and you’re done..


The Result

Continue reading >

Build a Unity multiplayer drawing game using UNET

In this article you’ll learn how to build the foundation for a multiplayer drawing game.  We’ll start with drawing on a texture and add some Unity UNET network components to make it multiplayer.  By the end, you’ll see other players drawing in real time and have a good foundation to build your own drawing game in Unity3D.


To start, we’ll need a couple pieces of art.

The Canvas

First is our default/blank canvas.

For this example, I’m using a solid white texture that I put a little border around.

Download this canvas or create your own

Color Wheel

The other thing we need is a color wheel.

Download this wheel or find your own

Add both of those textures (or alternate ones you choose) to your project in a Textures folder.

Setup the Canvas

Create a new Quad.

Resize it so it looks similar to this.

Drag the canvas texture you’ve chosen onto the Quad.

Change the material shader on the quad to Unlit/Texture.

Make sure you select a resolution and don’t use free aspect while you’re setting this up.  I”m using 1920×1080.

Name it “Paint Canvas”.

Create a script named PaintCanvas.cs and replace the contents with this.

PaintCanvas Code

This script is used for two things.  First, it makes a copy of the texture in memory so we can easily read and write to it.  This texture is created in PrepareTemporaryTexture and assigned to the static property “Texture”.

The second thing it does is set the texture data from a byte array.  This is so we can ‘load’ a texture from the host when we join the game as a client.  You’ll see this later when we get into the networking code.

Add the new PaintCanvas component to  the “Paint Canvas” Quad.

Back to the Inspector

Your PaintCanvas should look similar to this.

Color Picker

It’s time to setup our color picker so the player can choose different colors easily.

Create a Quad

Name it “Color Picker”

Drag the ColorWheel texture onto the Quad.

Change the Shader to “Unlit/Transparent Cutout”

Create a new script named “ColorPicker.cs” and replace the contents with this.

Add the ColorPicker component to your “Color Picker” object in the inspector.

ColorPicker Code

This script starts off with a static “SelectedColor” property.  This is where we’ll store the users color selection when they click on the colorpicker.

But the work here is done in Update().  We check to see if the user has clicked this frame, and if so, we do a raycast from the click point into the scene).

If the ray intersects with something (line 17) and that something happens to be the color picker (line 20), then we pull the texture coordinate from the RayCastHit multiply it by the height and width of the texture, and get the actual pixel on the texture that we clicked.

With that pixel, we use the Texture2D method GetPixel to get its color and store it in that “SelectedColor” property (line 32).

Finally, we set the material color of our “preview” object to the selected color (line 34).  This is where the user will see the color they’ve picked and have “selected”.

Back to the Inspector

Your color picker should look like this.

Move the wheel so it looks like this.

Selected Color Preview

If you look at the Color Picker code or inspector, you may notice that we have a “Selected Color Preview” field.

Create another Quad and position it just below the wheel like this.

Create a new Material and name it “SelectedColor

Assign the material to the “Selected Color Preview” Renderer

Change the Shader to “Unlit/Color

We don’t want light having any impact on how our drawing appears.  Unlit/Color makes that not an issue.

It should look like this in the inspector.

Brush Size Slider

Let’s also add a brush size slider.

Create a new Slider from the GameObject->UI menu.

Move it so it looks like this.  (I also added a text object at the top, feel free to do that too if you want)

Create a new script named “BrushSizeSlider.cs” and replace the contents with this.

BrushSizeSlider Code

This class is really just wrapping the slider value so we don’t have to reference it anywhere in the editor.  Because our player is network instantiated, and we don’t have any objects in the scene that would make sense referencing this slider, we’re just putting the BrushSize into a static global int.  This isn’t the best architecture for something like this, but we’re not building out a full game or editor so it’s a quick enough way to get things working.

Add the BrushSizeSlider component to your slider GameObject.

Your slider should look like this.

Save your work to a scene!

Player & Brush Time

Now that we have the board setup, it’s time to create the player & brush.

Create a new script and name it “PlayerBrush.cs“.

Replace the contents with this.

PlayerBrush Code

This is the most important part of the project.  Here, we’re doing the drawing and networking.  (ideally we’d split this into 2 classes soon)

The Start method is only called on the server/host because of the [Server] tag.  That’s because the Start method is getting the texture data and sending it to the client.  This may be a little confusing, but remember that the “Player” will be spawned on the server, and this method is being called on the player gameobject but only on the host/server.

RpcSendFullTexture is the opposite.  It uses the [ClientRpc] tag because we only want that method being called on the clients (it’s also required to send the command to the client).  This method calls the SetAllTextureData method we covered earlier, setting the data of the client to match the server.

.Compress() & .Decompress() – These methods are extensions that you’ll see in a while.  They’re used to compress the texture data into something much smaller for network transmission.  The compression here is extremely important, without it, this wouldn’t work.

When you look at the Update method, it should feel familiar.  Like with the color picker, we’re checking for left mouse down, doing a raycast, and checking to see if the click was on what we wanted.  In this case, we’re looking to see if they have the mouse down on the PaintCanvas.

If they do, we get the texture coordinate (like before), get the pixel x & y, then we send a command to the server using CmdBrushAreaWithColorOnServer.  We also call BrushAreaWithColor on the client (if we don’t do this, the pixel won’t change until the server gets the message, handles it, and sends one back.  this would feel laggy and bad, so we need to call the method on the client immediately).

CmdBrushAreaWithColorOnServer doesn’t really do any work itself.  It’s a [Command] so clients can call it on the server, but all it really does is tell the clients to brush the area using an Rpc.  It also tells the server/host to draw using BrushAreaWithColor.

BrushAreaWithColor is responsible for changing the pixels.  It does looping over the brush size to get all the pixels surrounding the clicked one.  It does this in a simple square pattern.  If you wanted to change the brush to be circular or some other shape, this is the method you’d modify.

Back to the Inspector

Create a new “Empty GameObject“.

Name it “Player

Add a NetworkIdentity component to it & check the “Local Player Authority” box.

Add the “PlayerBrushcomponent.

Your Player object should look like this.

Drag the Player object into a folder named Prefabs.  This will make your player a prefab so we can instantiate it for network play.

Error! – An Extension Method!

The playerbrush script references some compression methods that we’ll use to sync data to the clients when they first connect.

To add these compression methods, let’s create a new script for our extension methods.  If you don’t know what extension methods are, you can read more about them here: Unity Extension Methods

Create a new script named “ByteArrayExtensions.cs” & replace the contents with this.

ByteArrayExtensions Code

I won’t go into the details on how this compression works, but this is some standard c# code for doing a quick in memory compression of data.  These are extension methods that will ‘extend’ the byte arrays.  It’s essentially just a cleaner way so we can write somearray.Compress() instead of ByteArrayExtensions.Compress(somearray).

The Networkmanager

The last thing we need is a networkmanager.

Create a new gameobject and name it “[NetworkManager]“.

Add the NetworkManager component to it.

Add the NetworkManagerHUD component to it.

Expand the NetworkManager component.

Drag the “Player” prefab from your Prefabs folder (NOT THE SCENE VIEW ONE).. onto the “Player Prefab” area of the component.

The work is done, Save your Scene!

Testing the game

Now that everything’s setup, it’s time to test.

To do this, create an executable build (make sure to add your scene to the build settings).

In one instance, start a LAN host, then the other can join.


If you want to download the full working project sample, it’s available here:

Online Multiplayer

If you want to go beyond LAN mode, you’ll need to enable Multiplayer in your Services window.  It will take you to the Unity webpage where you’ll need to set a maximum room size.  For my test I went with 8 players.

Conclusion & Notes

This project is meant only to be an example for UNET & drawing.  To keep things simple, I used quite a few static fields, which I’d highly recommend against in a real project of any size.



Continue reading >

VR Movement – Ironman / Jetpack Flying with SteamVR

There are a lot of interesting movement systems for VR.  Arm swinging, dashing, teleportation, trackpad, and more.  In this guide, I’ll show you another one I experimented with previously and really enjoyed.  We’ll go over how to make a player fly like Ironman or at least like a person holding some jet packs..


This article assumes you have SteamVR in your project, though converting it to OVR native should be a simple task.

Rigidbody on [CameraRig]

Start by adding the [CameraRig] prefab from the SteamVR package to your scene.

Add a Rigidbody component to the camerarig.

Freeze the rotation values.

Locking rotation is very important, if you don’t, your player will end up spinning around, flipping over, and getting sick

Now, add a box collider to the rig so you can land (this could be a capsule or any other collider that works well for your game)

Controller Setup

Expand the CameraRig and select both controllers.

Add the SteamVR_TrackedController component to them both.

JetpackBasic Script

Create a new script, name it “JetpackBasic”

Replace the contents with this.

Your controller should look similar to this: (the sphere collider and audio source are optional and beyond the scope of this article)

Press Play

Aim the controllers where you want to go.

Pull the trigger.


Continue reading >
1 2 3 4
Page 1 of 4