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/monolog" 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 } 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.GetNumJoysticks() monolog.Printf("Found %d joysticks.\n", num) for i:= 0; i < num; i ++ { joy := al.GetJoystick(i) ms.Joysticks = append(ms.Joysticks, joy) monolog.Printf("Joystick nr %d, name %s", i, joy.GetName()) snum := joy.GetNumSticks() bnum := joy.GetNumButtons() 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) 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 } else { 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.GetKeyboardEventSource()) ms.Queue.RegisterEventSource(al.GetMouseEventSource()) ms.DefaultFont = al.CreateBuiltinFont() ms.FPS.Time = al.Time() ms.Camera.W = ms.Display.Widthf() ms.Camera.H = ms.Display.Heightf() 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 (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) } 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_tiled11.tmx") } func (ms * State) Run() { ms.Load() for !ms.Done { ms.Draw() ms.HandleEvents() ms.Update() } } func (ms * State) HandleEvents() { for event, ok := ms.Queue.GetNextEvent() ; ok ; event, ok = ms.Queue.GetNextEvent() { ms.HandleEvent(event.Event()) } } func (ms * State) HandleEvent(event al.Event) { switch uevent := event.(type) { case *al.KeyboardEvent: ms.HandleKeyboardEvent(uevent) default: break } } func (ms * State) HandleKeyboardEvent(event * al.KeyboardEvent ) { switch (event.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 } }