GameDev Diary: Adding Basic Animations and Menus

Andrew Lukes
5 min readAug 31, 2023

--

Improving on the UI and UX aspects of my video game

Welcome back! Today, I’m excited to share with you the progress I’ve made in enhancing the User Experience. I’ve incorporated several new features, including basic pixel-art animation, a start screen, an end screen, and settings options.

Start Screen
End Screen
Animations
UI
Settings
Conclusion

Start Screen

The start screen is the first screen the player will see when opening the game. Currently, it consists of two buttons: one for starting a new game and another to go into the settings. I am thinking about adding screenshots from the game, so it wouldn't be just a plain brown background.

def handle_start_screen():
if not screen_set_up:
set_up_game_screen()

screen.fill(BRIDGE_COLOR)

# Create a font object
font = pygame.font.Font(None, 36)

# Render the text
text = font.render("BATTELFORGE", True, (255, 255, 255))

# Get the size of the text
text_width, text_height = text.get_size()

# Calculate the position of the text
text_x = (WIDTH - text_width) / 2
text_y = (HEIGHT - text_height) / 2 - 100

# Blit the text onto the screen
screen.blit(text, (text_x, text_y))

game_state.start_game_button.draw(screen)
game_state.settings_button.draw(screen)

for event in pygame.event.get():
if event.type == pygame.QUIT:
print(event)
game_state.lets_continue = False

if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if game_state.start_game_button.rect.collidepoint(event.pos):
game_state.start_game_button.callback()
elif game_state.settings_button.rect.collidepoint(event.pos):
game_state.settings_button.callback()

# Render everything on the display
pygame.display.update()

clock.tick(fps)

End Screen

After the game ends, or one of the players gives up, a new screen will show up containing the result of the game. This means who won and some basic stats, like how many moves were played, how many shots were fired, or how many units each player lost. The end screen contains a button back to the start screen

Animations

Recently I have found out, that I can easily create and add gifs into the game using a free tool called “Pixilart” (#notsponsored). Even if it does not align perfectly with the graphical style of the game, I am glad I can add some custom animation to the game and experiment with the tools for future projects.

import pygame
import os
from config import *
from utils.render_utils import draw_ui, draw_units
import game_state

class Animation:
def __init__(self, x, y, animation_folder, switch_speed=50, resize=None):
self.resize = resize
self.images = self.load_animation(animation_folder)
self.start_time = pygame.time.get_ticks()
self.switch_speed = switch_speed # Switch image every 'switch_speed' milliseconds
self.current_frame = 0
self.x = x
self.y = y
self.animation_ended = False

def __repr__(self):
return f'{type(self).__name__} '

def load_animation(self, animation_folder):
images = []
for filename in os.listdir(animation_folder):
if filename.endswith(".png"):
img = pygame.image.load(
os.path.join(animation_folder, filename))
if self.resize:
img = pygame.transform.scale(img, self.resize)
images.append(img)
return images

def render(self):


# Update animation
current_time = pygame.time.get_ticks()
elapsed_time = current_time - self.start_time
if elapsed_time >= self.switch_speed:
self.current_frame = (self.current_frame + 1) % len(self.images)
self.start_time = current_time

# Render current frame
frame = self.images[self.current_frame]

screen.blit(frame, (self.x, self.y))

# Check if animation has ended
if self.current_frame == len(self.images) - 1:
self.animation_ended = True

game_state.animations.remove(self)
del self

Some footage of me playtesting the game:

UI

In order to better orient in the gameboard I included icons and a graphical interface. When you hover over a unit, you will see its stats like ammo, hp, and lives. You will also immediately see the units' movement area, even when you hover over an enemy unit. When there is a change in the amount of ammunition for the unit, a proper animation will play. And lastly, when a unit misses an attack (determined by a random chance) a message will appear over the attacked unit.

Settings

Inside the new settings bar, you can now generate the game based on your desires. You can choose the number of towns, rivers, and roads, as well as manage the number of units the players will be starting with. You can set the units for each player individually allowing you to create custom battles.

class Slider:
def __init__(self, label, min_value, max_value, connected_value, update_function, x, y):
"""Initialize the slider."""
self.label = label
self.min_value = min_value
self.max_value = max_value
self.value = connected_value
self.update_function = update_function
self.x = x
self.y = y
self.slider_start = self.x + 100
self.slider_end = self.slider_start + 100
self.slider_rect = pygame.Rect(self.slider_start,self.y -15, self.slider_end - self.slider_start +10, 30)
settings_bars.append(self)
def draw(self, screen):
"""Draw the slider on the screen."""

# draw the label
text = default_font.render(self.label, True, BLACK)
text_rect = text.get_rect(center=(self.x + 50, self.y))
screen.blit(text, text_rect)

# draw the slider
pygame.draw.rect(screen, BLACK, (self.slider_start, self.y - 10, 100, 20), 1)
pygame.draw.rect(screen, BLACK,
(self.x + 100 + int(100 * (self.value - self.min_value) / (self.max_value - self.min_value)) - 5,
self.y - 15,
10,
30))

# draw the current value of the slider
value_text = default_font.render(str(self.value), True, BLACK)
value_text_rect = value_text.get_rect(center=(self.slider_start + 50, self.y - 25))
screen.blit(value_text, value_text_rect)

def handle_click(self, pos):
"""Handle click events on the slider."""

# update the value of the slider based on the click position
new_value = int((pos[0] - self.x - 100) * (self.max_value - self.min_value) / 100) + self.min_value
# ensure that the new value is within the valid range
new_value = max(self.min_value, min(new_value, self.max_value))
if new_value != self.value:
# update the value of the connected variable using the update function
# self.update_function(new_value)
# update the value of the slider
self.value = new_value

Conclusion

To sum it up this is what I added:

  • Start Screen: Here you can navigate the menu and start the game
  • End screen. A summary of the result of the battle
  • Art: Pixel art animation is used to convey more game information to the player
  • Settings screen: Here you can augment the game generation

Check out the previous article here

Check out the next article here

Note: feel free to use any code I am sharing in these articles!

--

--

Andrew Lukes

Introducing Andrew Lukes: a Prague web dev & language enthusiast who shares his ideas on Medium. You can visit andrewebdev.online to see some of my projects