Tag Archives: C#

How to Debug a Unity APK on an Android device with Visual Studio

Oh my goodness this was far too difficult… so I had to write it up! This guide assumes you have some experience with Unity, debugging in Visual Studio, and building APK’s (let me know if you don’t in the comments!).

If you’re using Unity, you’re coding in C#, and you’re using Visual Studio… Here’s how you can setup a remote debugger to debug your APK on an Android device.

I’m currently using the following tools but the steps are generally the same:

Unity v2020.1.7f1

Visual Studio Community 2019

Android Studio v3.5 & SDK

Samsung Galaxy S9

Step 1: When you build your APK you’ll want to tick 2 boxes on the build settings menu. ‘Development Build‘ & ‘Script Debugging

Step 2: Create your build as usual and copy the build to your Android device. Connect your Android Device to your PC via USB. Be sure your machine and Android device are connected to the same wifi network.

Step 3: If you haven’t previously, Enable USB Debugging on your Android Device.

  1. Open Settings
  2. Select System
  3. Scroll to the bottom and select About Phone
  4. Scroll to the bottom and tap ‘Build Number’ 7 times
  5. Return to the previous screen and find ‘Developer Options’ near the bottom
  6. Scroll down and select to enable ‘USB Debugging’
Advertisements

Step 4: Back on your computer, open up a cmd prompt (or terminal) as an administrator and change your directory to:

C:\Users\[user]\AppData\Local\Android\sdk\platform-tools

Step 5: Back on your Android Device, find the Android Device’s IP by going to:

  1. Go to Settings
  2. Go to ‘About Phone’
  3. Got to ‘Status’
  4. Find ‘IP Address’
  5. Write it down…

Step 6: Back in your command prompt enter the following command:

adb tcpip 5555

If you need some extra help see the Unity Documentation here

Step 7: Connect to your Device with this command using your IP from Step 5:

adb connect [YourIpAddress]:5555
Advertisements

Step 8: Open Visual Studio from within Unity and go to the ‘Debug’ menu option. Select ‘Attach Unity Debugger’

Step 9: You should see a small menu popup and it should display both your computer and your connected Android device. Select your Android device, set some break points in your code, and have fun!

Hopefully this guide saves you some time and headache on trying to figure this out. If you need more information on connecting your device that this guide doesn’t provide let me know so I can update it!

Taking your Objects for a Swim

There are times while we’re coding that we need to create a number of objects to handle various workloads. This could be a Factory producing a number of enemies for a game or a SaaS application firing up multiple instances of a worker process.



Whenever we start dealing with a number of the same object like this we have to start considering object management, the lifetime of the objects, and garbage collection. If we don’t we’ll have to deal with out of memory exceptions, rouge processes, and bugs, bugs, bugs…

photo cred: Wynand Uys

Thankfully there’s a solid way to handle all of these objects, not only in a clean way, but in an efficient way. That way is called, Object Pooling.

Object Pooling is the concept of taking each of our created objects and placing them into a group or “pool“. Then when our game or application needs to use one of these objects, we provide a way to check that pool, find an inactive object, activate it, and return it to the caller.

Advertisements

If we check our pool and find there are no free objects available because they’re all already in use somewhere else, then we can provide the functionality for our pool to create us a brand new object, add it to the pool, and return it to our caller.

When our callers are done with their objects they can shut themselves off and remain inactive in our pool until another caller needs to request the object. Whew… okay that got technical so let’s break it down a little bit and see how it looks in code:

//our "pool" of enemies
List<Enemy> enemies = new List<Enemy();

//our function to check our pool for an enemy that is inactive
public Enemy GetEnemy()
{
   foreach (var enemy in enemies)
   {
       if (!enemy.IsActive())
         return enemy;
   }
}

So in a very basic example we have our “pool” and a way to get inactive objects out of that pool. But what happens if there aren’t any objects in our pool to begin with? What happens if there are some objects in our pool but they’re all in use and there aren’t any in active ones to be returned? Let’s see what else we can add to fix this.

Advertisements
//let's add some functionality to create a new enemy if our list has none 

//our function to check our pool for an enemy that is inactive
public Enemy GetEnemy()
{
   //loop over our pool and find an inactive enemy to return
   foreach (var enemy in enemies)
   {
       if (!enemy.IsActive())
         return enemy;
   }

   //if no enemy returned, create a new one and add it to the pool
   var enemy = new Enemy();
   enemies.Add(enemy);
   return enemy;
}

So what did we change here? Well we gave our GetEnemy() function the ability to not only find an inactive object to return to the caller but we added the ability for it to create a new enemy if there aren’t any available enemies to return. This means that no matter what, when we call GetEnemy() we are guaranteed to get an available object returned back to us.

photo cred: Joe Calata

This is essentially the bread and butter of Object Pooling, but why is this better and what are the advantages?

  1. We get a single place to find and get an available object
  2. We’re not forcing our application to create and destroy objects over-and-over, eating up resources.
  3. We’re not allowing our objects to run free. They’re all contained and managed in our “pool” and if we wanted to, we could turn them all off.

Now how do we know when the best time is to use Object Pooling? If you find you’re creating and destroying a number of the same object, repeatedly overtime, you should be using Object Pooling. The performance gains are significant and the pattern can be implemented in any scenario.