GameDev Diary: Buying Units, Getting Buffs, and Defense Bonuses
Adding depth to my Python game
I warmly welcome everyone to another installment of my game dev diary. I have added a lot of new features to the game, which I will share with you in this article.
- I wanted to include a demo file, but sadly there seems to be a problem with the compilation.
∘ Buying Units
∘ Money Settings
∘ Cursor Improvements
∘ Defense Bonuses
∘ Improved Cities
· Conclusion
Buying Units
So far the player was only able to play with the units he was given at the start of the game. Now I am changing that. In the new version, you are able to pick up a unit from the buy menu at the bottom of the screen and place it somewhere inside your buy area. The unit price will be subtracted from your current balance, which replenishes at 10 supplies per turn. You will be able to buy pikemen, musketeers, canons, shields, and medics.
def buy_unit(self, click_pos):
def check_unit_overlap(unit, player, bought_unit):
if unit == bought_unit:
return False
# create a copy of the unit.rect object
rect_copy = unit.rect.copy()
# inflate the copy of the rect object
rect_copy.inflate_ip(bought_unit.size, bought_unit.size)
# check if the inflated copy of the rect object collides with the click position
if rect_copy.collidepoint(click_pos):
return True
def check_valid_placement_position():
if background_screen.get_at((click_pos[0], click_pos[1])) == RIVER_BLUE:
abort_placement_mode(player, bought_unit)
return False
buy_area_rect = pygame.Rect(*player.buy_area)
buy_area_rect.inflate_ip(-bought_unit.size //
2, -bought_unit.size//2)
if not buy_area_rect.collidepoint(click_pos):
print("Cannot place unit outside of buy area.")
return False
return True
def point_in_occupied_town():
for town in player.occupied_towns:
if town.rect.collidepoint((cursor_x,cursor_y)):
return True
return False
player = game_state.players[game_state.cur_player]
bought_unit = player.preview_unit
cursor_x, cursor_y = pygame.mouse.get_pos()
print("PREVIEW UNIT", bought_unit)
for unit in game_state.living_units.array:
res = check_unit_overlap(unit, player, bought_unit)
if res:
return
if bought_unit:
check_valid_placement_position()
if not check_valid_placement_position() and not point_in_occupied_town():
# abort_placement_mode(bought_unit)
return
else:
player.preview_unit = None
game_state.unit_placement_mode = False
game_state.money_spent += bought_unit.cost
else:
print(
f"Error: Unit type {bought_unit} not found.")
Money Settings
Inside the settings bar, you can now increase the money the player starts with up to 1000$ and the per-turn income to 100$.
Cursor Improvements
When you now hover on interactable objects like buttons, units, or sliders. Your cursor will change to a hand.
def set_cursor():
global hovered_slider
if game_state.hovered_button != None or game_state.hovered_unit != None or hovered_slider != None:
pygame.mouse.set_cursor(pygame.SYSTEM_CURSOR_HAND)
else:
pygame.mouse.set_cursor(pygame.SYSTEM_CURSOR_ARROW)
Defense Bonuses
When Inside a forest, city, or near your commander, your troops will get an additional bonus to their attack resistance, which is the percentage chance of them being hit by an attack. Currently, forest decreases hit chance by 25%, town by 20% and commander proximity by 33%.
def apply_modifiers(self):
self.attack_resistances = {"base_resistance": 1 }
new_pos_color = game_state.pixel_colors[self.center[0]][self.center[1]]
if new_pos_color == FORREST_GREEN:
self.attack_resistances["IN FORREST" ] = 0.3
for town in game_state.battle_ground.towns:
if town.rect.collidepoint(self.center):
print("IN TOWN RECT", self)
self.attack_resistances["IN TOWN" ] = 0.1
break
for commander in game_state.living_units.dict["Commanders"]:
if commander.color == self.color and commander != self:
commander.give_deffense_boost(self)
Improved Cities
Now, cities actually have a functionality. When you leave your unit inside an uncontested city for a turn, it will capture it for you (signified by a change in the outline), and the city will start producing by default 10$ per turn for you. On top of that, you can buy units in those cities, allowing you to deploy them closer to the frontline. However, once you leave the city, it will automatically change to being neutral at the end of your turn.
def get_occupied_towns(self):
def get_units_inside_town():
units_inside_town = []
for unit in game_state.living_units.array:
if town.rect.collidepoint(unit.center):
units_inside_town.append(unit)
return units_inside_town
def check_controlled_by_one_team():
first_unit_color = units_inside_town[0].color
for unit in units_inside_town:
if unit.color != first_unit_color:
return False
return True
def occupy_town():
first_unit_color = units_inside_town[0].color
town.occupied_by = first_unit_color
def update_players_occupied_towns():
for player in game_state.players:
player.occupied_towns = []
for town in towns:
if player.color == town.occupied_by:
player.occupied_towns.append(town)
print("players occupied towns", player.occupied_towns)
towns = game_state.battle_ground.towns
# get the units, whose centers are inside of the town rect
for town in towns:
units_inside_town = get_units_inside_town()
if len(units_inside_town) < 1:
town.occupied_by = None
continue
units_are_same_color = check_controlled_by_one_team()
if units_are_same_color:
occupy_town()
update_players_occupied_towns()
player.supplies += game_state.money_per_turn + len(player.occupied_towns)* game_state.city_turn_revenue
Conclusion
In this article, we have discussed the latest improvements to Battleforge such as:
- Buying units from the bottom bar
- Functional cities give bonuses to the players occupying them
- UI improvements like a dynamic cursor
Check out the previous article here:
Check out the next article here