11 KiB
Game Profile Manager
A PySDL2-based user profile management system designed for gamepad-only control with virtual keyboard input. This system allows players to create, edit, delete, and select user profiles for games using only gamepad inputs or directional keys, with no need for physical keyboard text input.
Features
- 640x480 Resolution: Optimized for retro gaming systems and handheld devices
- Create New Profiles: Add new user profiles with custom names using virtual keyboard
- Profile Selection: Browse and select active profiles
- Edit Settings: Modify profile settings including difficulty, volume levels, and preferences
- Delete Profiles: Remove unwanted profiles
- Gamepad/Directional Navigation: Full control using only gamepad/joystick inputs or arrow keys
- Virtual Keyboard: Text input using directional controls - no physical keyboard typing required
- JSON Storage: Profiles stored in human-readable JSON format
- Persistent Settings: All changes automatically saved
Installation
Requirements
- Python 3.6+
- PySDL2
- SDL2 library
Setup
# Install required Python packages
pip install pysdl2
# For Ubuntu/Debian users, you may also need:
sudo apt-get install libsdl2-dev libsdl2-ttf-dev
# Make launcher executable
chmod +x launch_profile_manager.sh
Usage
Running the Profile Manager
# Method 1: Use the launcher script
./launch_profile_manager.sh
# Method 2: Run directly with Python
python3 profile_manager.py
Gamepad Controls
Standard Gamepad Layout (Xbox/PlayStation compatible)
- D-Pad/Hat: Navigate menus up/down/left/right, control virtual keyboard cursor
- Button 0 (A/X): Confirm selection, enter menus, select virtual keyboard characters
- Button 1 (B/Circle): Go back, cancel action
- Button 2 (X/Square): Delete profile, backspace in virtual keyboard
- Button 3 (Y/Triangle): Reserved for future features
Keyboard Controls (Alternative)
- Arrow Keys: Navigate menus and virtual keyboard cursor
- Enter/Space: Confirm selection, select virtual keyboard characters
- Escape: Go back, cancel action
- Delete/Backspace: Delete profile, backspace in virtual keyboard
- Tab: Reserved for future features
Virtual Keyboard Text Input
When creating or editing profile names:
- Navigate: Use D-Pad/Arrow Keys to move cursor over virtual keyboard
- Select Character: Press A/Enter to add character to profile name
- Backspace: Press X/Delete to remove last character
- Complete: Navigate to "DONE" and press A/Enter to finish input
- Cancel: Navigate to "CANCEL" and press A/Enter to abort
Navigation Flow
- Main Menu: Create Profile → Select Profile → Edit Settings → Exit
- Profile List: Choose from existing profiles, or go back
- Create Profile: Use virtual keyboard to enter name, confirm with directional controls
- Edit Profile: Adjust settings using left/right navigation
Display Specifications
- Resolution: 640x480 pixels (4:3 aspect ratio)
- Optimized for: Retro gaming systems, handheld devices, embedded systems
- Font Scaling: Adaptive font sizes for optimal readability at low resolution
Profile Structure
Profiles are stored in user_profiles.json with the following structure:
{
"profiles": {
"PlayerName": {
"name": "PlayerName",
"created_date": "2024-01-15T10:30:00",
"last_played": "2024-01-20T14:45:00",
"games_played": 25,
"total_score": 15420,
"best_score": 980,
"settings": {
"difficulty": "normal",
"sound_volume": 75,
"music_volume": 60,
"screen_shake": true,
"auto_save": true
},
"achievements": [
"first_win",
"score_500"
]
}
},
"active_profile": "PlayerName"
}
Integration with Games
Loading Active Profile
import json
def load_active_profile():
try:
with open('user_profiles.json', 'r') as f:
data = json.load(f)
active_name = data.get('active_profile')
if active_name and active_name in data['profiles']:
return data['profiles'][active_name]
except (FileNotFoundError, json.JSONDecodeError):
pass
return None
# Usage in your game
profile = load_active_profile()
if profile:
difficulty = profile['settings']['difficulty']
sound_volume = profile['settings']['sound_volume']
Updating Profile Stats
def update_profile_stats(score, game_completed=True):
try:
with open('user_profiles.json', 'r') as f:
data = json.load(f)
active_name = data.get('active_profile')
if active_name and active_name in data['profiles']:
profile = data['profiles'][active_name]
if game_completed:
profile['games_played'] += 1
profile['total_score'] += score
profile['best_score'] = max(profile['best_score'], score)
profile['last_played'] = datetime.now().isoformat()
with open('user_profiles.json', 'w') as f:
json.dump(data, f, indent=2)
except Exception as e:
print(f"Error updating profile: {e}")
Customization
Adding New Settings
Edit the UserProfile dataclass and the settings adjustment methods:
# In profile_manager.py, modify the UserProfile.__post_init__ method
def __post_init__(self):
if self.settings is None:
self.settings = {
"difficulty": "normal",
"sound_volume": 50,
"music_volume": 50,
"screen_shake": True,
"auto_save": True,
"your_new_setting": "default_value" # Add here
}
Custom Font
Place your font file in the assets/ directory and update the font path:
font_path = "assets/your_font.ttf"
Screen Resolution
The application is optimized for 640x480 resolution. To change resolution, modify the window size in the init_sdl method:
self.window = sdl2.ext.Window(
title="Profile Manager",
size=(your_width, your_height) # Change from (640, 480)
)
Virtual Keyboard Layout
Customize the virtual keyboard characters by modifying the keyboard_chars list:
self.keyboard_chars = [
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'],
['K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'],
['U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4'],
['5', '6', '7', '8', '9', '0', '_', '-', ' ', '<'],
['DONE', 'CANCEL', '', '', '', '', '', '', '', '']
]
Troubleshooting
No Gamepad Detected
- Ensure your gamepad is connected before starting the application
- Try different USB ports
- Check if your gamepad is recognized by your system
- The application will show "No gamepad detected - using keyboard fallback"
- Virtual keyboard works with both gamepad and keyboard controls
Font Issues
- Ensure the font file exists in the assets directory
- The system will fall back to default font if custom font is not found
- Supported font formats: TTF, OTF
- Font sizes are automatically scaled for 640x480 resolution
Virtual Keyboard Not Responding
- Ensure you're in text input mode (creating/editing profile names)
- Use arrow keys or D-Pad to navigate the virtual keyboard cursor
- Press Enter/A button to select characters
- The virtual keyboard cursor should be visible as a highlighted character
Profile Not Saving
- Check file permissions in the application directory
- Ensure sufficient disk space
- Verify JSON format is not corrupted
Resolution Issues
- The application is designed for 640x480 resolution
- On higher resolution displays, the window may appear small
- This is intentional for compatibility with retro gaming systems
- Content is optimized and readable at this resolution
File Structure
project_directory/
├── profile_manager.py # Main application (640x480, virtual keyboard)
├── launch_profile_manager.sh # Launcher script
├── user_profiles.json # Profile data storage
├── test_profile_manager.py # Test suite for core functions
├── game_profile_integration.py # Example game integration
├── assets/
│ └── decterm.ttf # Font file (optional)
└── README_PROFILE_MANAGER.md # This documentation
Development Notes
Virtual Keyboard Implementation
The virtual keyboard is implemented as a 2D grid of characters:
- Cursor position tracked with (keyboard_cursor_x, keyboard_cursor_y)
- Character selection adds to input_text string
- Special functions: DONE (confirm), CANCEL (abort), < (backspace)
- Fully navigable with directional controls only
Screen Layout for 640x480
- Header area: 0-80px (titles, status)
- Content area: 80-400px (main UI elements)
- Controls area: 400-480px (help text, instructions)
- All elements scaled and positioned for optimal readability
Adding New Screens
- Add screen name to
current_screenhandling - Create render method (e.g.,
render_new_screen()) - Add navigation logic in input handlers
- Update screen transitions in confirm/back handlers
Gamepad Button Mapping
The application uses SDL2's joystick interface. Button numbers may vary by controller:
- Most modern controllers follow the Xbox layout
- PlayStation controllers map similarly but may have different button numbers
- Test with your specific controller and adjust mappings if needed
Performance Considerations
- Rendering is capped at 60 FPS for smooth operation
- Input debouncing prevents accidental rapid inputs
- JSON operations are minimized and occur only when necessary
- Virtual keyboard rendering optimized for 640x480 resolution
- Font scaling automatically adjusted for readability
Adding Support for Different Resolutions
To support different screen resolutions, modify these key areas:
- Window initialization in
init_sdl() - Panel and button positioning in render methods
- Font size scaling factors
- Virtual keyboard grid positioning
Gamepad Integration Notes
- Uses SDL2's joystick interface for maximum compatibility
- Button mapping follows standard Xbox controller layout
- Hat/D-Pad input prioritized over analog sticks for precision
- Input timing designed for responsive but not accidental activation
Target Platforms
This profile manager is specifically designed for:
- Handheld Gaming Devices: Steam Deck, ROG Ally, etc.
- Retro Gaming Systems: RetroPie, Batocera, etc.
- Embedded Gaming Systems: Custom arcade cabinets, portable devices
- Low-Resolution Displays: 640x480, 800x600, and similar resolutions
- Gamepad-Only Environments: Systems without keyboard access
License
This profile manager is provided as-is for educational and personal use. Designed for integration with retro and handheld gaming systems.