Welcome to part 2 of the StarCraft II AI tutorials. In the previous tutorial, we wrote a basic bot that just collects resources with available workers. Now, we'd like to get more workers so we can get supplies faster!
Starting code from previous tutorial:
import sc2 from sc2 import run_game, maps, Race, Difficulty from sc2.player import Bot, Computer class SentdeBot(sc2.BotAI): async def on_step(self, iteration): # what to do every step await self.distribute_workers() # in sc2/bot_ai.py run_game(maps.get("AbyssalReefLE"), [ Bot(Race.Protoss, SentdeBot()), Computer(Race.Terran, Difficulty.Easy) ], realtime=True)
This was pretty easy for us, because the distribute_workers
method already existed. We wont have this luxury for everything. For example, we need more workers. Let's add a call to a build_workers
method to our class:
class SentdeBot(sc2.BotAI): async def on_step(self, iteration): # what to do every step await self.distribute_workers() # in sc2/bot_ai.py await self.build_workers()
This build_workers
method doesn't exist, however. We need to make it. In order to make workers, we need to access our NEXUS
object in the game. The Nexus is the "command center" for the Protoss race. We intend to make workers, which are called "Probes" for the Protoss class, so we also need to interact with the PROBE
object. Let's import them:
from sc2.constants import NEXUS, PROBE, PYLON
Now, in order to build workers, we need to use the nexus, or one of our nexus buildings anyway, and then, if we can afford another probe, let's build one! Another small detail is that buildings that produce units like this can only make a handful at a time, such as 5. When a human is the player, it can be useful to just queue up all 5 things at once, so they can go do other things at the same time. When an AI is playing, however, there's no point to occupying up the queue. Unlike the human, you can manage every unit and building simultaneously. Humans are *so* weak and slow!
So to build our workers, our build_workers
method:
async def build_workers(self): # nexus = command center for nexus in self.units(NEXUS).ready.noqueue: if self.can_afford(PROBE): await self.do(nexus.train(PROBE))
We could run this, but we're going to hit an issue with Supply
. We need to build more pylons
in order to increase our "supply," which is basically how many units we're allowed to have produced (units, as in workers, fighters, ships...etc). Okay, so then we want to create these Pylons then. Let's add an await self.build_pylons()
to our on_step
method:
class SentdeBot(sc2.BotAI): async def on_step(self, iteration): # what to do every step await self.distribute_workers() # in sc2/bot_ai.py await self.build_workers() # workers bc obviously await self.build_pylons() # pylons are protoss supply buildings
Next, let's build the build_pylons
method. What we will do here is, if our remaining supply is 'n' or less, then we want to build more pylons. We want to build pylons around our Nexus buildings/our general base. The Protoss class requires you to build your buildings within the "Psionic Matrix" zone. Pylons extend this matrix, and increase your supply.
async def build_pylons(self): if self.supply_left < 5 and not self.already_pending(PYLON): nexuses = self.units(NEXUS).ready if nexuses.exists: if self.can_afford(PYLON): await self.build(PYLON, near=nexuses.first)
Notice we also want to make a check to make sure we don't already have a Pylon being built, otherwise we'll just be making a bunch of them and wasting resources.
Running this code, we produce more pylons and workers as needed and possible:
In the next tutorial, we're going to work on expansion and collecting the other resource: gas.