# 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 ```bash # 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 ```bash # 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: 1. **Navigate**: Use D-Pad/Arrow Keys to move cursor over virtual keyboard 2. **Select Character**: Press A/Enter to add character to profile name 3. **Backspace**: Press X/Delete to remove last character 4. **Complete**: Navigate to "DONE" and press A/Enter to finish input 5. **Cancel**: Navigate to "CANCEL" and press A/Enter to abort #### Navigation Flow 1. **Main Menu**: Create Profile → Select Profile → Edit Settings → Exit 2. **Profile List**: Choose from existing profiles, or go back 3. **Create Profile**: Use virtual keyboard to enter name, confirm with directional controls 4. **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: ```json { "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 ```python 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 ```python 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: ```python # 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: ```python 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: ```python 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: ```python 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 1. Add screen name to `current_screen` handling 2. Create render method (e.g., `render_new_screen()`) 3. Add navigation logic in input handlers 4. 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: 1. Window initialization in `init_sdl()` 2. Panel and button positioning in render methods 3. Font size scaling factors 4. 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.