Hey everyone! I’ve been busy recently working on a really set of features that will enhance the ability for players to change up their strategy in my coding realtime strategy game Crash.
For those who are new, I am making a realtime strategy game where you can control your soldiers directly using Python code to fight the enemy and take down their base.
While making changes to the code in realtime is doable it’s probably not advisable since the matches are quite fast paced.
Say I wanted to spawn new units or tell my existing units to get into a specific formation depending on what’s happening in the game, this would be quite tough with the current setup.
Commands
To solve this I have created commands.
Say I wanted to spawn a line of units at a given y
position on the map, in my code all I have to do is create a function that takes in a parameter y
and mark it with the @command
notation:
@command("defensive_line")
def create_defensive_line(y : str):
global active_game
active_game.run_background(spawn_defensive_line(active_game, int(y)))
Where spawn_defensive_line
is a function like so:
async def spawn_defensive_line(game: Game, y = 1):
global arrow_prediction
while True:
defensive_units = [] # type: List[Unit]
global active_game
for i in range(0, game.grid.width):
if i%2 == 0:
await until (lambda: game.unit_manager.can_spawn_unit(UnitType.ARCHER))
try:
unit = await game.unit_manager.spawn_unit_at_tile(UnitType.ARCHER, i, y)
except:
pass
defensive_units.append(unit)
else:
await until (lambda: game.unit_manager.can_spawn_unit(UnitType.SOLDIER))
try:
unit = await game.unit_manager.spawn_unit_at_tile(UnitType.SOLDIER, i, y)
except:
pass
defensive_units.append(unit)
Now here’s the exciting part. In the game I just have to hit /
which will open up the command terminal:
Put in my command with any arguments I want, here 2 is the y-position
to spawn it at.
Just like that the units spawn just as they were programmed to!
In the background the command from the client simply sends a message to the Python side which interprets it and calls the function. The @command
annotation takes care of registering the command.
Mouse Events & Position
But why stop here? Wouldn’t it be nice if you could assign a group of units to be your specialist squad that would follow where your mouse clicked for very specialised attacks. Or what about spawning combinations of units exactly where you click.
So as part of the data payload I’m sending to Python I also send any mouse events and the world & screen position of the mouse and the player is free to do with that whatever they want.
And it’s this simple:
async def scout_regiment(game: Game):
while True:
await until(lambda: game.mouse.left_clicked)
for u in game.unit_manager.get_selected_units():
u.move_to(game.mouse.world_position)
Linked with my own couroutine system you can await until the mouse is clicked to do something.
I am also planning of implementing keyboard events in future but I think that may be overkill for now, but the mouse seems almost essential now that I’ve implemented it. Having a human controlled aspect provides so much freedom for more fluid strategies.
Control Panels
In an older iteration of the game I used to have support for a GUI control panel that would show up on screen in the client which was directly linked to the variables in the code. This was much easier to implement when I was utilising IronPython which allowed me to read / set values directly within Unity.
However this functionality is crucial as well.
Imagine you have an integer a
that you would like to control with a slider, I imagine you would simply be able to write:
game.control_panel.a = 3
Then in the game client a slider would pop up and when the user changes it, it would change the value in the code as well. I feel this would be the last missing element needed for players to very easily change their code on the fly and it would encourage code to be written in an extensible and fluid way.
I will definitely be creating a post when I get to the control panel so stay tuned!
See you all next time 🙂