Make 2D games with Python - No C++ required!
Source Code • Downloads • Quickstart • Tutorials • API Reference • Cookbook • C++ Extensions
Practical code snippets you can copy and paste into your games.
A simple text input field that captures keyboard input. Perfect for player names, chat messages, or console commands.
import mcrfpy
# Create scene
mcrfpy.createScene("text_demo")
mcrfpy.setScene("text_demo")
# Create UI elements
ui = mcrfpy.sceneUI("text_demo")
# Background frame for the input field
input_frame = mcrfpy.Frame(50, 100, 300, 30)
input_frame.fill_color = (255, 255, 255, 255)
input_frame.outline_color = (100, 100, 100, 255)
input_frame.outline = 2
ui.append(input_frame)
# Text display
text_display = mcrfpy.Caption("", 55, 107)
text_display.fill_color = (0, 0, 0, 255)
ui.append(text_display)
# Cursor (blinking underscore)
cursor = mcrfpy.Caption("_", 55, 107)
cursor.fill_color = (0, 0, 0, 255)
ui.append(cursor)
# Input state
text_content = ""
cursor_visible = True
def update_display():
"""Update the text display and cursor position"""
text_display.text = text_content
# Simple cursor positioning (works for monospace fonts)
cursor_x = 55 + len(text_content) * 8
cursor.x = cursor_x
def toggle_cursor(timer_name):
"""Blink the cursor"""
global cursor_visible
cursor_visible = not cursor_visible
cursor.visible = cursor_visible
# Set up cursor blinking
mcrfpy.setTimer("cursor_blink", toggle_cursor, 500)
def handle_input(key, state):
"""Handle keyboard input"""
global text_content
if state != "start": # Only handle key press, not release
return
# Handle special keys
if key == "Backspace" and len(text_content) > 0:
text_content = text_content[:-1]
update_display()
elif key == "Return":
print(f"Submitted: {text_content}")
text_content = ""
update_display()
# Handle alphanumeric input
elif len(key) == 1 and key.isprintable():
text_content += key
update_display()
# Handle space
elif key == "Space":
text_content += " "
update_display()
# Register keyboard handler
mcrfpy.keypressScene(handle_input)
# Initial display update
update_display()
For multiple text fields with focus management, use this reusable widget class:
import mcrfpy
class TextInput:
"""Reusable text input widget"""
def __init__(self, x, y, width, height=30, placeholder="", on_submit=None):
self.x = x
self.y = y
self.width = width
self.height = height
self.placeholder = placeholder
self.on_submit = on_submit
self.text = ""
self.focused = False
self.cursor_pos = 0
# Create UI elements
self.frame = mcrfpy.Frame(x, y, width, height)
self.frame.fill_color = (255, 255, 255, 255)
self.frame.outline_color = (128, 128, 128, 255)
self.frame.outline = 2
self.text_display = mcrfpy.Caption("", x + 5, y + 7)
self.text_display.fill_color = (0, 0, 0, 255)
self.placeholder_display = mcrfpy.Caption(placeholder, x + 5, y + 7)
self.placeholder_display.fill_color = (180, 180, 180, 255)
self.cursor = mcrfpy.Caption("|", x + 5, y + 7)
self.cursor.fill_color = (0, 0, 0, 255)
self.cursor.visible = False
# Set click handler
def on_click():
self.focus()
self.frame.click = on_click
def add_to_scene(self, ui):
"""Add widget to scene UI"""
ui.append(self.frame)
ui.append(self.placeholder_display)
ui.append(self.text_display)
ui.append(self.cursor)
def focus(self):
"""Give focus to this input"""
self.focused = True
self.frame.outline_color = (0, 120, 215, 255) # Blue when focused
self.cursor.visible = True
self._update_display()
def blur(self):
"""Remove focus from this input"""
self.focused = False
self.frame.outline_color = (128, 128, 128, 255)
self.cursor.visible = False
def _update_display(self):
"""Update text and cursor display"""
if self.text:
self.text_display.text = self.text
self.placeholder_display.visible = False
# Update cursor position (assumes ~8 pixels per character)
self.cursor.x = self.x + 5 + len(self.text) * 8
else:
self.text_display.text = ""
self.placeholder_display.visible = True
self.cursor.x = self.x + 5
def handle_key(self, key):
"""Process keyboard input"""
if not self.focused:
return False
if key == "Backspace" and self.cursor_pos > 0:
self.text = self.text[:self.cursor_pos-1] + self.text[self.cursor_pos:]
self.cursor_pos -= 1
elif key == "Return":
if self.on_submit:
self.on_submit(self.text)
self.text = ""
self.cursor_pos = 0
elif len(key) == 1 and key.isprintable():
self.text = self.text[:self.cursor_pos] + key + self.text[self.cursor_pos:]
self.cursor_pos += 1
elif key == "Space":
self.text = self.text[:self.cursor_pos] + " " + self.text[self.cursor_pos:]
self.cursor_pos += 1
elif key == "Left" and self.cursor_pos > 0:
self.cursor_pos -= 1
elif key == "Right" and self.cursor_pos < len(self.text):
self.cursor_pos += 1
else:
return False
self._update_display()
return True
# Example usage
mcrfpy.createScene("form_demo")
mcrfpy.setScene("form_demo")
ui = mcrfpy.sceneUI("form_demo")
# Create multiple input fields
name_input = TextInput(50, 50, 300, placeholder="Enter your name",
on_submit=lambda text: print(f"Name: {text}"))
email_input = TextInput(50, 100, 300, placeholder="Enter your email",
on_submit=lambda text: print(f"Email: {text}"))
name_input.add_to_scene(ui)
email_input.add_to_scene(ui)
# Track focused input
current_input = None
def handle_keys(key, state):
"""Global keyboard handler"""
global current_input
if state != "start":
return
# Tab to switch between inputs
if key == "Tab":
if current_input == name_input:
name_input.blur()
email_input.focus()
current_input = email_input
else:
email_input.blur()
name_input.focus()
current_input = name_input
elif current_input:
current_input.handle_key(key)
# Register keyboard handler
mcrfpy.keypressScene(handle_keys)
# Focus first input by default
name_input.focus()
current_input = name_input
Keyboard Input: McRogueFace sends key names like “A”, “Space”, “Return”, “Backspace”, etc. to your handler function.
Focus Management: Only one input should be focused at a time. Use visual indicators like outline color to show which input is active.
Cursor Positioning: For precise cursor positioning with proportional fonts, you’ll need to measure text width. The examples above assume monospace fonts.
Special Characters: To handle shift states and special characters properly, track whether shift is pressed:
shift_pressed = False
def handle_keys(key, state):
global shift_pressed
if key in ["LShift", "RShift"]:
shift_pressed = (state == "start")
return
if state == "start" and len(key) == 1:
char = key.upper() if shift_pressed else key.lower()
# Add char to input...
# Numeric only input
if key.isdigit():
self.text += key
# Max length
if len(self.text) < self.max_length:
self.text += key
self.text_display.text = "*" * len(self.text)
More recipes will be added here for common game development patterns like: