package global import "math" import al "gitlab.com/beoran/al5go/al" import "gitlab.com/beoran/ebsgo/engine/tile" import "gitlab.com/beoran/ebsgo/engine/physics" // import "gitlab.com/beoran/ebsgo/engine/geometry" import "gitlab.com/beoran/ebsgo/monolog" import zori_backend "gitlab.com/beoran/ebsgo/zori/backend" import al5go_backend "gitlab.com/beoran/ebsgo/zori/backend/al5go" import "gitlab.com/beoran/ebsgo/zori" import "gitlab.com/beoran/ebsgo/zori/style" import ztypes "gitlab.com/beoran/ebsgo/zori/types" import zevent "gitlab.com/beoran/ebsgo/zori/event" import "gitlab.com/beoran/ebsgo/zori/widget" type FPS struct { FPS float64 Now float64 Time float64 Show bool } type State struct { Display * al.Display Fullscreen bool W int H int HaveAudio bool HaveTouch bool HaveJoystick bool Done bool DefaultFont * al.Font TTF * al.Font Colors map[string](al.Color) Queue * al.EventQueue FPS Frames int LastUpdate float64 Joysticks [] * al.Joystick Map * tile.Map // MapID store.ID // area.Area Camera physics.Camera // Sprites sprite.List // ScriptEngine raku.Runtime // zori.Console // zori.State // Actor area.Thing zori_backend.Backend * zori.UI } func (ms * State) Hf() float32 { return float32(ms.H) } func (ms * State) Wf() float32 { return float32(ms.W) } func (ms * State) LogIfFail(ok bool, text string) bool { if !ok { monolog.Error("%s", text) } return ok } func (ms * State) LoadMap(name string) { tm, err := tile.LoadMapFifi(name) if err != nil { monolog.Error("Could not load tile map: %s", err) } else { ms.Map = tm } } func (ms * State) SetupJoysticks() { if (!ms.HaveJoystick) { return } ms.Joysticks = make([]*al.Joystick, 0) num := al.NumJoysticks() monolog.Printf("Found %d joysticks.\n", num) for i:= 0; i < num; i ++ { joy := al.FindJoystick(i) ms.Joysticks = append(ms.Joysticks, joy) monolog.Printf("Joystick nr %d, name %s", i, joy.Name()) snum := joy.NumSticks() bnum := joy.NumButtons() monolog.Printf("%d sticks and %d buttons", snum, bnum) } ms.Queue.RegisterEventSource(al.JoystickEventSource()) } func (ms * State) InstallAllegro() bool { res := ms.LogIfFail(al.InstallSystem(), "Could not install Allegro") res = res && ms.LogIfFail(al.InstallKeyboard(), "Could not install Keyboard") res = res && ms.LogIfFail(al.InstallMouse(), "Could not install mouse") al.InitFontAddon() res = res && ms.LogIfFail(al.InitTTFAddon(), "Could not init TTF addon") res = res && ms.LogIfFail(al.InitPrimitivesAddon(), "Could not init primitives addon") res = res && ms.LogIfFail(al.InitImageAddon(), "Could not init image addon") if res { ms.HaveTouch = al.InstallTouchInput() ms.HaveJoystick = al.InstallJoystick() ms.HaveAudio = al.InstallAudio() ms.HaveAudio = ms.HaveAudio && al.InitAcodecAddon() } ms.Queue = al.CreateEventQueue() ms.SetupJoysticks() return res } func (ms * State) SetupTestUI(theme * style.Theme) { box := ztypes.Bounds(80, 90, 120, 30) label := widget.NewLabel(ms.UI.Root, &box, "Heyho") ms.UI.Root.AddChild(label) ms.UI = zori.New(ms.Backend, theme) box2 := ztypes.Bounds(80, 120, 120, 30) var button1 * widget.Button button1 = widget.NewButton(ms.UI.Root, &box2, "Button 1", func(w widget.Widget, d... interface{}) zevent.Result { monolog.Info("Button pressed handler for %v", button1) return zevent.Done }) ms.UI.Root.AddChild(button1) } func (ms * State) SetupUI() { theme := &style.Theme{} theme.Border.Color = al.MapRGB(255, 255, 255) theme.Border.Radius = 5 theme.Background.Color = al.MapRGB(0, 16, 64) theme.Background.Radius = 5 theme.Text.Font = ms.DefaultFont theme.Text.Color = al.MapRGB(0xff, 0xff, 0xee) ms.Backend = al5go_backend.New(ms.Display, ms.Queue) ms.UI = zori.New(ms.Backend, theme) ms.UI.Root.Cursors.Mouse.TargetTheme = *theme ms.UI.Root.Cursors.Keyjoy.TargetTheme = *theme ms.UI.Root.Cursors.Mouse.TargetTheme.Background.Color = al.MapRGB(32, 32, 128) ms.SetupTestUI(theme) } func (ms * State) OpenDisplay(w, h int, title string, fullscreen bool) * al.Display { ms.Fullscreen = fullscreen ms.W = w ms.H = h flags := 0 // Use full screen mode if needed. if fullscreen { flags = al.FULLSCREEN // | GENERATE_EXPOSE_EVENTS } al.SetNewDisplayFlags(flags) // Create a window to display things on: 640x480 pixels. display := al.CreateDisplay(w, h) // display.Resize(w, h) if !(fullscreen) { display.SetWindowTitle(title) } ms.Display = display ms.Queue.RegisterEventSource(al.KeyboardEventSource()) ms.Queue.RegisterEventSource(al.MouseEventSource()) ms.DefaultFont = al.CreateBuiltinFont() ms.FPS.Time = al.Time() ms.Camera.W = ms.Display.Widthf() ms.Camera.H = ms.Display.Heightf() tile.InitBlendMasks(); ms.SetupUI(); return display } func (ms * State) ScaleDisplay() { real_w := ms.Display.Width() real_h := ms.Display.Height() scale_x := real_w / ms.W scale_y := real_h / ms.H scale := scale_y if scale_x < scale_y { scale = scale_x } offset_x := (real_w - (ms.W * scale)) / 2 offset_y := (real_h - (ms.H * scale)) / 2 trans := al.CreateIdentityTransform() /* Draw black bars to cover the usused areas. */ black := al.MapRGB(0,0,0) if (offset_y > 0) { al.DrawFilledRectangleInt(-offset_x , -offset_y, real_w, 0, black) al.DrawFilledRectangleInt(-offset_x , ms.H, real_w, ms.H +offset_y, black) } if (offset_x > 0) { al.DrawFilledRectangleInt(-offset_x , -offset_y, 0, real_h, black) al.DrawFilledRectangleInt(ms.W , -offset_y, ms.W + offset_x, real_h, black) } trans.ScaleInt(scale, scale).TranslateInt(offset_x, offset_y).Use() /* al.SetClippingRectangle(offset_x, offset_y, ms.W, ms.H); */ } func (ms * State) DrawFPS() { white := al.MapRGB(255,255,255) black := al.MapRGB(0,0,255) al.DrawFilledRectangleInt(10, 10, 100, 10 + ms.DefaultFont.LineHeight(),black) ms.DefaultFont.DrawTextf(white, 10.0, 10.0, al.ALIGN_LEFT, "FPS: %d", int(ms.FPS.FPS)) } func (ms * State) Update() { ms.Frames++ now := al.Time() delta := now - ms.LastUpdate ms.LastUpdate = now if ms.Map != nil { ms.Map.Update(delta) } if ms.UI != nil { ms.UI.Update(delta) } if (now - ms.FPS.Time) >= 1.0 { realfps := float64(ms.Frames) / (now - ms.FPS.Time) /* Display and use a rounded value for FPS, the number after the comma is normally due to jitter anyway. */ ms.FPS.FPS = math.Floor(realfps + 0.5) /* A little trick, to prevent jerkiness, keep half the frames; and half the time */ ms.Frames = ms.Frames / 2 ms.FPS.Time = now - 0.5 } } func (ms * State) Draw() { if ms.Map != nil { ms.Map.Draw(&ms.Camera) } if ms.UI != nil { ms.UI.Draw() } yellow := al.MapRGB(255, 255, 0) al.DrawFilledCircle(30.0, 40.0, 15.0, yellow) ms.DrawFPS() al.FlipDisplay() } func (ms * State) Load() { // ms.LoadMap("map/map_0001_tiled115.tmx") } func (ms * State) Close() { if ms.Map != nil { ms.Map.Close() ms.Map = nil } if ms.Queue != nil { ms.Queue.Destroy() ms.Queue = nil } if ms.Display != nil { ms.Display.Destroy() ms.Display = nil } } func (ms * State) Run() { ms.Load() defer ms.Close() for !ms.Done { ms.Draw() ms.HandleEvents() ms.Update() } } func (ms * State) HandleEvents() { for event, ok := ms.Queue.NextEvent() ; ok ; event, ok = ms.Queue.NextEvent() { ms.HandleEvent(event.Event()) } } func (ms * State) HandleEvent(event al.Event) { switch event.Type() { case al.EVENT_KEY_DOWN: ms.HandleKeyboardEvent(event) default: break } if ms.UI != nil { evwrap := al5go_backend.WrapEvent(ms.Backend, event) ms.UI.Dispatch(evwrap) } } func (ms * State) HandleKeyboardEvent(event al.Event ) { kev := event.(*al.KeyboardEvent) switch kev.KeyCode() { case al.KEY_ESCAPE: ms.Done = true case al.KEY_UP: ms.Camera.Y-= 10 case al.KEY_DOWN: ms.Camera.Y+= 10 case al.KEY_LEFT: ms.Camera.X-= 10 case al.KEY_RIGHT: ms.Camera.X+= 10 } }