feat: ...
This commit is contained in:
parent
d4ac7909db
commit
348c03cfc9
18 changed files with 397 additions and 343 deletions
24
camera.go
24
camera.go
|
@ -3,8 +3,19 @@ package gg
|
|||
// Implements the camera component
|
||||
// for the main window.
|
||||
type Camera struct {
|
||||
// The shaders that will be applied to everything
|
||||
// that the camera shows.
|
||||
ShaderOptions
|
||||
Transform
|
||||
buf *Matrix
|
||||
engine *Engine
|
||||
}
|
||||
|
||||
func (e *Engine) NewCamera() *Camera {
|
||||
ret := &Camera{}
|
||||
ret.Transform = T()
|
||||
ret.engine = e
|
||||
return ret
|
||||
}
|
||||
|
||||
// Returns the matrix satysfying camera
|
||||
|
@ -14,11 +25,16 @@ type Camera struct {
|
|||
// (Should implement buffering it so we do not
|
||||
// need to calculate it each time for each object. )
|
||||
func (c *Camera)RealMatrix() Matrix {
|
||||
/*if c.buf != nil {
|
||||
return *(c.buf)
|
||||
}*/
|
||||
g := &Matrix{}
|
||||
g.Translate(-c.P.X, -c.P.Y)
|
||||
g.Rotate(c.R)
|
||||
g.Scale(c.S.X, c.S.Y)
|
||||
g.Translate(c.RA.X, c.RA.Y)
|
||||
g.Translate(-c.Position.X, -c.Position.Y)
|
||||
g.Rotate(c.Rotation)
|
||||
siz := c.engine.AbsWinSize()
|
||||
g.Translate(c.Around.X * siz.X, c.Around.Y * siz.Y)
|
||||
g.Scale(c.Scale.X, c.Scale.Y)
|
||||
|
||||
|
||||
c.buf = g
|
||||
|
||||
|
|
40
cmd/test/debug.go
Normal file
40
cmd/test/debug.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package main
|
||||
|
||||
import "github.com/di4f/gg"
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Debug struct {
|
||||
gg.Visibility
|
||||
gg.Layer
|
||||
}
|
||||
|
||||
func (d *Debug) Draw(c *Context) {
|
||||
e := c.Engine
|
||||
keyStrs := []string{}
|
||||
for _, k := range e.Keys() {
|
||||
keyStrs = append(keyStrs, k.String())
|
||||
}
|
||||
|
||||
if rectMove.ContainsPoint(e.AbsCursorPosition()) {
|
||||
keyStrs = append(keyStrs, "contains cursor")
|
||||
}
|
||||
|
||||
if rectMove.Vertices().Contained(rect).Len() > 0 ||
|
||||
rect.Vertices().Contained(rectMove).Len() > 0 {
|
||||
keyStrs = append(keyStrs, "rectangles intersect")
|
||||
}
|
||||
|
||||
keyStrs = append(keyStrs, fmt.Sprintf("%v", e.CursorPosition()))
|
||||
keyStrs = append(keyStrs, fmt.Sprintf("%v", e.AbsCursorPosition()))
|
||||
keyStrs = append(keyStrs, fmt.Sprintf("absWinSize: %v", c.AbsWinSize()))
|
||||
|
||||
e.DebugPrint(c.Image,
|
||||
strings.Join(keyStrs, "\n"))
|
||||
|
||||
}
|
||||
|
||||
func (d *Debug) IsVisible() bool { return true }
|
256
cmd/test/main.go
256
cmd/test/main.go
|
@ -3,12 +3,10 @@ package main
|
|||
import (
|
||||
"github.com/di4f/gg"
|
||||
"github.com/hajimehoshi/ebiten/v2/examples/resources/images"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"bytes"
|
||||
"log"
|
||||
"strings"
|
||||
//"strings"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
type Context = gg.Context
|
||||
|
@ -22,94 +20,6 @@ const (
|
|||
LowestL
|
||||
)
|
||||
|
||||
type Player struct {
|
||||
*gg.Sprite
|
||||
MoveSpeed gg.Float
|
||||
ScaleSpeed gg.Float
|
||||
gg.Layer
|
||||
}
|
||||
|
||||
type Debug struct {
|
||||
gg.Visibility
|
||||
gg.Layer
|
||||
}
|
||||
|
||||
type Rect struct {
|
||||
*gg.DrawableRectangle
|
||||
gg.Layer
|
||||
}
|
||||
|
||||
type Tri struct {
|
||||
*gg.DrawablePolygon
|
||||
gg.Layer
|
||||
}
|
||||
|
||||
func NewTri() *Tri {
|
||||
ret := &Tri{}
|
||||
ret.DrawablePolygon = &gg.DrawablePolygon{}
|
||||
ret.Transform.S = gg.V(1, 1)
|
||||
|
||||
ret.Triangles = gg.Triangles{
|
||||
gg.Triangle{
|
||||
gg.V(0, 0),
|
||||
gg.V(100, 100),
|
||||
gg.V(0, -50),
|
||||
},
|
||||
gg.Triangle{
|
||||
gg.V(0, 0),
|
||||
gg.V(-100, -100),
|
||||
gg.V(0, 50),
|
||||
},
|
||||
}
|
||||
ret.Color = gg.Color{gg.MaxColorV, gg.MaxColorV, 0, gg.MaxColorV}
|
||||
ret.Visible = true
|
||||
ret.Layer = TriangleL
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func NewRect() *Rect {
|
||||
ret := &Rect{&gg.DrawableRectangle{
|
||||
Rectangle: gg.Rectangle{
|
||||
Transform: gg.Transform{
|
||||
S: gg.Vector{
|
||||
X: 200,
|
||||
Y: 400,
|
||||
},
|
||||
},
|
||||
},
|
||||
Color: gg.Color{
|
||||
gg.MaxColorV,
|
||||
0,
|
||||
0,
|
||||
gg.MaxColorV,
|
||||
},
|
||||
Visible: true,
|
||||
/*Shader: gg.SolidWhiteColorShader,
|
||||
Options: gg.ShaderOptions{
|
||||
Images: [4]*gg.Image{
|
||||
playerImg,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},*/
|
||||
},
|
||||
RectL,
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (r *Rect) Update(c *Context) error {
|
||||
//r.R += 0.3 * e.DT()
|
||||
r.P = c.AbsCursorPosition()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Rect) Event(c *Context) {
|
||||
}
|
||||
|
||||
var (
|
||||
playerImg *gg.Image
|
||||
player *Player
|
||||
|
@ -118,170 +28,6 @@ var (
|
|||
tri *Tri
|
||||
)
|
||||
|
||||
func NewPlayer() *Player {
|
||||
ret := &Player{
|
||||
Sprite: &gg.Sprite{
|
||||
Transform: gg.Transform{
|
||||
S: gg.Vector{5, 5},
|
||||
RA: gg.Vector{.5, .5},
|
||||
},
|
||||
Visible: true,
|
||||
ShaderOptions: gg.ShaderOptions{
|
||||
Shader: gg.SolidWhiteColorShader,
|
||||
Uniforms: make(map[string]any),
|
||||
},
|
||||
},
|
||||
MoveSpeed: 90.,
|
||||
ScaleSpeed: .2,
|
||||
}
|
||||
|
||||
ret.Images[0] = playerImg
|
||||
ret.Layer = PlayerL
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (p *Player) Draw(c *Context) {
|
||||
p.Sprite.Draw(c)
|
||||
t := p.Transform
|
||||
t.S.X *= 4.
|
||||
t.S.Y *= 4.
|
||||
rectMove = gg.Rectangle{
|
||||
Transform: t,
|
||||
}
|
||||
r := &gg.DrawableRectangle{
|
||||
Rectangle: rectMove,
|
||||
Color: gg.Color{0, 0, gg.MaxColorV, gg.MaxColorV},
|
||||
}
|
||||
r.Draw(c)
|
||||
}
|
||||
|
||||
func (p *Player) Start(c *Context) {
|
||||
fmt.Println("starting")
|
||||
cam := c.Camera()
|
||||
cam.RA = gg.V(360, 240)
|
||||
}
|
||||
|
||||
func (p *Player) Update(c *Context) error {
|
||||
dt := c.DT()
|
||||
cam := c.Camera()
|
||||
keys := c.Keys()
|
||||
|
||||
p.Uniforms["Random"] = any(rand.Float32())
|
||||
for _, v := range keys {
|
||||
switch v {
|
||||
case ebiten.KeyArrowUp:
|
||||
cam.P.Y += p.MoveSpeed * dt
|
||||
case ebiten.KeyArrowLeft:
|
||||
cam.P.X -= p.MoveSpeed * dt
|
||||
case ebiten.KeyArrowDown:
|
||||
cam.P.Y -= p.MoveSpeed * dt
|
||||
case ebiten.KeyArrowRight:
|
||||
cam.P.X += p.MoveSpeed * dt
|
||||
case ebiten.KeyW:
|
||||
p.P.Y += p.MoveSpeed * dt
|
||||
case ebiten.KeyA:
|
||||
p.P.X -= p.MoveSpeed * dt
|
||||
case ebiten.KeyS:
|
||||
p.P.Y -= p.MoveSpeed * dt
|
||||
case ebiten.KeyD:
|
||||
p.P.X += p.MoveSpeed * dt
|
||||
case ebiten.KeyR:
|
||||
cam.R += gg.Pi * p.ScaleSpeed * dt
|
||||
case ebiten.KeyT:
|
||||
cam.R -= gg.Pi * p.ScaleSpeed * dt
|
||||
case ebiten.KeyRightBracket:
|
||||
if c.IsPressed(gg.KeyShift) {
|
||||
p.R -= gg.Pi * 0.3 * dt
|
||||
} else {
|
||||
p.R += gg.Pi * 0.3 * dt
|
||||
}
|
||||
case gg.KeyF:
|
||||
if c.IsPressed(ebiten.KeyShift) {
|
||||
cam.S.X -= gg.Pi * p.ScaleSpeed * dt
|
||||
} else {
|
||||
cam.S.X += gg.Pi * p.ScaleSpeed * dt
|
||||
}
|
||||
case gg.KeyG:
|
||||
if c.IsPressed(ebiten.KeyShift) {
|
||||
cam.S.Y -= gg.Pi * p.ScaleSpeed * dt
|
||||
} else {
|
||||
cam.S.Y += gg.Pi * p.ScaleSpeed * dt
|
||||
}
|
||||
case gg.KeyZ:
|
||||
if c.IsPressed(ebiten.KeyShift) {
|
||||
cam.RA.X -= gg.Pi * p.MoveSpeed * dt
|
||||
} else {
|
||||
cam.RA.X += gg.Pi * p.MoveSpeed * dt
|
||||
}
|
||||
case gg.KeyX:
|
||||
if c.IsPressed(ebiten.KeyShift) {
|
||||
cam.RA.Y -= gg.Pi * p.MoveSpeed * dt
|
||||
} else {
|
||||
cam.RA.Y += gg.Pi * p.MoveSpeed * dt
|
||||
}
|
||||
case gg.KeyV:
|
||||
if c.IsPressed(ebiten.KeyShift) {
|
||||
tri.R -= gg.Pi * 0.3 * dt
|
||||
} else {
|
||||
tri.R += gg.Pi * 0.3 * dt
|
||||
}
|
||||
case gg.KeyLeftBracket:
|
||||
if c.IsPressed(ebiten.KeyShift) {
|
||||
rect.R -= gg.Pi * 0.3 * dt
|
||||
} else {
|
||||
rect.R += gg.Pi * 0.3 * dt
|
||||
}
|
||||
case gg.Key0:
|
||||
c.Del(p)
|
||||
case gg.KeyB:
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Player) Signal(e *gg.Engine, ev any) {
|
||||
fmt.Println("event:", ev)
|
||||
switch ec := ev.(type) {
|
||||
case *gg.KeyDown:
|
||||
switch {
|
||||
case ec.Key == gg.KeyB:
|
||||
if p.Layer != PlayerL {
|
||||
p.Layer = PlayerL
|
||||
} else {
|
||||
p.Layer = HighestL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Debug) Draw(c *Context) {
|
||||
e := c.Engine
|
||||
keyStrs := []string{}
|
||||
for _, k := range e.Keys() {
|
||||
keyStrs = append(keyStrs, k.String())
|
||||
}
|
||||
|
||||
if rectMove.ContainsPoint(e.AbsCursorPosition()) {
|
||||
keyStrs = append(keyStrs, "contains cursor")
|
||||
}
|
||||
|
||||
if rectMove.Vertices().Contained(rect).Len() > 0 ||
|
||||
rect.Vertices().Contained(rectMove).Len() > 0 {
|
||||
keyStrs = append(keyStrs, "THIS IS SHIT")
|
||||
}
|
||||
|
||||
keyStrs = append(keyStrs, fmt.Sprintf("%v", e.CursorPosition()))
|
||||
keyStrs = append(keyStrs, fmt.Sprintf("%v", e.AbsCursorPosition()))
|
||||
|
||||
e.DebugPrint(c.Image,
|
||||
strings.Join(keyStrs, ", "))
|
||||
|
||||
}
|
||||
|
||||
func (d *Debug) IsVisible() bool { return true }
|
||||
|
||||
func main() {
|
||||
e := gg.NewEngine(&gg.WindowConfig{
|
||||
Title: "Test title",
|
||||
|
|
129
cmd/test/player.go
Normal file
129
cmd/test/player.go
Normal file
|
@ -0,0 +1,129 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
//"math/rand"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
import "github.com/di4f/gg"
|
||||
|
||||
type Player struct {
|
||||
gg.Sprite
|
||||
MoveSpeed gg.Float
|
||||
ScaleSpeed gg.Float
|
||||
gg.Layer
|
||||
}
|
||||
|
||||
func NewPlayer() *Player {
|
||||
ret := &Player{}
|
||||
ret.Transform = gg.T()
|
||||
ret.Scale = gg.V(5, 5)
|
||||
// Around center.
|
||||
ret.Around = gg.V(.5, .5)
|
||||
ret.MoveSpeed = 90.
|
||||
ret.ScaleSpeed = .2
|
||||
|
||||
ret.Visible = true
|
||||
|
||||
ret.Images[0] = playerImg
|
||||
ret.Layer = PlayerL
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// Custom drawing function.
|
||||
func (p *Player) Draw(c *Context) {
|
||||
p.Sprite.Draw(c)
|
||||
t := p.Transform
|
||||
t.Scale.X *= 4.
|
||||
t.Scale.Y *= 4.
|
||||
|
||||
r := &gg.DrawableRectangle{}
|
||||
r.Color = gg.Rgba(0, 0, 1, 1)
|
||||
r.Rectangle = gg.Rectangle{
|
||||
Transform: t,
|
||||
}
|
||||
r.Draw(c)
|
||||
}
|
||||
|
||||
func (p *Player) Update(c *Context) {
|
||||
dt := c.DT()
|
||||
cam := c.Camera
|
||||
keys := c.Keys()
|
||||
|
||||
//p.Uniforms["Random"] = any(rand.Float32())
|
||||
for _, v := range keys {
|
||||
switch v {
|
||||
case gg.KeyArrowUp:
|
||||
cam.Position.Y += p.MoveSpeed * dt
|
||||
case gg.KeyArrowLeft:
|
||||
cam.Position.X -= p.MoveSpeed * dt
|
||||
case gg.KeyArrowDown:
|
||||
cam.Position.Y -= p.MoveSpeed * dt
|
||||
case gg.KeyArrowRight:
|
||||
cam.Position.X += p.MoveSpeed * dt
|
||||
case gg.KeyW:
|
||||
p.Position.Y += p.MoveSpeed * dt
|
||||
case gg.KeyA:
|
||||
p.Position.X -= p.MoveSpeed * dt
|
||||
case gg.KeyS:
|
||||
p.Position.Y -= p.MoveSpeed * dt
|
||||
case gg.KeyD:
|
||||
p.Position.X += p.MoveSpeed * dt
|
||||
case gg.KeyR:
|
||||
cam.Rotation += gg.Pi * p.ScaleSpeed * dt
|
||||
case gg.KeyT:
|
||||
cam.Rotation -= gg.Pi * p.ScaleSpeed * dt
|
||||
case gg.KeyRightBracket:
|
||||
if c.IsPressed(gg.KeyShift) {
|
||||
p.Rotation -= gg.Pi * 0.3 * dt
|
||||
} else {
|
||||
p.Rotation += gg.Pi * 0.3 * dt
|
||||
}
|
||||
case gg.KeyF:
|
||||
if c.IsPressed(gg.KeyShift) {
|
||||
cam.Scale = cam.Scale.Add(gg.V1(p.ScaleSpeed * dt))
|
||||
} else {
|
||||
cam.Scale = cam.Scale.Add(gg.V1(-p.ScaleSpeed * dt))
|
||||
}
|
||||
case gg.KeyG:
|
||||
if c.IsPressed(gg.KeyShift) {
|
||||
cam.Scale.Y -= gg.Pi * p.ScaleSpeed * dt
|
||||
} else {
|
||||
cam.Scale.Y += gg.Pi * p.ScaleSpeed * dt
|
||||
}
|
||||
case gg.KeyV:
|
||||
if c.IsPressed(gg.KeyShift) {
|
||||
tri.Rotation -= gg.Pi * 0.3 * dt
|
||||
} else {
|
||||
tri.Rotation += gg.Pi * 0.3 * dt
|
||||
}
|
||||
case gg.KeyLeftBracket:
|
||||
if c.IsPressed(gg.KeyShift) {
|
||||
rect.Rotation -= gg.Pi * 0.3 * dt
|
||||
} else {
|
||||
rect.Rotation += gg.Pi * 0.3 * dt
|
||||
}
|
||||
case gg.Key0:
|
||||
c.Del(p)
|
||||
case gg.KeyB:
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (p *Player) Event(c *gg.Context) {
|
||||
fmt.Println("event:", c.Event)
|
||||
switch ec := c.Event.(type) {
|
||||
case *gg.KeyDown:
|
||||
switch {
|
||||
case ec.Key == gg.KeyB:
|
||||
if p.Layer != PlayerL {
|
||||
p.Layer = PlayerL
|
||||
} else {
|
||||
p.Layer = HighestL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
30
cmd/test/rect.go
Normal file
30
cmd/test/rect.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package main
|
||||
|
||||
import "github.com/di4f/gg"
|
||||
|
||||
type Rect struct {
|
||||
gg.DrawableRectangle
|
||||
gg.Layer
|
||||
}
|
||||
|
||||
func NewRect() *Rect {
|
||||
ret := &Rect{}
|
||||
ret.Scale = gg.V(200, 400)
|
||||
ret.Color = gg.Color{
|
||||
gg.MaxColorV,
|
||||
0,
|
||||
0,
|
||||
gg.MaxColorV,
|
||||
}
|
||||
ret.Layer = RectL
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (r *Rect) Update(c *Context) {
|
||||
//r.R += 0.3 * e.DT()
|
||||
//r.Position = c.AbsCursorPosition()
|
||||
}
|
||||
|
||||
func (r *Rect) Event(c *Context) {
|
||||
}
|
41
cmd/test/trianlge.go
Normal file
41
cmd/test/trianlge.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package main
|
||||
|
||||
import "github.com/di4f/gg"
|
||||
//import "fmt"
|
||||
|
||||
type Tri struct {
|
||||
*gg.DrawablePolygon
|
||||
gg.Layer
|
||||
}
|
||||
|
||||
func NewTri() *Tri {
|
||||
ret := &Tri{}
|
||||
ret.DrawablePolygon = &gg.DrawablePolygon{}
|
||||
ret.Transform.Scale = gg.V(1, 1)
|
||||
|
||||
ret.Triangles = gg.Triangles{
|
||||
gg.Triangle{
|
||||
gg.V(0, 0),
|
||||
gg.V(100, 100),
|
||||
gg.V(0, -50),
|
||||
},
|
||||
gg.Triangle{
|
||||
gg.V(0, 0),
|
||||
gg.V(-100, -100),
|
||||
gg.V(0, 50),
|
||||
},
|
||||
}
|
||||
ret.Color = gg.Color{gg.MaxColorV, gg.MaxColorV, 0, gg.MaxColorV}
|
||||
ret.Visible = true
|
||||
ret.Layer = TriangleL
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (t *Tri) Update(c *Context) {
|
||||
if t.ContainsPoint(c.AbsCursorPosition()) {
|
||||
t.Color = gg.Rgba(0, 1, 0, 1)
|
||||
} else {
|
||||
t.Color = gg.Rgba(1, 0, 1, 1)
|
||||
}
|
||||
}
|
96
engine.go
96
engine.go
|
@ -3,8 +3,8 @@ package gg
|
|||
import (
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||
"github.com/omnipunk/gods/maps"
|
||||
"fmt"
|
||||
"github.com/di4f/gods/maps"
|
||||
//"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -18,11 +18,16 @@ func (l Layer) GetLayer() Layer {
|
|||
|
||||
// Window configuration type.
|
||||
type WindowConfig struct {
|
||||
// The title of the window.
|
||||
Title string
|
||||
|
||||
// Width and height of the window
|
||||
// in pixels.
|
||||
Width,
|
||||
Height int
|
||||
|
||||
// Optional settings with
|
||||
// self describing names.
|
||||
FixedSize,
|
||||
Fullscreen,
|
||||
VSync bool
|
||||
|
@ -31,26 +36,30 @@ type WindowConfig struct {
|
|||
// The main structure that represents current state of [game] engine.
|
||||
type Engine struct {
|
||||
wcfg *WindowConfig
|
||||
objects maps.Map[Object, struct{}]
|
||||
|
||||
// The main holder for objects.
|
||||
// Uses the map structure to quickly
|
||||
// delete and create new objects.
|
||||
Objects maps.Map[Object, struct{}]
|
||||
|
||||
// The main camera to display in window.
|
||||
// If is set to nil then the engine will panic.
|
||||
Camera *Camera
|
||||
|
||||
// The same delta time for all frames
|
||||
// and all objects.
|
||||
lastTime time.Time
|
||||
dt Float
|
||||
camera *Camera
|
||||
|
||||
// Temporary stuff
|
||||
keys, prevKeys []Key
|
||||
cursorPos, prevCursorPos Vector
|
||||
mouseButtons, prevMouseButtons []MouseButton
|
||||
outerEvents, handleEvents EventChan
|
||||
}
|
||||
|
||||
type engine Engine
|
||||
|
||||
// Return current camera.
|
||||
func (e *Engine) Camera() *Camera {
|
||||
return e.camera
|
||||
}
|
||||
|
||||
// Set new current camera.
|
||||
func (e *Engine) SetCamera(c *Camera) {
|
||||
e.camera = c
|
||||
}
|
||||
|
||||
// Get currently pressed keys.
|
||||
func (e *Engine) Keys() []Key {
|
||||
return e.keys
|
||||
|
@ -60,22 +69,29 @@ func (e *Engine) Keys() []Key {
|
|||
func NewEngine(
|
||||
cfg *WindowConfig,
|
||||
) *Engine {
|
||||
w := Float(cfg.Width)
|
||||
h := Float(cfg.Height)
|
||||
return &Engine{
|
||||
wcfg: cfg,
|
||||
camera: &Camera{
|
||||
Transform: Transform{
|
||||
// Normal, no distortion.
|
||||
S: Vector{1, 1},
|
||||
// Center.
|
||||
RA: V(w/2, h/2),
|
||||
},
|
||||
},
|
||||
objects: maps.NewOrdered[Object, struct{}](),
|
||||
outerEvents: make(EventChan),
|
||||
handleEvents: make(EventChan),
|
||||
/*w := Float(cfg.Width)
|
||||
h := Float(cfg.Height)*/
|
||||
|
||||
ret := &Engine{}
|
||||
|
||||
ret.wcfg = cfg
|
||||
ret.Camera = ret.NewCamera()
|
||||
ret.outerEvents = make(EventChan)
|
||||
ret.handleEvents = make(EventChan)
|
||||
ret.Objects = maps.NewOrdered[Object, struct{}]()
|
||||
return ret
|
||||
}
|
||||
|
||||
// Get the real window size in the current context.
|
||||
func (c *Engine) RealWinSize() Vector {
|
||||
return V(
|
||||
Float(c.wcfg.Width),
|
||||
Float(c.wcfg.Height),
|
||||
)
|
||||
}
|
||||
|
||||
func (c *Engine) AbsWinSize() Vector {
|
||||
return c.RealWinSize().Div(c.Camera.Scale)
|
||||
}
|
||||
|
||||
func (e *Engine) EventInput() EventChan {
|
||||
|
@ -86,7 +102,7 @@ func (e *Engine) EventInput() EventChan {
|
|||
// interfaces it implements.
|
||||
func (e *Engine) Add(b any) error {
|
||||
object, _ := b.(Object)
|
||||
if e.objects.Has(object) {
|
||||
if e.Objects.Has(object) {
|
||||
return ObjectExistErr
|
||||
}
|
||||
/*o, ok := e.makeObject(b)
|
||||
|
@ -101,7 +117,7 @@ func (e *Engine) Add(b any) error {
|
|||
})
|
||||
}
|
||||
|
||||
e.objects.Set(object, struct{}{})
|
||||
e.Objects.Set(object, struct{}{})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -109,7 +125,7 @@ func (e *Engine) Add(b any) error {
|
|||
// Delete object from Engine.
|
||||
func (e *Engine) Del(b any) error {
|
||||
object, _ := b.(Object)
|
||||
if !e.objects.Has(object) {
|
||||
if !e.Objects.Has(object) {
|
||||
return ObjectNotExistErr
|
||||
}
|
||||
|
||||
|
@ -120,14 +136,13 @@ func (e *Engine) Del(b any) error {
|
|||
})
|
||||
}
|
||||
|
||||
e.objects.Del(b)
|
||||
e.Objects.Del(b)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func (e *engine) Update() error {
|
||||
var err error
|
||||
eng := (*Engine)(e)
|
||||
|
||||
e.prevKeys = e.keys
|
||||
|
@ -152,7 +167,7 @@ func (e *engine) Update() error {
|
|||
}
|
||||
|
||||
e.dt = time.Since(e.lastTime).Seconds()
|
||||
for object := range e.objects.KeyChan() {
|
||||
for object := range e.Objects.KeyChan() {
|
||||
eventer, ok := object.(Eventer)
|
||||
if ok {
|
||||
for _, event := range events {
|
||||
|
@ -166,12 +181,9 @@ func (e *engine) Update() error {
|
|||
if !ok {
|
||||
continue
|
||||
}
|
||||
err = updater.Update(&Context{
|
||||
updater.Update(&Context{
|
||||
Engine: eng,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
e.lastTime = time.Now()
|
||||
|
||||
|
@ -181,7 +193,7 @@ func (e *engine) Update() error {
|
|||
func (e *engine) Draw(i *ebiten.Image) {
|
||||
eng := (*Engine)(e)
|
||||
m := map[Layer][]Drawer{}
|
||||
for object := range eng.objects.KeyChan() {
|
||||
for object := range eng.Objects.KeyChan() {
|
||||
drawer, ok := object.(Drawer)
|
||||
if !ok {
|
||||
continue
|
||||
|
@ -208,6 +220,8 @@ func (e *engine) Draw(i *ebiten.Image) {
|
|||
})
|
||||
}
|
||||
}
|
||||
// Empty the buff to generate it again.
|
||||
eng.Camera.buf = nil
|
||||
}
|
||||
|
||||
func (e *engine) Layout(ow, oh int) (int, int) {
|
||||
|
@ -231,7 +245,7 @@ func (e *Engine) Run() error {
|
|||
ebiten.SetVsyncEnabled(e.wcfg.VSync)
|
||||
|
||||
e.lastTime = time.Now()
|
||||
fmt.Println(e.objects)
|
||||
//fmt.Println(e.Objects)
|
||||
return ebiten.RunGame((*engine)(e))
|
||||
}
|
||||
|
||||
|
|
2
go.mod
2
go.mod
|
@ -5,8 +5,8 @@ go 1.21
|
|||
toolchain go1.21.3
|
||||
|
||||
require (
|
||||
github.com/di4f/gods v0.0.0-20231214190239-d523423d8d5e
|
||||
github.com/hajimehoshi/ebiten/v2 v2.6.0-alpha.3.0.20230521122940-90562ee84b9b
|
||||
github.com/omnipunk/gods v0.0.0-20231112101528-1f82aa46d746
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
4
go.sum
4
go.sum
|
@ -1,3 +1,5 @@
|
|||
github.com/di4f/gods v0.0.0-20231214190239-d523423d8d5e h1:LdL9GpXPJikQ7DXQZFf5Zz5h5MYAS9R7itEztnscku8=
|
||||
github.com/di4f/gods v0.0.0-20231214190239-d523423d8d5e/go.mod h1:5GbuWHGgBJIIhBiQB/00flvo3k421S8O1XvmrXKWO2U=
|
||||
github.com/ebitengine/purego v0.4.0-alpha.4 h1:Y7yIV06Yo5M2BAdD7EVPhfp6LZ0tEcQo5770OhYUVes=
|
||||
github.com/ebitengine/purego v0.4.0-alpha.4/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b h1:GgabKamyOYguHqHjSkDACcgoPIz3w0Dis/zJ1wyHHHU=
|
||||
|
@ -6,8 +8,6 @@ github.com/hajimehoshi/ebiten/v2 v2.6.0-alpha.3.0.20230521122940-90562ee84b9b h1
|
|||
github.com/hajimehoshi/ebiten/v2 v2.6.0-alpha.3.0.20230521122940-90562ee84b9b/go.mod h1:+fFI6Ag5YvbX1ivNQD2TxNhpWFDPuxEoew421TTQAxI=
|
||||
github.com/jezek/xgb v1.1.0 h1:wnpxJzP1+rkbGclEkmwpVFQWpuE2PUGNUzP8SbfFobk=
|
||||
github.com/jezek/xgb v1.1.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
|
||||
github.com/omnipunk/gods v0.0.0-20231112101528-1f82aa46d746 h1:3Hqv6OBITqr9SUhCqD9ZZG3xXMrYNDvyCsZK7BF4lTo=
|
||||
github.com/omnipunk/gods v0.0.0-20231112101528-1f82aa46d746/go.mod h1:zARHZc37wTaPpL5GVzZd0FK59r8UbPnxodIXWQ59uLk=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
|
|
11
img.go
11
img.go
|
@ -16,11 +16,20 @@ type Color struct {
|
|||
R, G, B, A ColorV
|
||||
}
|
||||
|
||||
|
||||
const (
|
||||
MaxColorV = math.MaxUint32
|
||||
)
|
||||
|
||||
// The wrapper to make RGBA color via
|
||||
// values from 0 to 1 (no value at all and the max value).
|
||||
func Rgba(r, g, b, a Float) Color {
|
||||
return Color {
|
||||
ColorV(r*MaxColorV),
|
||||
ColorV(g*MaxColorV),
|
||||
ColorV(b*MaxColorV),
|
||||
ColorV(a*MaxColorV),
|
||||
}
|
||||
}
|
||||
|
||||
func LoadImage(input io.Reader) (*Image, error) {
|
||||
img, _, err := image.Decode(input)
|
||||
|
|
2
mouse.go
2
mouse.go
|
@ -13,7 +13,7 @@ func (e *Engine) CursorPosition() Vector {
|
|||
|
||||
func (e *Engine) AbsCursorPosition() Vector {
|
||||
m := &Matrix{}
|
||||
m.Concat(e.Camera().AbsMatrix())
|
||||
m.Concat(e.Camera.AbsMatrix())
|
||||
return e.CursorPosition().Apply(m)
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ type Starter interface {
|
|||
// will call the function on each
|
||||
// engine iteration.
|
||||
type Updater interface {
|
||||
Update(*Context) error
|
||||
Update(*Context)
|
||||
}
|
||||
|
||||
// Implementing the interface type
|
||||
|
|
|
@ -13,6 +13,10 @@ type Polygon struct {
|
|||
Triangles
|
||||
}
|
||||
|
||||
func (p *Polygon) ContainsPoint(pnt Point) bool {
|
||||
return p.MakeTriangles().ContainsPoint(pnt)
|
||||
}
|
||||
|
||||
// Polygon that can be drawn.
|
||||
type DrawablePolygon struct {
|
||||
Polygon
|
||||
|
|
9
rect.go
9
rect.go
|
@ -9,8 +9,6 @@ import (
|
|||
|
||||
// The type describes rectangle geometry.
|
||||
type Rectangle struct {
|
||||
// P - position of the rotating center.
|
||||
// Scale represent width and height.
|
||||
Transform
|
||||
}
|
||||
|
||||
|
@ -22,10 +20,10 @@ type DrawableRectangle struct {
|
|||
// Solid color of the rectangle.
|
||||
// Will be ignored if the Shader
|
||||
// field is not nil.
|
||||
Color Color
|
||||
Colority
|
||||
|
||||
// Should be draw or not.
|
||||
Visible bool
|
||||
Visibility
|
||||
}
|
||||
|
||||
// Return points of vertices of the rectangle.
|
||||
|
@ -55,7 +53,6 @@ func (r Rectangle) Triangles() Triangles {
|
|||
p2 := pts[1]
|
||||
p3 := pts[2]
|
||||
p4 := pts[3]
|
||||
//fmt.Println("in:", p1, p2, p3, p4)
|
||||
|
||||
return Triangles{
|
||||
Triangle{p1, p2, p3},
|
||||
|
@ -75,7 +72,7 @@ func (r *DrawableRectangle) IsVisible() bool {
|
|||
|
||||
func (r *DrawableRectangle) Draw(c *Context) {
|
||||
m := r.Matrix()
|
||||
rm := c.Camera().RealMatrix()
|
||||
rm := c.Camera.RealMatrix()
|
||||
m.Concat(rm)
|
||||
// Draw solid color if no shader.
|
||||
if r.Shader == nil {
|
||||
|
|
17
sprite.go
17
sprite.go
|
@ -2,12 +2,14 @@ package gg
|
|||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
//"fmt"
|
||||
)
|
||||
|
||||
type Sprite struct {
|
||||
Transform
|
||||
ShaderOptions
|
||||
Floating, Visible bool
|
||||
Floating bool
|
||||
Visibility
|
||||
}
|
||||
|
||||
func (s *Sprite) Draw(c *Context) {
|
||||
|
@ -20,7 +22,7 @@ func (s *Sprite) Draw(c *Context) {
|
|||
m := &Matrix{}
|
||||
m.Concat(t.Matrix())
|
||||
if !s.Floating {
|
||||
m.Concat(c.Camera().RealMatrix())
|
||||
m.Concat(c.Camera.RealMatrix())
|
||||
}
|
||||
|
||||
// Drawing without shader.
|
||||
|
@ -41,11 +43,6 @@ func (s *Sprite) Draw(c *Context) {
|
|||
c.DrawRectShader(w, h, s.Shader, opts)
|
||||
}
|
||||
|
||||
// Check is sprite is visible.
|
||||
func (s *Sprite) IsVisible() bool {
|
||||
return s.Visible
|
||||
}
|
||||
|
||||
// Return the rectangle that contains the sprite.
|
||||
func (s *Sprite) Rectangle() Rectangle {
|
||||
if s.Images[0] == nil {
|
||||
|
@ -54,12 +51,14 @@ func (s *Sprite) Rectangle() Rectangle {
|
|||
|
||||
w, h := s.Images[0].Size()
|
||||
t := s.Transform
|
||||
t.RA.X *= Float(w)
|
||||
t.RA.Y *= Float(h)
|
||||
t.Around.X *= Float(w)
|
||||
t.Around.Y *= Float(h)
|
||||
|
||||
return Rectangle{t}
|
||||
}
|
||||
|
||||
// Get triangles of the rectangle that contains the sprite
|
||||
// and has the same widght and height.
|
||||
func (s *Sprite) Triangles() Triangles {
|
||||
return s.Rectangle().Triangles()
|
||||
}
|
||||
|
|
49
transform.go
49
transform.go
|
@ -8,23 +8,26 @@ import (
|
|||
// The structure represents basic transformation
|
||||
// features: positioning, rotating and scaling.
|
||||
type Transform struct {
|
||||
// P - absolute phisycal position in engine itself.
|
||||
//
|
||||
// S - scale width and height (X and Y).
|
||||
//
|
||||
// RA - rotate around(relatively of position, not absolute).
|
||||
//
|
||||
// For example RA=Vector{0, 0} will rotate around right up corner
|
||||
// and RA=Vector{.5, .5} will rotate around center.
|
||||
P, S, RA Vector
|
||||
// Rotation angle in radians.
|
||||
R Float
|
||||
// Absolute (if no parent) position and
|
||||
// the scale.
|
||||
Position, Scale Vector
|
||||
// The object rotation in radians.
|
||||
Rotation Float
|
||||
// The not scaled offset vector from upper left corner
|
||||
// which the object should be rotated around.
|
||||
Around Vector
|
||||
// Needs to be implemented.
|
||||
// Makes transform depending on the other one.
|
||||
// Is the root one if Parent == nil
|
||||
Parent *Transform
|
||||
}
|
||||
|
||||
// Returns empty Transform.
|
||||
// Returns empty Transform
|
||||
// with standard scaling. (1/1)
|
||||
func T() Transform {
|
||||
ret := Transform{
|
||||
S: Vector{1, 1},
|
||||
Scale: Vector{1, 1},
|
||||
Around: V(.5, .5),
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
@ -34,12 +37,12 @@ func (t Transform) ScaledToXY(x, y Float) Transform {
|
|||
}
|
||||
|
||||
func (t Transform) ScaledToX(x Float) Transform {
|
||||
t.S.X = x
|
||||
t.Scale.X = x
|
||||
return t
|
||||
}
|
||||
|
||||
func (t Transform) ScaledToY(y Float) Transform {
|
||||
t.S.Y = y
|
||||
t.Scale.Y = y
|
||||
return t
|
||||
}
|
||||
|
||||
|
@ -48,10 +51,18 @@ func (t Transform) ScaledToY(y Float) Transform {
|
|||
func (t Transform)Matrix() Matrix {
|
||||
g := &Matrix{}
|
||||
|
||||
g.Scale(t.S.X, t.S.Y)
|
||||
g.Translate(-t.RA.X * t.S.X, -t.RA.Y * t.S.Y)
|
||||
g.Rotate(t.R)
|
||||
g.Translate(t.P.X, t.P.Y)
|
||||
// Scale first.
|
||||
g.Scale(t.Scale.X, t.Scale.Y)
|
||||
|
||||
// Then move and rotate.
|
||||
g.Translate(
|
||||
-t.Around.X * t.Scale.X,
|
||||
-t.Around.Y * t.Scale.Y,
|
||||
)
|
||||
g.Rotate(t.Rotation)
|
||||
|
||||
// And finally move to the absolute position.
|
||||
g.Translate(t.Position.X, t.Position.Y)
|
||||
|
||||
return *g
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ func (ts Triangles) ContainsPoint(p Point) bool {
|
|||
}
|
||||
|
||||
func (r *DrawableTriangles) Draw(c *Context) {
|
||||
m := c.Camera().RealMatrix()
|
||||
m := c.Camera.RealMatrix()
|
||||
cm := &m
|
||||
|
||||
// Draw solid color if no shader.
|
||||
|
|
18
vector.go
18
vector.go
|
@ -18,6 +18,24 @@ func V(x, y Float) Vector {
|
|||
return Vector{x, y}
|
||||
}
|
||||
|
||||
func V1(v Float) Vector {
|
||||
return V(v, v)
|
||||
}
|
||||
|
||||
func (v Vector) Div(o Vector) Vector {
|
||||
return V(
|
||||
v.X / o.X,
|
||||
v.Y / o.Y,
|
||||
)
|
||||
}
|
||||
|
||||
func (v Vector) Scale(o Vector) Vector {
|
||||
return V(
|
||||
v.X * o.X,
|
||||
v.Y * o.Y,
|
||||
)
|
||||
}
|
||||
|
||||
func (v Vector) Eq(o Vector) bool {
|
||||
return v.X == o.X && v.Y == o.Y
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue