🎮 Building an Animated Hangman Game in Python (Tkinter) — Step by Step
Source: Dev.to
🧰 What We’ll Use
- Python 3
- Tkinter (GUI framework)
- ttk (styled widgets)
- sv‑ttk (modern light/dark themes)
📦 Step 1 – Imports & Dependencies
import sys
import os
import random
import tkinter as tk
from tkinter import ttk, messagebox
import sv_ttk
Why these imports?
| Module | Purpose |
|---|---|
random | Choose random words |
tkinter | Build the GUI |
ttk | Nicer‑looking widgets |
messagebox | Pop‑up dialogs |
sv_ttk | Modern light/dark theme support |
🧠 Step 2 – Helper Functions
Loading files correctly (even after packaging)
def resource_path(file_name):
base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, file_name)
This helper ensures file paths work correctly if you later bundle the app with tools like PyInstaller.
Updating the status bar
def set_status(msg):
status_var.set(msg)
root.update_idletasks()
Updates the status message at the bottom of the app in real time.
🪟 Step 3 – Create the Main App Window
root = tk.Tk()
root.title("Animated Hangman Game")
root.geometry("700x850")
sv_ttk.set_theme("light")
Tk()creates the window.geometry()sets its size.sv_ttk.set_theme()applies a modern theme.
🌍 Step 4 – Global Game State
dark_mode_var = tk.BooleanVar(value=False)
word_list = ["PYTHON", "HANGMAN", "COMPUTER", "AI", "PROGRAMMING", "DEVELOPER"]
current_word = ""
guessed_letters = set()
wrong_guesses = 0
max_wrong = 6
UI‑bound variables
display_word_var = tk.StringVar()
status_var = tk.StringVar(value="Ready")
lives_var = tk.StringVar(value=f"Lives: {max_wrong}")
StringVarallows Tkinter widgets to update automatically when values change.
🌗 Step 5 – Dark‑Mode Toggle
def toggle_theme():
bg = "#2E2E2E" if dark_mode_var.get() else "#FFFFFF"
fg = "white" if dark_mode_var.get() else "black"
root.configure(bg=bg)
for w in ["TFrame", "TLabel", "TLabelframe", "TLabelframe.Label", "TCheckbutton"]:
style.configure(w, background=bg, foreground=fg)
guess_entry.configure(background=bg, foreground=fg)
hangman_canvas.configure(bg=bg)
Dynamically switches background and text colors when the checkbox is toggled.
🔁 Step 6 – Starting a New Game
def start_new_game():
global current_word, guessed_letters, wrong_guesses
current_word = random.choice(word_list)
guessed_letters = set()
wrong_guesses = 0
update_display_word()
lives_var.set(f"Lives: {max_wrong}")
draw_hangman(animated=False)
set_status("New game started! Guess a letter.")
Resets everything: picks a new word, clears guesses, and resets the hangman drawing.
🔤 Step 7 – Updating the Word Display
def update_display_word():
display = " ".join(
c if c in guessed_letters else "_" for c in current_word
)
display_word_var.set(display)
# Win condition
if "_" not in display:
set_status("Congratulations! You guessed the word!")
messagebox.showinfo("Winner!", f"You correctly guessed: {current_word}")
Example output:
P Y T H O N
❓ Step 8 – Guessing a Letter
def guess_letter():
global wrong_guesses
letter = guess_var.get().strip().upper()
guess_var.set("")
Validate input
if not letter or len(letter) != 1 or not letter.isalpha():
set_status("Please enter a single letter.")
return
Prevent duplicate guesses
if letter in guessed_letters:
set_status(f"You already guessed '{letter}'.")
return
Handle correct vs. wrong guesses
guessed_letters.add(letter)
if letter not in current_word:
wrong_guesses += 1
lives_var.set(f"Lives: {max_wrong - wrong_guesses}")
draw_hangman(animated=True)
# Game‑over logic
if wrong_guesses >= max_wrong:
messagebox.showinfo("Game Over", f"The word was: {current_word}")
start_new_game()
return
update_display_word()
🎨 Step 9 – Drawing the Hangman
Base structure (always drawn)
def draw_hangman(animated=True):
hangman_canvas.delete("all")
# Scaffold
hangman_canvas.create_line(50, 350, 250, 350, width=3) # Ground
hangman_canvas.create_line(150, 350, 150, 50, width=3) # Pole
hangman_canvas.create_line(150, 50, 300, 50, width=3) # Top beam
hangman_canvas.create_line(300, 50, 300, 100, width=3) # Rope
Body parts (added per mistake)
parts = []
if wrong_guesses >= 1:
parts.append(("oval", 275, 100, 325, 150)) # Head
if wrong_guesses >= 2:
parts.append(("line", 300, 150, 300, 250)) # Body
if wrong_guesses >= 3:
parts.append(("line", 300, 180, 260, 220)) # Left arm
if wrong_guesses >= 4:
parts.append(("line", 300, 180, 340, 220)) # Right arm
if wrong_guesses >= 5:
parts.append(("line", 300, 250, 260, 300)) # Left leg
if wrong_guesses >= 6:
parts.append(("line", 300, 250, 340, 300)) # Right leg
Render (with optional animation)
for i, (shape, *coords) in enumerate(parts):
if animated:
# Simple animation: draw each part after a short delay
root.after(i * 200, lambda s=shape, c=coords: draw_part(s, *c))
else:
draw_part(shape, *coords)
def draw_part(shape, *coords):
if shape == "oval":
hangman_canvas.create_oval(*coords, width=3)
elif shape == "line":
hangman_canvas.create_line(*coords, width=3)
🎬 Step 10 – Wire Everything Up (UI Layout)
style = ttk.Style()
# Top frame – title & theme toggle
top_frame = ttk.Frame(root, padding=10)
top_frame.pack(fill="x")
title_lbl = ttk.Label(top_frame, text="Hangman", font=("Helvetica", 24))
title_lbl.pack(side="left")
theme_chk = ttk.Checkbutton(
top_frame,
text="Dark mode",
variable=dark_mode_var,
command=toggle_theme
)
theme_chk.pack(side="right")
# Word display
word_frame = ttk.Frame(root, padding=10)
word_frame.pack(fill="x")
word_lbl = ttk.Label(word_frame, textvariable=display_word_var, font=("Consolas", 32))
word_lbl.pack()
# Canvas for the drawing
hangman_canvas = tk.Canvas(root, width=400, height=400, bg="white", highlightthickness=0)
hangman_canvas.pack(pady=10)
# Guess entry & button
guess_frame = ttk.Frame(root, padding=10)
guess_frame.pack(fill="x")
guess_var = tk.StringVar()
guess_entry = ttk.Entry(guess_frame, textvariable=guess_var, width=5, font=("Helvetica", 18))
guess_entry.pack(side="left", padx=(0, 5))
guess_btn = ttk.Button(guess_frame, text="Guess", command=guess_letter)
guess_btn.pack(side="left")
# Lives & status bar
status_frame = ttk.Frame(root, padding=5)
status_frame.pack(fill="x", side="bottom")
lives_lbl = ttk.Label(status_frame, textvariable=lives_var)
lives_lbl.pack(side="left")
status_lbl = ttk.Label(status_frame, textvariable=status_var, anchor="e")
status_lbl.pack(side="right", fill="x", expand=True)
# Start the first game
start_new_game()
root.mainloop()
🎉 You’re Done!
Run the script, toggle dark mode, and enjoy an animated Hangman experience built entirely with the standard Python library. Feel free to extend it with:
- A larger word list (load from a file).
- Sound effects using
winsoundorpygame. - A high‑score tracker.
Happy coding!
Animated Hangman – Code Walk‑through
Below is a cleaned‑up version of the markdown segment. All original code, headings, and content are preserved, but the stray “Enter fullscreen mode / Exit fullscreen mode” lines have been removed and the code blocks are properly fenced.
animate_parts – Draw the Hangman step‑by‑step
def animate_parts(parts, idx=0):
"""Recursively draw each part of the hangman with a short delay."""
if idx >= len(parts):
return
# Draw an oval (the head)
if parts[idx][0] == "oval":
hangman_canvas.create_oval(*parts[idx][1:], width=3)
# Draw a line (any limb)
else:
x1, y1, x2, y2 = parts[idx][1:]
hangman_canvas.create_line(x1, y1, x2, y2, width=3)
# Wait a bit, then draw the next part
hangman_canvas.after(400, lambda: animate_parts(parts, idx + 1))
🎛 Step 11: UI Layout
Main container
main = ttk.Frame(root, padding=20)
main.pack(expand=True, fill="both")
Canvas
hangman_canvas = tk.Canvas(main, width=400, height=400, bg="white")
hangman_canvas.grid(row=1, column=0, pady=10)
Input & buttons
guess_var = tk.StringVar()
guess_entry = ttk.Entry(
main,
textvariable=guess_var,
font=("Segoe UI", 16),
width=5,
)
guess_entry.grid(row=4, column=0)
ttk.Button(main, text="Guess", command=guess_letter).grid(row=5, column=0)
▶️ Step 12: Run the App
start_new_game()
root.mainloop()
This starts the game loop and opens the window.
🎉 Final Result
You now have:
- ✅ Animated hangman drawing
- 🌗 Light / Dark mode
- 🎯 Input validation
- 🧠 Game‑state handling
- 🎨 Modern UI styling
🚀 Next Ideas
- Add difficulty levels
- Load words from a file
- Add keyboard input
- Track high scores
- Package as an
.exe
Preview
All code snippets are ready to be copied into your project.
