package input import ( "encoding/json" "log" "os" "path/filepath" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/inpututil" ) type Binding [][]ebiten.Key const settingsFile = "assets/settings.json" type InputManager struct { Actions map[string]Binding recordingAction string recordingKeys []ebiten.Key isRecording bool } var Manager *InputManager func init() { Manager = NewInputManager() Manager.LoadSettings() } func NewInputManager() *InputManager { return &InputManager{ Actions: make(map[string]Binding), recordingKeys: make([]ebiten.Key, 0), } } func (im *InputManager) LoadDefaultSettings() { im.Actions = map[string]Binding{ "Run": {{ebiten.KeyControl}}, "ClimbMode": {{ebiten.KeyShift}}, "MoveLeft": {{ebiten.KeyA}, {ebiten.KeyLeft}}, "MoveRight": {{ebiten.KeyD}, {ebiten.KeyRight}}, "MoveUp": {{ebiten.KeyW}, {ebiten.KeyUp}}, "MoveDown": {{ebiten.KeyS}, {ebiten.KeyDown}}, "Jump": {{ebiten.KeySpace}}, "ClimbLeft": {{ebiten.KeyA}, {ebiten.KeyLeft}}, "ClimbRight": {{ebiten.KeyD}, {ebiten.KeyRight}}, "ClimbUp": {{ebiten.KeyW}}, "ClimbDown": {{ebiten.KeyS}}, "ClimbIn": {{ebiten.KeyUp}}, "ClimbOut": {{ebiten.KeyDown}}, } } func (im *InputManager) LoadSettings() { im.LoadDefaultSettings() // Load defaults first data, err := os.ReadFile(settingsFile) if err != nil { if os.IsNotExist(err) { im.SaveSettings() // Create the file if it doesn't exist } else { log.Println("Error reading settings.json:", err) } return } var loadedActions map[string]Binding if err := json.Unmarshal(data, &loadedActions); err != nil { log.Println("Error unmarshaling settings.json:", err) return } // Overwrite defaults with loaded ones for k, v := range loadedActions { im.Actions[k] = v } } func (im *InputManager) SaveSettings() { // Ensure directory exists if err := os.MkdirAll(filepath.Dir(settingsFile), 0755); err != nil { log.Println("Failed to create settings directory:", err) return } data, err := json.MarshalIndent(im.Actions, "", " ") if err != nil { log.Println("Error marshaling settings:", err) return } if err := os.WriteFile(settingsFile, data, 0644); err != nil { log.Println("Error writing settings.json:", err) } } func (im *InputManager) IsActionPressed(action string) bool { bindings, ok := im.Actions[action] if !ok { return false } for _, combination := range bindings { allPressed := true for _, key := range combination { if !ebiten.IsKeyPressed(key) { allPressed = false break } } // Om alla tangenter i kombinationen är nedtryckta så triggas handlingen if len(combination) > 0 && allPressed { return true } } return false } func (im *InputManager) IsActionJustPressed(action string) bool { bindings, ok := im.Actions[action] if !ok { return false } for _, combination := range bindings { allPressed := true justPressedCount := 0 for _, key := range combination { if !ebiten.IsKeyPressed(key) { allPressed = false break } if inpututil.IsKeyJustPressed(key) { justPressedCount++ } } if len(combination) > 0 && allPressed && justPressedCount > 0 { return true } } return false } func (im *InputManager) StartRecording(action string) { im.recordingAction = action im.recordingKeys = []ebiten.Key{} im.isRecording = true } // UpdateRecording called every frame while in settings to record inputs. // Returns true when recording finished. func (im *InputManager) UpdateRecording() bool { if !im.isRecording { return false } // Avbryt med ESC if inpututil.IsKeyJustPressed(ebiten.KeyEscape) { im.StopRecording() return true } // Spara med Enter if inpututil.IsKeyJustPressed(ebiten.KeyEnter) { if len(im.recordingKeys) > 0 { im.Actions[im.recordingAction] = Binding{im.recordingKeys} im.SaveSettings() } im.isRecording = false return true } pressedKeys := make([]ebiten.Key, 0) for k := ebiten.KeyA; k <= ebiten.KeyMax; k++ { if ebiten.IsKeyPressed(k) { // Ignorera Escape och Enter från att bindas if k == ebiten.KeyEscape || k == ebiten.KeyEnter { continue } pressedKeys = append(pressedKeys, k) } } // Limit to max 2 keys if len(pressedKeys) > 2 { pressedKeys = pressedKeys[:2] } // Uppdatera de lagrade tangenterna att visa i UI if len(pressedKeys) > 0 { im.recordingKeys = pressedKeys } return false } func (im *InputManager) StopRecording() { im.isRecording = false } func (im *InputManager) IsRecording() bool { return im.isRecording } func (im *InputManager) GetRecordingAction() string { return im.recordingAction } func (im *InputManager) GetRecordingKeys() []ebiten.Key { return im.recordingKeys }