feat: ...

This commit is contained in:
Andrey Parhomenko 2023-12-23 00:09:07 +03:00
parent d4ac7909db
commit 348c03cfc9
18 changed files with 397 additions and 343 deletions

View file

@ -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
View 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 }

View file

@ -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
View 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
View 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
View 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)
}
}

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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)

View file

@ -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)
}

View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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()
}

View file

@ -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
}

View file

@ -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.

View file

@ -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
}