engine.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. package gg
  2. import (
  3. "github.com/hajimehoshi/ebiten/v2"
  4. "github.com/hajimehoshi/ebiten/v2/inpututil"
  5. "surdeus.su/core/gods/maps"
  6. "time"
  7. "slices"
  8. )
  9. import "surdeus.su/core/gg/mx"
  10. const (
  11. MaxVertices = 1 << 16
  12. )
  13. type GraphicsLibrary = ebiten.GraphicsLibrary
  14. type RunOptions = ebiten.RunGameOptions
  15. // Window configuration type.
  16. type WindowConfig struct {
  17. DebugInfo ebiten.DebugInfo
  18. Options *RunOptions
  19. // The title of the window.
  20. Title string
  21. // Width and height of the window
  22. // in pixels.
  23. Width,
  24. Height int
  25. // Optional settings with
  26. // self describing names.
  27. FixedSize,
  28. Fullscreen,
  29. VSync bool
  30. }
  31. // The main structure that represents
  32. // current state of [game] engine.
  33. type Engine struct {
  34. wcfg WindowConfig
  35. // The main holder for objects.
  36. // Uses the map structure to quickly
  37. // delete and create new objects.
  38. objects *Objects
  39. // The main camera to display in window.
  40. // If is set to nil then the engine will panic.
  41. camera Camera
  42. drawLastTime time.Time
  43. drawdt Duration
  44. // Frame delta time.
  45. dt Duration
  46. lastTime time.Time
  47. // Temporary stuff
  48. keys, prevKeys []Key
  49. buttons MouseButtonMap
  50. wheel mx.Vector
  51. cursorPos mx.Vector
  52. outerEvents, handleEvents EventChan
  53. //bufs [LayerBufSize]*Image
  54. vertices map[Layer] []ebiten.Vertex
  55. //vindices []uint16
  56. // Draw frame.
  57. dframe uint
  58. // Frame.
  59. frame uint
  60. runes []rune
  61. }
  62. type engine Engine
  63. // Get currently pressed keys.
  64. func (e *Engine) GetKeyboardKeys() []Key {
  65. return e.keys
  66. }
  67. func (e *Engine) GraphicsLibrary() GraphicsLibrary {
  68. return e.wcfg.DebugInfo.GraphicsLibrary
  69. }
  70. // Returns currently pressed buttons.
  71. func (e *Engine) GetMouseButtons() []MouseButton {
  72. ret := make([]MouseButton, len(e.buttons))
  73. i := 0
  74. for v := range e.buttons {
  75. ret[i] = v
  76. i++
  77. }
  78. slices.Sort(ret)
  79. return ret
  80. }
  81. // Returns new empty Engine.
  82. func NewEngine(
  83. cfg WindowConfig,
  84. ) *Engine {
  85. ret := &Engine{}
  86. ret.wcfg = cfg
  87. ret.outerEvents = make(EventChan)
  88. ret.handleEvents = make(EventChan)
  89. ret.objects = NewObjects()
  90. ret.buttons = MouseButtonMap{}
  91. return ret
  92. }
  93. func (e *Engine) Camera() Camera {
  94. return e.camera
  95. }
  96. func (e *Engine) SetCamera(c Camera) *Engine {
  97. e.camera = c
  98. return e
  99. }
  100. func (e *Engine) EventInput() EventChan {
  101. return e.outerEvents
  102. }
  103. func (e *Engine) Exist(object Object) bool {
  104. return e.objects.has(object)
  105. }
  106. // Add new objects to the Engine's view.
  107. func (e *Engine) Spawn(object Object) bool {
  108. ctx := Context{
  109. engine: e,
  110. }
  111. object.OnStart(ctx)
  112. ok := e.objects.add(object)
  113. return ok
  114. }
  115. // Delete object from Engine.
  116. func (e *Engine) Delete(object Object) bool {
  117. ctx := Context{
  118. engine: e,
  119. }
  120. object.OnDelete(ctx)
  121. ok := e.objects.remove(object)
  122. return ok
  123. }
  124. var (
  125. allButtons = []MouseButton{
  126. MouseButton0,
  127. MouseButton1,
  128. MouseButton2,
  129. MouseButton3,
  130. MouseButton4,
  131. }
  132. )
  133. func (e *Engine) IsPressed(k Key) bool {
  134. keys := e.GetKeyboardKeys()
  135. for _, v := range keys {
  136. if v == k {
  137. return true
  138. }
  139. }
  140. return false
  141. }
  142. func (e *Engine) IsButtoned(b MouseButton) bool {
  143. _, ok := e.buttons[b]
  144. return ok
  145. }
  146. func (e *Engine) GetMouseWheel() mx.Vector {
  147. return e.wheel
  148. }
  149. func (e *Engine) cursorPosition() mx.Vector {
  150. x, y := ebiten.CursorPosition()
  151. return mx.Vector{mx.Float(x), mx.Float(y)}
  152. }
  153. // Get the real cursor position.
  154. func (e *Engine) GetRealCursorPosition() mx.Vector {
  155. return e.cursorPos
  156. }
  157. // Get the absolute cursor position in the world
  158. // of the engine.
  159. func (e *Engine) GetAbsCursorPosition(
  160. ) mx.Vector {
  161. return e.GetRealCursorPosition().
  162. Apply(e.camera.GetAbsMatrice(Context{
  163. engine: e,
  164. }))
  165. }
  166. // Get the real window size in the current context.
  167. func (e *Engine) GetRealWinSize() mx.Vector {
  168. var w, h int
  169. if e.wcfg.Fullscreen {
  170. w, h = ebiten.ScreenSizeInFullscreen()
  171. } else {
  172. w, h = e.wcfg.Width, e.wcfg.Height
  173. }
  174. return mx.Vector{
  175. mx.Float(w),
  176. mx.Float(h),
  177. }
  178. }
  179. func (e *Engine) GetAbsWinSize() mx.Vector {
  180. return e.camera.GetAbsWinSize(Context{
  181. engine: e,
  182. })
  183. }
  184. func (e *Engine) Runes() []rune {
  185. return e.runes
  186. }
  187. func (e *engine) updateEvents() Events {
  188. eng := (*Engine)(e)
  189. events := Events{}
  190. // Mouse buttons.
  191. btns := e.buttons
  192. for _, btn := range allButtons {
  193. if inpututil.IsMouseButtonJustPressed(btn) {
  194. btns[btn] = struct{}{}
  195. events.Mouse.Downs = append(
  196. events.Mouse.Downs,
  197. MouseButtonDown{
  198. MouseButton: btn,
  199. },
  200. )
  201. } else if inpututil.IsMouseButtonJustReleased(btn) {
  202. delete(btns, btn)
  203. events.Mouse.Ups = append(
  204. events.Mouse.Ups,
  205. MouseButtonUp{
  206. MouseButton: btn,
  207. },
  208. )
  209. }
  210. }
  211. // Mouse wheel.
  212. x, y := ebiten.Wheel()
  213. e.wheel = mx.Vector{x, y}
  214. if !(e.wheel.Eq(mx.ZV)) {
  215. events.Mouse.Wheel = &WheelChange{
  216. Offset: e.wheel,
  217. }
  218. }
  219. // Cursor position.
  220. realPos := eng.cursorPosition()
  221. if !realPos.Eq(e.cursorPos) {
  222. absM := eng.camera.GetAbsMatrice(Context{
  223. engine: eng,
  224. })
  225. absPrevPos := e.cursorPos.Apply(absM)
  226. absPos := realPos.Apply(absM)
  227. events.Mouse.Move = &MouseMove{
  228. RealDelta: realPos.Sub(e.cursorPos),
  229. AbsDelta: absPos.Sub(absPrevPos),
  230. }
  231. e.cursorPos = realPos
  232. }
  233. e.prevKeys = e.keys
  234. //newKeys := []Key{e.keys[0]}
  235. e.keys = nil
  236. e.keys = inpututil.
  237. AppendPressedKeys(e.keys[:0])
  238. // Keyboard.
  239. keyDiff := diffEm(e.prevKeys, e.keys)
  240. for _, key := range keyDiff {
  241. if eng.IsPressed(key) {
  242. events.Keyboard.Downs = append(
  243. events.Keyboard.Downs,
  244. KeyDown{
  245. Key: key,
  246. },
  247. )
  248. } else {
  249. events.Keyboard.Ups = append(
  250. events.Keyboard.Ups,
  251. KeyUp{
  252. Key: key,
  253. },
  254. )
  255. }
  256. }
  257. return events
  258. }
  259. func (e *engine) Update() error {
  260. eng := (*Engine)(e)
  261. e.dt = time.Since(e.lastTime)
  262. e.runes = ebiten.AppendInputChars(e.runes[:0])
  263. //fmt.Println("runes:", e.runes)
  264. // Buffering the context for faster.
  265. // Providing the events to the objects.
  266. // Maybe should think of the better way,
  267. // but for it is simple enough.
  268. events := e.updateEvents()
  269. c := Context{
  270. engine: eng,
  271. events: events,
  272. }
  273. // Should think of the order?
  274. e.objects.updateTags(c)
  275. e.objects.updateObjects(c)
  276. e.lastTime = time.Now()
  277. e.frame++
  278. return nil
  279. }
  280. func (e *Engine) Objects() *Objects {
  281. return e.objects
  282. }
  283. var (
  284. fullPageIndexes = func() [MaxVertices]uint16 {
  285. ret := [MaxVertices]uint16{}
  286. for i:=0 ; i<len(ret) ; i++ {
  287. ret[i] = uint16(i)
  288. }
  289. return ret
  290. }()
  291. defaultPageImg = func() *Image {
  292. img := NewImage(1, 1)
  293. img.Set(0, 0, RGBA(1, 1, 1, 1))
  294. return img
  295. }()
  296. defaultTriOptions = &ebiten.DrawTrianglesOptions{}
  297. )
  298. func (e *engine) Draw(img *ebiten.Image) {
  299. e.drawdt = time.Since(e.drawLastTime)
  300. eng := (*Engine)(e)
  301. m := map[Layer][]Drawer{}
  302. for _, object := range eng.objects.store {
  303. // Skipping the ones we do not need to draw.
  304. if object == nil || !object.IsVisible() {
  305. continue
  306. }
  307. l := object.GetLayer()
  308. layer, ok := m[l]
  309. // Create new if has no the layer
  310. if !ok {
  311. m[l] = []Drawer{object}
  312. continue
  313. }
  314. m[l] = append(layer, object)
  315. }
  316. // Drawing layers via the sparse array.
  317. // First drawing via the inside function
  318. // and then the returned []EVertex.
  319. layers := maps.NewSparse[Layer, []Drawer](nil, m)
  320. c := Context{engine: eng, image: img}
  321. for layer := range layers.Chan() {
  322. vertices := Vertices{}
  323. for _, drawer := range layer {
  324. drawing := drawer.Draw(c)
  325. if drawing != nil {
  326. vertices = append(
  327. vertices,
  328. drawing.Vertices...,
  329. )
  330. }
  331. }
  332. pn := len(vertices) / MaxVertices
  333. mod := len(vertices) % MaxVertices
  334. for i := 0 ; i<pn ; i++ {
  335. cur := i*MaxVertices
  336. img.DrawTriangles(
  337. vertices[cur:cur+MaxVertices].ToAPI(),
  338. fullPageIndexes[:],
  339. defaultPageImg,
  340. defaultTriOptions,
  341. )
  342. }
  343. st := pn*MaxVertices
  344. img.DrawTriangles(
  345. vertices[st:].ToAPI(),
  346. fullPageIndexes[:mod],
  347. defaultPageImg,
  348. defaultTriOptions,
  349. )
  350. }
  351. // Empty the buff to generate it again.
  352. e.drawLastTime = time.Now()
  353. e.dframe++
  354. }
  355. func (e *engine) Layout(ow, oh int) (int, int) {
  356. if e.wcfg.FixedSize {
  357. return e.wcfg.Width, e.wcfg.Height
  358. }
  359. return ow, oh
  360. }
  361. // Return the delta time between Draw calls.
  362. func (e *Engine) DrawDT() Duration {
  363. return e.drawdt
  364. }
  365. // Current Drawing frame.
  366. func (e *Engine) Dframe() uint {
  367. return e.dframe
  368. }
  369. // Return the real delta time.
  370. // Please, prefer the DT().
  371. func (e *Engine) RealDT() Duration {
  372. return e.dt
  373. }
  374. // Returns the current delta time. (btw frames)
  375. // (By the Ebiten community convention
  376. // currently it is a fixed value)
  377. func (e *Engine) DT() Duration {
  378. return time.Second/60
  379. }
  380. // Current frame
  381. func (e *Engine) Frame() uint {
  382. return e.frame
  383. }
  384. // Current FPS.
  385. func (e *Engine) FPS() float64 {
  386. return ebiten.ActualFPS()
  387. }
  388. // Current TPS.
  389. func (e *Engine) TPS() float64 {
  390. return ebiten.ActualTPS()
  391. }
  392. // Run the engine.
  393. func (e *Engine) Run() error {
  394. ebiten.ReadDebugInfo(&e.wcfg.DebugInfo)
  395. ebiten.SetWindowTitle(e.wcfg.Title)
  396. ebiten.SetWindowSize(e.wcfg.Width, e.wcfg.Height)
  397. ebiten.SetWindowSizeLimits(1, 1, e.wcfg.Width, e.wcfg.Height)
  398. ebiten.SetFullscreen(e.wcfg.Fullscreen)
  399. ebiten.SetVsyncEnabled(e.wcfg.VSync)
  400. e.lastTime = time.Now()
  401. //fmt.Println(e.Objects)
  402. return ebiten.RunGameWithOptions((*engine)(e), e.wcfg.Options)
  403. }
  404. func (e *Engine) GetWindowConfig() WindowConfig {
  405. return e.wcfg
  406. }