This commit is contained in:
Andrey Parhomenko 2024-06-01 18:07:28 +05:00
parent 234f4f4d0c
commit cde993db48
36 changed files with 782 additions and 527 deletions

View file

@ -6,11 +6,11 @@ import (
// Unique identifier for animation // Unique identifier for animation
// in the animation set. // in the animation set.
type AnimationId int type AnimationID int
// The type describes set of animations // The type describes set of animations
// to switch between. // to switch between.
type AnimationSet map[AnimationId] Animation type AnimationSet map[AnimationID] Animation
// Make new animation set from an image. // Make new animation set from an image.
func AnimationSetFromImage( func AnimationSetFromImage(

View file

@ -12,13 +12,13 @@ type RectIndex struct {
// to structurely define // to structurely define
// animations. // animations.
type AnimationDefine struct{ type AnimationDefine struct{
Id AnimationId Id AnimationID
Indexes []RectIndex Indexes []RectIndex
} }
// Animation define shortcut. // Animation define shortcut.
func AD( func AD(
id AnimationId, id AnimationID,
indexes ...RectIndex, indexes ...RectIndex,
) AnimationDefine { ) AnimationDefine {
return AnimationDefine{ return AnimationDefine{

View file

@ -3,7 +3,7 @@ package gg
import "surdeus.su/core/gg/mx" import "surdeus.su/core/gg/mx"
// The type describes what // The type describes what
// a camera object must implement. // a window camera object must implement.
type Camera interface { type Camera interface {
// Get the matrice to apply // Get the matrice to apply
// camera's features. // camera's features.
@ -15,5 +15,7 @@ type Camera interface {
// The shaders to apply on // The shaders to apply on
// everything on the camera. // everything on the camera.
GetShaderOptions() *ShaderOptions GetShaderOptions() *ShaderOptions
GetAbsWinSize(Context) mx.Vector
} }

55
cmd/test/camera.go Normal file
View file

@ -0,0 +1,55 @@
package main
import "surdeus.su/core/gg/ox"
import "surdeus.su/core/gg/mx"
import "surdeus.su/core/gg"
var (
camera = &Camera{
Camera: ox.NewCamera(),
ScaleSpeed: 5.,
RotationSpeed: .3,
}
)
type Camera struct {
ox.ObjectImpl
ox.Camera
ScaleSpeed mx.Float
RotationSpeed mx.Float
}
func (cam *Camera) OnUpdate(c gg.Context) {
dt := c.Engine().DT().Seconds()
mov := c.Events().Mouse.Move
wheel := c.Events().Mouse.WheelChange
shiftPressed := c.Engine().IsPressed(gg.KeyShift)
d := float64(1.)
if shiftPressed {
d *= -1
}
// Moving.
if mov != nil && c.Engine().IsButtoned(
gg.MouseButtonRight,
) {
cam.Move(mov.AbsDelta)
}
// Scale.
if wheel != nil {
cam.AddScale(mx.V2(
wheel.Offset.Y * dt * cam.ScaleSpeed * 40,
))
}
// Scale and rotation.
for _, key := range c.Engine().GetKeyboardKeys() {
switch key {
case gg.KeyF:
cam.AddScale(mx.V2(d*cam.ScaleSpeed * dt))
case gg.KeyR:
cam.Rotate(d*mx.Pi * cam.ScaleSpeed * dt)
}
}
}

View file

@ -1,6 +1,8 @@
package main package main
import "surdeus.su/core/gg" import "surdeus.su/core/gg"
import "surdeus.su/core/gg/ox"
import "surdeus.su/core/gg/mx"
import ( import (
"strings" "strings"
@ -8,24 +10,24 @@ import (
) )
type Debug struct { type Debug struct {
gg.Object ox.ObjectImpl
gg.Visibility ox.Visibility
} }
func (d *Debug) Update(c *Context) { func (d *Debug) OnUpdate(c Context) {
for _, e := range c.Events { for _, key := range c.Events().Keyboard.KeyDowns {
switch ec := e.(type) { switch key.Key {
case *gg.KeyDown:
switch ec.Key {
case gg.KeyF11: case gg.KeyF11:
d.Visible = !d.Visible d.ToggleVisibility()
} //d.Visible = !d.IsVisible()
} }
} }
} }
func (d *Debug) Draw(c *Context) []gg.EVertex { func (d *Debug) GetLayer() gg.Layer {return LayerHighest}
e := c.Engine
func (d *Debug) Draw(c Context) *gg.Drawing {
e := c.Engine()
relTri := tri.Rel() relTri := tri.Rel()
relPlayer := player.Rel() relPlayer := player.Rel()
@ -34,36 +36,36 @@ func (d *Debug) Draw(c *Context) []gg.EVertex {
"counter: %d", counter, "counter: %d", counter,
)) ))
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"tps: %d", int(c.Tps()), "tps: %d", int(c.Engine().TPS()),
)) ))
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"fps: %d", int(c.Fps()), "fps: %d", int(c.Engine().FPS()),
)) ))
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"dframe: %d", int(c.Dframe()), "dframe: %d", int(c.Engine().Dframe()),
)) ))
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"frame: %d", int(c.Frame()), "frame: %d", int(c.Engine().Frame()),
)) ))
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"relPlayerPos: %v", relPlayer.Position(), "relPlayerPos: %v", relPlayer.GetPosition(),
)) ))
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"absPlayerPos: %v", player.Position(), "absPlayerPos: %v", player.GetPosition(),
)) ))
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"relTriPos: %v", relTri.Position(), "relTriPos: %v", relTri.GetPosition(),
)) ))
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"absTriPos: %v", tri.Position(), "absTriPos: %v", tri.GetPosition(),
)) ))
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"absTriRot: %v", gg.Degree(tri.Rotation()), "absTriRot: %v", mx.Degree(tri.GetRotation()),
)) ))
keys := []string{} keys := []string{}
for _, k := range e.Keys() { for _, k := range e.GetKeyboardKeys() {
keys = append(keys, k.String()) keys = append(keys, k.String())
} }
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
@ -71,10 +73,10 @@ func (d *Debug) Draw(c *Context) []gg.EVertex {
)) ))
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"buttons: %v", c.MouseButtons(), "buttons: %v", c.Engine().MouseButtons(),
)) ))
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"wheel: %v", c.Wheel(), "wheel: %v", c.Engine().Wheel(),
)) ))
/*if rectMove.ContainsPoint(e.AbsCursorPosition()) { /*if rectMove.ContainsPoint(e.AbsCursorPosition()) {
keyStrs = append(keyStrs, "contains cursor") keyStrs = append(keyStrs, "contains cursor")
@ -87,14 +89,22 @@ func (d *Debug) Draw(c *Context) []gg.EVertex {
keyStrs = append(keyStrs, fmt.Sprintf( keyStrs = append(keyStrs, fmt.Sprintf(
"camera position: %v %v", "camera position: %v %v",
c.Camera.Position().X, camera.GetPosition().X,
c.Camera.Position().Y, camera.GetPosition().Y,
)) ))
keyStrs = append(keyStrs, fmt.Sprintf("realCursorPos: %v", e.CursorPosition())) keyStrs = append(keyStrs, fmt.Sprintf(
keyStrs = append(keyStrs, fmt.Sprintf("absCursorPos: %v", e.AbsCursorPosition())) "realCursorPos: %v", e.GetRealCursorPosition()))
keyStrs = append(keyStrs, fmt.Sprintf("absWinSize: %v", c.AbsWinSize())) keyStrs = append(keyStrs, fmt.Sprintf(
"absCursorPos: %v", e.GetAbsCursorPosition() ))
e.DebugPrint(c.Image, keyStrs = append(keyStrs,
fmt.Sprintf(
"absWinSize: %v",
c.Engine().GetAbsWinSize(),
),
)
e.DebugPrint(c.Image(),
strings.Join(keyStrs, "\n")) strings.Join(keyStrs, "\n"))
return nil return nil

53
cmd/test/grid.go Normal file
View file

@ -0,0 +1,53 @@
package main
import "surdeus.su/core/gg"
import "surdeus.su/core/gg/ox"
import "surdeus.su/core/gg/mx"
type Grid struct {
ox.ObjectImpl
ox.Sprite
Cage, Width mx.Float
}
func (grid *Grid) OnUpdate(c Context) {
//d := c.IsPressed(gg.KeyShift)
for _, down := range c.Events().Keyboard.KeyDowns {
switch down.Key {
case gg.Key9:
grid.Cage /= 10
grid.Width /= 5
case gg.Key0:
grid.Cage *= 10
grid.Width *= 5
}
}
}
func NewGrid() *Grid {
grid := &Grid{}
grid.Transform = ox.T()
grid.SetAround(mx.V2(0))
grid.Layer = LayerBackground
grid.Images[0] = gg.NewImage(720, 480)
grid.Images[0].Fill(gg.RGBA(1, 1, 1, 1))
grid.Shader = bgShader
grid.Uniforms = map[string]any{}
//bg.Floating = true
grid.Visible = true
grid.Floating = true
grid.Cage = 100
grid.Width = 5
return grid
}
func (grid *Grid) Draw(c Context) *gg.Drawing {
scale := camera.GetScale()
pos := camera.GetPosition()
grid.Uniforms["Zoom"] = mx.Float(scale.X)
grid.Uniforms["PosX"] = pos.X
grid.Uniforms["PosY"] = pos.Y
grid.Uniforms["Cage"] = grid.Cage
grid.Uniforms["Width"] = grid.Width
return grid.Sprite.Draw(c)
}

View file

@ -3,8 +3,9 @@ package main
import ( import (
"surdeus.su/core/gg" "surdeus.su/core/gg"
"surdeus.su/core/gg/ox" "surdeus.su/core/gg/ox"
//"surdeus.su/core/gg/mx"
"surdeus.su/core/gg/ax"
"github.com/hajimehoshi/ebiten/v2/examples/resources/images" "github.com/hajimehoshi/ebiten/v2/examples/resources/images"
"github.com/hajimehoshi/ebiten/v2/examples/resources/fonts"
//_ "github.com/silbinarywolf/preferdiscretegpu" //_ "github.com/silbinarywolf/preferdiscretegpu"
"bytes" "bytes"
"log" "log"
@ -13,105 +14,32 @@ import (
type Context = gg.Context type Context = gg.Context
type Grid struct {
ox.Sprite
Cage, Width gg.Float
}
func (grid *Grid) OnUpdate(c *Context) {
//d := c.IsPressed(gg.KeyShift)
for _, ev := range c.Events {
switch e := ev.(type) {
case *gg.KeyDown:
switch e.Key {
case gg.Key9:
grid.Cage /= 10
grid.Width /= 5
case gg.Key0:
grid.Cage *= 10
grid.Width *= 5
}
}
}
}
func (grid *Grid) OnDraw(c *Context) []gg.EVertex {
scale := c.Camera.Scale()
pos := c.Camera.Position()
grid.Uniforms["Zoom"] = gg.Float(scale.X)
grid.Uniforms["PosX"] = pos.X
grid.Uniforms["PosY"] = pos.Y
grid.Uniforms["Cage"] = grid.Cage
grid.Uniforms["Width"] = grid.Width
return grid.Sprite.Draw(c)
}
const ( const (
HighestL gg.Layer = -iota LayerHighest gg.Layer = -iota
DebugL
TriangleL LayerDebug
PlayerL LayerTriangle
RectL LayerPlayer
BackgroundLayer LayerRect
LowestL LayerBackground
LayerLowest
) )
const ( const (
Stand gg.AnimationId = iota Stand ax.AnimationID = iota
Walk Walk
) )
var ( var (
playerAnimations gg.AnimationSet playerAnimations ax.AnimationSet
playerImg *gg.Image playerImg *gg.Image
player *Player player *Player
rectMove gg.Rectangle rectMove ox.Rectangle
rect *Rect rect *Rect
tri *Tri tri *Tri
) bgShader = gg.MustNewShader([]byte(`
func main() {
e := gg.NewEngine(&gg.WindowConfig{
Title: "Test title",
Width: 720,
Height: 480,
VSync: true,
Fullscreen: false,
})
var err error
playerImg, err = gg.LoadImage(bytes.NewReader(images.Runner_png))
if err != nil {
log.Fatal(err)
}
rect = NewRect()
playerAnimations, _ = gg.AnimationSetFromImage(
playerImg,
8, 3,
10, 1,
gg.AD(Stand).DefRow(0, 0, 1, 2, 3, 4),
gg.AD(Walk).DefRow(1, 0, 1, 2, 3, 4, 5, 6, 7),
)
player = NewPlayer()
tri = NewTri()
e.Spawn(&Debug{})
e.Spawn(player)
e.Spawn(rect)
e.Spawn(tri)
/*circle := &gg.Circle{}
circle.Transform = gg.T()
circle.Rotation = 300
circle.Color = gg.Rgba(1, 1, 1, 1)
circle.Antialias = true
circle.Layer = HighestL
circle.Visible = true*/
//e.Spawn(circle)
bgShader := gg.MustNewShader([]byte(`
package main package main
//kage:unit pixels //kage:unit pixels
@ -140,40 +68,58 @@ func main() {
return cx return cx
} }
`)) `))
grid := &Grid{}
grid.Transform = gg.T()
grid.SetAround(gg.V2(0))
grid.Layer = BackgroundLayer
grid.Images[0] = gg.NewImage(720, 480)
grid.Images[0].Fill(gg.Rgba(1, 1, 1, 1))
grid.Shader = bgShader
grid.Uniforms = map[string]any{}
//bg.Floating = true
grid.Visible = true
grid.Floating = true
grid.Cage = 100
grid.Width = 5
e.Spawn(grid)
txt := &Text{}
txt.Transform = gg.T()
//txt.Position = gg.V2(400)
txt.Color = gg.Rgba(1, 1, 1, 1)
txt.Layer = HighestL
txt.Visible = true
txt.Data = "Hello, World!\nПривет, Мир!"
txt.Face, err = gg.MakeFaceFromTtf(
bytes.NewReader(fonts.MPlus1pRegular_ttf),
&gg.TtfFaceOptions{
Size: 32,
DPI: 72,
Hinting: gg.FontHintingNone,
},
) )
func main() {
e := gg.NewEngine(gg.WindowConfig{
Title: "Test title",
Width: 720,
Height: 480,
VSync: true,
Fullscreen: false,
})
e.SetCamera(camera)
e.Spawn(camera)
var err error
playerImg, err = gg.LoadImage(bytes.NewReader(images.Runner_png))
if err != nil {
log.Fatal(err)
}
rect = NewRect()
playerAnimations, _ = ax.AnimationSetFromImage(
playerImg,
8, 3,
10, 1,
ax.AD(Stand).DefRow(0, 0, 1, 2, 3, 4),
ax.AD(Walk).DefRow(1, 0, 1, 2, 3, 4, 5, 6, 7),
)
player = NewPlayer()
tri = NewTri()
e.Spawn(&Debug{})
e.Spawn(player)
e.Spawn(rect)
e.Spawn(tri)
/*circle := &gg.Circle{}
circle.Transform = gg.T()
circle.Rotation = 300
circle.Color = gg.Rgba(1, 1, 1, 1)
circle.Antialias = true
circle.Layer = HighestL
circle.Visible = true*/
//e.Spawn(circle)
e.Spawn(NewGrid())
text, err := NewText()
if err != nil { if err != nil {
panic(err) panic(err)
} }
e.Spawn(txt) e.Spawn(text)
//fmt.Println(rect.GetLayer(), player.GetLayer()) //fmt.Println(rect.GetLayer(), player.GetLayer())
fmt.Println("Starting...") fmt.Println("Starting...")

View file

@ -1,33 +1,36 @@
package main package main
import (
//"math/rand"
"fmt"
"time"
)
import "surdeus.su/core/gg" import "surdeus.su/core/gg"
import "surdeus.su/core/gg/ox"
import "surdeus.su/core/gg/mx"
import "time"
import "log"
type Player struct { type Player struct {
gg.AnimatedSprite ox.AnimatedSprite
MoveSpeed gg.Float MoveSpeed mx.Float
ScaleSpeed gg.Float ScaleSpeed mx.Float
Spawned bool Spawned bool
} }
func NewPlayer() *Player { func NewPlayer() *Player {
ret := &Player{} ret := &Player{}
ret.Transform = gg.T() //ret.Transform = ox.T()
ret.SetScale(gg.V2(1)) ret.AnimatedSprite = ox.NewAnimatedSprite(
ret.SetAround(gg.V2(.5)) playerAnimations,
time.Second / 1,
)
ret.SetScale(mx.V2(1))
ret.SetAround(mx.V2(.5))
ret.MoveSpeed = 40. ret.MoveSpeed = 40.
ret.ScaleSpeed = .2 ret.ScaleSpeed = .2
ret.Animations = playerAnimations
ret.TimeBetweenFrames = time.Second / 10
ret.Shader = gg.SolidWhiteColorShader ret.Shader = gg.SolidWhiteColorShader
ret.Visible = true ret.Visible = true
ret.Layer = PlayerL ret.Layer = LayerPlayer
//ret.Collidable = true //ret.Collidable = true
//ret.Resolvable = true //ret.Resolvable = true
@ -35,20 +38,28 @@ func NewPlayer() *Player {
return ret return ret
} }
func (p *Player) Start(c *Context) { func (p *Player) OnStart(c Context) {
p.Connect(rect) p.Connect(rect)
} }
func (p *Player) Draw(c *Context) []gg.EVertex { func (p *Player) Draw(c Context) *gg.Drawing {
return p.AnimatedSprite.Draw(c) return p.AnimatedSprite.Draw(c)
prect := &gg.DrawableRectangle{ prect := &ox.DrawableRectangle{
Rectangle: p.Rectangle(), Rectangle: p.GetRectangle(),
} }
prect.Color = gg.Rgba(1, 1, 1, 1) prect.Color = gg.RGBA(1, 1, 1, 1)
return prect.Draw(c) return prect.Draw(c)
} }
func (p *Player) Update(c *Context) { func (p *Player) OnUpdate(c Context) {
log.Println(p.IsVisible())
if p.Spawned {
return
}
e := c.Engine()
dt := e.DT().Seconds()
//cam := c.Camera
keys := e.GetKeyboardKeys()
/*r := gg.Rectangle{ /*r := gg.Rectangle{
Transform: gg.T(), Transform: gg.T(),
} }
@ -57,76 +68,52 @@ func (p *Player) Update(c *Context) {
col, _ := gg.Collide(p, r) col, _ := gg.Collide(p, r)
fmt.Println(col.Crosses)*/ fmt.Println(col.Crosses)*/
//p.SetPosition(p.Position().Sub(gg.Y(2))) //p.SetPosition(p.Position().Sub(gg.Y(2)))
p.Move(gg.Y(1)) //p.Move(gg.Y(1))
if p.Spawned {
return
}
dt := c.Dt().Seconds()
cam := c.Camera
keys := c.Keys()
walking := false walking := false
shift := c.IsPressed(gg.KeyShift) shiftPressed := e.IsPressed(gg.KeyShift)
d := float64(1)
if shiftPressed {
d *= -1
}
//p.Uniforms["Random"] = any(rand.Float32()) //p.Uniforms["Random"] = any(rand.Float32())
for _, v := range keys { for _, key := range keys {
switch v { switch key {
case gg.KeyQ: case gg.KeyQ:
p.SetScale( p.AddScale(mx.VX(d*p.ScaleSpeed * dt))
p.Scale().Add(
gg.X(p.ScaleSpeed * dt),
),
)
case gg.KeyW: case gg.KeyW:
p.Move(gg.Y(-p.MoveSpeed * dt)) p.Move(mx.VY(-p.MoveSpeed * dt))
walking = true walking = true
p.Animate(Walk) p.Animate(Walk)
case gg.KeyA: case gg.KeyA:
p.Move(gg.X(-p.MoveSpeed * dt)) p.Move(mx.VX(-p.MoveSpeed * dt))
p.SetScale(gg.V(-1, 1))
p.SetScale(mx.V(-1, 1))
walking = true walking = true
p.Animate(Walk) p.Animate(Walk)
case gg.KeyS: case gg.KeyS:
p.Move(gg.Y(p.MoveSpeed * dt)) p.Move(mx.VY(p.MoveSpeed * dt))
//p.Position.Y -= p.MoveSpeed * dt //p.Position.Y -= p.MoveSpeed * dt
walking = true walking = true
p.Animate(Walk) p.Animate(Walk)
case gg.KeyD: case gg.KeyD:
p.Move(gg.X(p.MoveSpeed * dt)) p.Move(mx.VX(p.MoveSpeed * dt))
p.SetScale(gg.V(1, 1)) p.SetScale(mx.V(1, 1))
walking = true walking = true
p.Animate(Walk) p.Animate(Walk)
case gg.KeyR:
cam.Rotate(gg.Pi * p.ScaleSpeed * dt) case gg.KeyE :
case gg.KeyT: p.Rotate(d*mx.Pi * 0.3 * dt)
cam.Rotate(-gg.Pi * p.ScaleSpeed * dt) case gg.KeyX:
case gg.KeyRightBracket: c.Engine().Delete(p)
if shift { case gg.KeyC:
p.Rotate(-gg.Pi * 0.3 * dt)
} else {
p.Rotate(+gg.Pi * 0.3 * dt)
}
case gg.KeyF:
if shift {
cam.AddScale(gg.V2(p.ScaleSpeed * dt))
} else {
cam.AddScale(gg.V2(-p.ScaleSpeed * dt))
}
case gg.KeyLeftBracket:
if shift {
rect.Rotate(-gg.Pi * 0.3 * dt)
} else {
rect.Rotate(+gg.Pi * 0.3 * dt)
}
case gg.Key0:
c.Del(p)
case gg.KeyB:
case gg.Key5:
pp := *p pp := *p
counter++ counter++
pp.Spawned = true pp.Spawned = true
pp.Collidable = false //pp.Collidable = false
pp.Resolvable = false //pp.Resolvable = false
c.Spawn(&pp) c.Engine().Spawn(&pp)
} }
} }
@ -134,38 +121,26 @@ func (p *Player) Update(c *Context) {
p.Animate(Stand) p.Animate(Stand)
} }
for _, event := range c.Events { for _, down := range c.Events().Keyboard.KeyDowns {
switch ec := event.(type) {
case *gg.KeyDown:
switch { switch {
case ec.Key == gg.KeyB: case down.Key == gg.KeyZ:
if p.Layer != PlayerL { if p.Layer != LayerPlayer {
p.Layer = PlayerL p.Layer = LayerPlayer
} else { } else {
p.Layer = HighestL p.Layer = LayerHighest
} }
} }
case *gg.MouseMove:
if !c.IsButtoned(gg.MouseButtonRight) {
break
}
c.Camera.Move(ec.Abs)
case *gg.WheelChange:
c.Camera.AddScale(gg.V2(
ec.Offset.Y * dt * p.ScaleSpeed * 40,
))
}
} }
} }
func (p *Player) GetCollisionInterest() []gg.CollisionType { /*func (p *Player) GetCollisionInterest() []gg.CollisionType {
return []gg.CollisionType{ return []gg.CollisionType{
gg.CollisionStaticPhysics, gg.CollisionStaticPhysics,
} }
} }*/
func (p *Player) Resolve(c *Context) { /*func (p *Player) Resolve(c *Context) {
col := c.Collisions[0] col := c.Collisions[0]
if !p.Spawned && false { if !p.Spawned && false {
fmt.Printf( fmt.Printf(
@ -186,4 +161,4 @@ func (p *Player) Resolve(c *Context) {
} }
} }
} }
} }*/

View file

@ -1,21 +1,19 @@
package main package main
import "surdeus.su/core/gg" import "surdeus.su/core/gg"
import "surdeus.su/core/gg/ox"
import "surdeus.su/core/gg/mx"
type Rect struct { type Rect struct {
gg.DrawableRectangle ox.ObjectImpl
ox.DrawableRectangle
} }
func NewRect() *Rect { func NewRect() *Rect {
ret := &Rect{} ret := &Rect{}
ret.SetScale(gg.V(5, 5)) ret.SetScale(mx.V(5, 5))
ret.Color = gg.Color{ ret.Color = gg.RGBA(1, 0, 0, 1)
gg.MaxColorV, ret.Layer = LayerRect
0,
0,
gg.MaxColorV,
}
ret.Layer = RectL
ret.Visible = true ret.Visible = true
//ret.Collidable = true //ret.Collidable = true
ret.Width = 100 ret.Width = 100
@ -24,27 +22,33 @@ func NewRect() *Rect {
return ret return ret
} }
func (r *Rect) CollisionType() gg.CollisionType { func (r *Rect) OnUpdate(c Context) {
return gg.CollisionStaticPhysics
}
func (r *Rect) Update(c *Context) {
//r.R += 0.3 * e.DT() //r.R += 0.3 * e.DT()
dt := c.Dt().Seconds() e := c.Engine()
dt := e.DT().Seconds()
shiftPressed := e.IsPressed(gg.KeyShift)
d := float64(1)
if shiftPressed {
d *= -1
}
//r.Position = c.AbsCursorPosition() //r.Position = c.AbsCursorPosition()
for _, v := range c.Keys() { for _, v := range e.GetKeyboardKeys() {
switch v { switch v {
case gg.KeyArrowUp: case gg.KeyArrowUp:
r.Move(gg.Y(-10 * dt)) r.Move(mx.VY(-10 * dt))
case gg.KeyArrowDown: case gg.KeyArrowDown:
r.Move(gg.Y(10 * dt)) r.Move(mx.VY(10 * dt))
case gg.KeyArrowLeft: case gg.KeyArrowLeft:
r.Move(gg.X(-10 * dt)) r.Move(mx.VX(-10 * dt))
case gg.KeyArrowRight: case gg.KeyArrowRight:
r.Move(gg.X(10 * dt)) r.Move(mx.VX(10 * dt))
case gg.KeyLeftBracket:
r.Rotate(d*mx.Pi * 0.3 * dt)
} }
} }
} }
func (r *Rect) Event(c *Context) { /*func (r *Rect) CollisionType() gg.CollisionType {
} return gg.CollisionStaticPhysics
}*/

View file

@ -2,26 +2,40 @@ package main
import ( import (
"surdeus.su/core/gg" "surdeus.su/core/gg"
"surdeus.su/core/gg/ox"
"github.com/hajimehoshi/ebiten/v2/examples/resources/fonts"
"bytes"
//"fmt" //"fmt"
) )
type Objecter interface {
}
type Wrap[V Objecter] struct {
O V
}
//func (w *Wrap)
type Context2 struct {
*gg.Context
}
type Text struct { type Text struct {
gg.Text ox.ObjectImpl
ox.Text
} }
func (txt *Text) Update(c *Context) { func NewText() (*Text, error) {
txt := &Text{}
txt.Transform = ox.T()
//txt.Position = gg.V2(400)
txt.Color = gg.RGBA(1, 1, 1, 1)
txt.Layer = LayerHighest
txt.Visible = true
txt.Data = "Hello, World!\nПривет, Мир!"
var err error
txt.Face, err = gg.MakeFaceFromTTF(
bytes.NewReader(fonts.MPlus1pRegular_ttf),
&gg.FaceOptionsTTF{
Size: 32,
DPI: 72,
Hinting: gg.FontHintingNone,
},
)
if err != nil {
return nil, err
}
return txt, nil
}
func (txt *Text) Update(c *gg.Context) {
//txt.Data += string(c.Runes()) //txt.Data += string(c.Runes())
} }

View file

@ -1,39 +1,42 @@
package main package main
import "surdeus.su/core/gg" import "surdeus.su/core/gg"
import "fmt" import "surdeus.su/core/gg/ox"
import "surdeus.su/core/gg/mx"
//import "fmt"
var ( var (
counter int counter int
) )
type Tri struct { type Tri struct {
gg.DrawablePolygon ox.ObjectImpl
ox.DrawablePolygon
Spawned bool Spawned bool
} }
func NewTri() *Tri { func NewTri() *Tri {
ret := &Tri{} ret := &Tri{}
ret.Transform = gg.T() ret.Transform = ox.T()
ret.SetPosition(gg.V(-100, -100)) ret.SetPosition(mx.V2(-100))
ret.Triangles = gg.Triangles{ ret.Triangles = mx.Triangles{
gg.Triangle{ mx.Triangle{
gg.V(0, 10), mx.V(0, 10),
gg.V(100, 0), mx.V(100, 0),
gg.V(0, -10), mx.V(0, -10),
}, },
} }
ret.Color = gg.Rgba(1, 1, 0, 1) ret.Color = gg.RGBA(1, 1, 0, 1)
ret.Visible = true ret.Visible = true
//ret.Collidable = true //ret.Collidable = true
ret.Type = gg.CollisionStaticPhysics //ret.Type = gg.CollisionStaticPhysics
ret.Layer = TriangleL ret.Layer = LayerTriangle
//ret.Connect(player) //ret.Connect(player)
return ret return ret
} }
func (t *Tri) Update(c *Context) { func (t *Tri) OnUpdate(c Context) {
//redges := rect.Edges() //redges := rect.Edges()
//tedges := t.Edges() //tedges := t.Edges()
//crosses, ok := tedges.CrossWithEdges(redges) //crosses, ok := tedges.CrossWithEdges(redges)
@ -42,24 +45,25 @@ func (t *Tri) Update(c *Context) {
if false { if false {
//fmt.Println("edges:", tedges) //fmt.Println("edges:", tedges)
} }
col, hasCol := gg.Collide(t, rect) /*col, hasCol := gg.Collide(t, rect)
if hasCol && len(col.Crosses) > 0 { if hasCol && len(col.Crosses) > 0 {
fmt.Println("col:", col) fmt.Println("col:", col)
} }*/
dt := c.Dt().Seconds() e := c.Engine()
if !t.ContainedPoints(gg.Points{c.AbsCursorPosition()}).Empty() { dt := e.DT().Seconds()
/*if !t.ContainedPoints(gg.Points{c.AbsCursorPosition()}).Empty() {
t.Color = gg.Rgba(0, 1, 0, 1) t.Color = gg.Rgba(0, 1, 0, 1)
} else { } else {
t.Color = gg.Rgba(1, 0, 1, 1) t.Color = gg.Rgba(1, 0, 1, 1)
} }*/
if t.Spawned { if t.Spawned {
return return
} }
keys := c.Keys() keys := e.GetKeyboardKeys()
d := +1. d := +1.
if c.IsPressed(gg.KeyShift) { if e.IsPressed(gg.KeyShift) {
d = -1 d = -1
} }
@ -67,21 +71,21 @@ func (t *Tri) Update(c *Context) {
switch key { switch key {
case gg.KeyM: case gg.KeyM:
t.Move(gg.Y(100 * dt * d)) t.Move(mx.VY(100 * dt * d))
case gg.KeyN: case gg.KeyN:
t.Move(gg.X(100 * dt * d)) t.Move(mx.VX(100 * dt * d))
case gg.KeyV: case gg.KeyV:
t.Rotate(d * gg.Pi * 0.3 * dt) t.Rotate(d * mx.Pi * 0.3 * dt)
case gg.Key2: case gg.Key2:
if t.Spawned { if t.Spawned {
break break
} }
t.Triangles = append(t.Triangles, gg.Triangle{ /*t.Triangles = append(t.Triangles, gg.Triangle{
gg.V(0, 10+gg.Float(counter)), gg.V(0, 10+ mx.Float(counter)),
gg.V(100+gg.Float(counter), 0), gg.V(100+ mx.Float(counter), 0),
gg.V(0, -10-gg.Float(counter)), gg.V(0, -10-gg.Float(counter)),
}) })*/
case gg.Key3: case gg.Key3:
if t.Spawned { if t.Spawned {
break break
@ -89,18 +93,16 @@ func (t *Tri) Update(c *Context) {
tt := *t tt := *t
tt.Spawned = true tt.Spawned = true
tt.Disconnect() tt.Disconnect()
if c.Spawn(&tt) == nil { if e.Spawn(&tt) == nil {
counter++ counter++
} }
} }
} }
for _, event := range c.Events { for _, down := range c.Events().Keyboard.KeyDowns {
switch e := event.(type) { switch down.Key {
case *gg.KeyDown:
switch e.Key {
case gg.Key1: case gg.Key1:
if t.Connected() { if t.IsConnected() {
t.Disconnect() t.Disconnect()
} else { } else {
t.Connect(player) t.Connect(player)
@ -108,4 +110,3 @@ func (t *Tri) Update(c *Context) {
} }
} }
} }
}

View file

@ -1,2 +0,0 @@
package gg

View file

@ -1,8 +1,35 @@
package gg package gg
// The type is used to provide
// custom behaviour for drawing and updating etc.
type Context struct { type Context struct {
Events []any events Events
*Engine engine *Engine
*Image image *Image
}
// Get the current engine.
func (c Context) Engine() *Engine {
return c.engine
}
func (c Context) Camera() Camera {
if c.engine == nil {
return nil
}
return c.engine.camera
}
// Get the image to draw to.
// Can be accessed only in the
// Draw(...) call.
func (c Context) Image() *Image {
return c.image
}
// Get the events.
// Available only in the Update(...) call.
func (c Context) Events() Events {
return c.events
} }

View file

@ -1,14 +1,14 @@
package gg package gg
type Drawing struct { type Drawing struct {
EVertices []EVertice Vertices []Vertice
} }
// The interface describes anything that can be // The interface describes anything that can be
// drawn. It will be drew corresponding to // drawn. It will be drew corresponding to
// the layers order so the layer must be returned. // the layers order so the layer must be returned.
type Drawer interface { type Drawer interface {
Draw(Context) Drawing Draw(Context) *Drawing
GetLayer() Layer GetLayer() Layer
IsVisible() bool IsVisible() bool
} }

158
engine.go
View file

@ -17,13 +17,6 @@ const (
type GraphicsLibrary = ebiten.GraphicsLibrary type GraphicsLibrary = ebiten.GraphicsLibrary
type RunOptions = ebiten.RunGameOptions type RunOptions = ebiten.RunGameOptions
// The type represents order of drawing.
// Higher values are drawn later.
type Layer float64
func (l Layer) GetLayer() Layer {
return l
}
// Window configuration type. // Window configuration type.
type WindowConfig struct { type WindowConfig struct {
@ -60,7 +53,7 @@ type Engine struct {
// The main camera to display in window. // The main camera to display in window.
// If is set to nil then the engine will panic. // If is set to nil then the engine will panic.
Camera Camera camera Camera
drawLastTime time.Time drawLastTime time.Time
drawdt Duration drawdt Duration
@ -92,7 +85,7 @@ type Engine struct {
type engine Engine type engine Engine
// Get currently pressed keys. // Get currently pressed keys.
func (e *Engine) Keys() []Key { func (e *Engine) GetKeyboardKeys() []Key {
return e.keys return e.keys
} }
@ -119,7 +112,6 @@ func NewEngine(
ret := &Engine{} ret := &Engine{}
ret.wcfg = cfg ret.wcfg = cfg
ret.Camera = ret.NewCamera()
ret.outerEvents = make(EventChan) ret.outerEvents = make(EventChan)
ret.handleEvents = make(EventChan) ret.handleEvents = make(EventChan)
ret.Objects = &Objects{} ret.Objects = &Objects{}
@ -127,24 +119,16 @@ func NewEngine(
return ret return ret
} }
// Get the real window size in the current context. func (e *Engine) Camera() Camera {
func (c *Engine) RealWinSize() mx.Vector { return e.camera
var w, h int
if c.wcfg.Fullscreen {
w, h = ebiten.ScreenSizeInFullscreen()
} else {
w, h = c.wcfg.Width, c.wcfg.Height
}
return mx.Vector{
mx.Float(w),
mx.Float(h),
}
} }
func (c *Engine) AbsWinSize() mx.Vector { func (e *Engine) SetCamera(c Camera) *Engine {
return c.RealWinSize().Div(c.Camera.GetScale()) e.camera = c
return e
} }
func (e *Engine) EventInput() EventChan { func (e *Engine) EventInput() EventChan {
return e.outerEvents return e.outerEvents
} }
@ -156,7 +140,7 @@ func (e *Engine) Spawn(o Object) error {
}*/ }*/
o.OnStart(Context{ o.OnStart(Context{
Engine: e, engine: e,
}) })
e.Objects.store = append(e.Objects.store, o) e.Objects.store = append(e.Objects.store, o)
@ -186,7 +170,7 @@ var (
) )
func (e *Engine) IsPressed(k Key) bool { func (e *Engine) IsPressed(k Key) bool {
keys := e.Keys() keys := e.GetKeyboardKeys()
for _, v := range keys { for _, v := range keys {
if v == k { if v == k {
return true return true
@ -210,77 +194,121 @@ func (e *Engine) cursorPosition() mx.Vector {
return mx.Vector{mx.Float(x), mx.Float(y)} return mx.Vector{mx.Float(x), mx.Float(y)}
} }
func (e *Engine) CursorPosition() mx.Vector { // Get the real cursor position.
func (e *Engine) GetRealCursorPosition() mx.Vector {
return e.cursorPos return e.cursorPos
} }
func (e *Engine) AbsCursorPosition() mx.Vector { // Get the absolute cursor position in the world
return e.CursorPosition().Apply(e.Camera.GetAbsMatrice()) // of the engine.
func (e *Engine) GetAbsCursorPosition(
) mx.Vector {
return e.GetRealCursorPosition().
Apply(e.camera.GetAbsMatrice(Context{
engine: e,
}))
} }
// Get the real window size in the current context.
func (e *Engine) GetRealWinSize() mx.Vector {
var w, h int
if e.wcfg.Fullscreen {
w, h = ebiten.ScreenSizeInFullscreen()
} else {
w, h = e.wcfg.Width, e.wcfg.Height
}
return mx.Vector{
mx.Float(w),
mx.Float(h),
}
}
func (e *Engine) GetAbsWinSize() mx.Vector {
return e.camera.GetAbsWinSize(Context{
engine: e,
})
}
func (e *Engine) Runes() []rune { func (e *Engine) Runes() []rune {
return e.runes return e.runes
} }
func (e *engine) updateEvents() []any { func (e *engine) updateEvents() Events {
eng := (*Engine)(e) eng := (*Engine)(e)
e.prevKeys = e.keys e.prevKeys = e.keys
e.keys = inpututil. e.keys = inpututil.
AppendPressedKeys(e.keys[:0]) AppendPressedKeys(e.keys[:0])
events := []any{} events := Events{}
// Mouse buttons.
btns := e.buttons btns := e.buttons
for _, btn := range allButtons { for _, btn := range allButtons {
if inpututil.IsMouseButtonJustPressed(btn) { if inpututil.IsMouseButtonJustPressed(btn) {
btns[btn] = struct{}{} btns[btn] = struct{}{}
events = append(events, &MouseButtonDown{ events.Mouse.ButtonDowns = append(
events.Mouse.ButtonDowns,
MouseButtonDown{
MouseButton: btn, MouseButton: btn,
}) },
)
} else if inpututil.IsMouseButtonJustReleased(btn) { } else if inpututil.IsMouseButtonJustReleased(btn) {
delete(btns, btn) delete(btns, btn)
events = append(events, &MouseButtonUp{ events.Mouse.ButtonUps = append(
events.Mouse.ButtonUps,
MouseButtonUp{
MouseButton: btn, MouseButton: btn,
}) },
)
} }
} }
// Mouse wheel.
x, y := ebiten.Wheel() x, y := ebiten.Wheel()
e.wheel = mx.Vector{x, y} e.wheel = mx.Vector{x, y}
if !(e.wheel.Eq(mx.ZV)) { if !(e.wheel.Eq(mx.ZV)) {
events = append(events, &WheelChange{ events.Mouse.WheelChange = &WheelChange{
Offset: e.wheel, Offset: e.wheel,
}) }
}
keyDiff := diffEm(e.prevKeys, e.keys)
for _, key := range keyDiff {
var event any
if eng.IsPressed(key) {
event = &KeyDown{
Key: key,
}
} else {
event = &KeyUp{
Key: key,
}
}
events = append(events, event)
} }
// Cursor position.
realPos := eng.cursorPosition() realPos := eng.cursorPosition()
if !realPos.Eq(e.cursorPos) { if !realPos.Eq(e.cursorPos) {
absM := eng.Camera.GetAbsMatrice() absM := eng.camera.GetAbsMatrice(Context{
engine: eng,
})
absPrevPos := e.cursorPos.Apply(absM) absPrevPos := e.cursorPos.Apply(absM)
absPos := realPos.Apply(absM) absPos := realPos.Apply(absM)
events = append(events, &MouseMove{ events.Mouse.Move = &MouseMove{
RealDelta: realPos.Sub(e.cursorPos), RealDelta: realPos.Sub(e.cursorPos),
AbsDelta: absPos.Sub(absPrevPos), AbsDelta: absPos.Sub(absPrevPos),
}) }
e.cursorPos = realPos e.cursorPos = realPos
} }
// Keyboard.
keyDiff := diffEm(e.prevKeys, e.keys)
for _, key := range keyDiff {
if eng.IsPressed(key) {
events.Keyboard.KeyDowns = append(
events.Keyboard.KeyDowns,
KeyDown{
Key: key,
},
)
} else {
events.Keyboard.KeyUps = append(
events.Keyboard.KeyUps,
KeyUp{
Key: key,
},
)
}
}
return events return events
} }
@ -298,8 +326,8 @@ func (e *engine) Update() error {
events := e.updateEvents() events := e.updateEvents()
c := Context{ c := Context{
Engine: eng, engine: eng,
Events: events, events: events,
} }
for _, object := range e.Objects.store { for _, object := range e.Objects.store {
object.OnUpdate(c) object.OnUpdate(c)
@ -350,16 +378,16 @@ func (e *engine) Draw(img *ebiten.Image) {
// First drawing via the inside function // First drawing via the inside function
// and then the returned []EVertex. // and then the returned []EVertex.
layers := maps.NewSparse[Layer, []Drawer](nil, m) layers := maps.NewSparse[Layer, []Drawer](nil, m)
c := Context{Engine: eng, Image: img} c := Context{engine: eng, image: img}
for layer := range layers.Chan() { for layer := range layers.Chan() {
vertices := []EVertice{} vertices := Vertices{}
for _, drawer := range layer { for _, drawer := range layer {
drawing := drawer.Draw(c) drawing := drawer.Draw(c)
if drawing.EVertices != nil { if drawing != nil {
vertices = append( vertices = append(
vertices, vertices,
drawing.EVertices..., drawing.Vertices...,
) )
} }
} }
@ -369,7 +397,7 @@ func (e *engine) Draw(img *ebiten.Image) {
for i := 0 ; i<pn ; i++ { for i := 0 ; i<pn ; i++ {
cur := i*MaxVertices cur := i*MaxVertices
img.DrawTriangles( img.DrawTriangles(
vertices[cur:cur+MaxVertices], vertices[cur:cur+MaxVertices].ToAPI(),
fullPageIndexes[:], fullPageIndexes[:],
defaultPageImg, defaultPageImg,
defaultTriOptions, defaultTriOptions,
@ -378,7 +406,7 @@ func (e *engine) Draw(img *ebiten.Image) {
st := pn*MaxVertices st := pn*MaxVertices
img.DrawTriangles( img.DrawTriangles(
vertices[st:], vertices[st:].ToAPI(),
fullPageIndexes[:mod], fullPageIndexes[:mod],
defaultPageImg, defaultPageImg,
defaultTriOptions, defaultTriOptions,
@ -387,7 +415,6 @@ func (e *engine) Draw(img *ebiten.Image) {
// Empty the buff to generate it again. // Empty the buff to generate it again.
eng.Camera.buffered = false
e.drawLastTime = time.Now() e.drawLastTime = time.Now()
e.dframe++ e.dframe++
} }
@ -453,3 +480,6 @@ func (e *Engine) Run() error {
return ebiten.RunGameWithOptions((*engine)(e), e.wcfg.Options) return ebiten.RunGameWithOptions((*engine)(e), e.wcfg.Options)
} }
func (e *Engine) GetWindowConfig() WindowConfig {
return e.wcfg
}

View file

@ -67,5 +67,22 @@ type WheelChange struct {
Offset mx.Vector Offset mx.Vector
} }
type KeyboardEvents struct {
KeyDowns []KeyDown
KeyUps []KeyUp
}
type MouseEvents struct {
ButtonDowns []MouseButtonDown
ButtonUps []MouseButtonUp
Move *MouseMove
WheelChange *WheelChange
}
type Events struct {
Keyboard KeyboardEvents
Mouse MouseEvents
}
type EventChan chan any type EventChan chan any

9
layer.go Normal file
View file

@ -0,0 +1,9 @@
package gg
// The type represents order of drawing.
// Higher values are drawn later.
type Layer float64
func (l Layer) GetLayer() Layer {
return l
}

8
math.go Normal file
View file

@ -0,0 +1,8 @@
package gg
import (
//"surdeus.su/core/gg/mx"
)
//type Float = mx.Float

View file

@ -11,11 +11,11 @@ import (
type Float = float64 type Float = float64
const ( const (
MaxFloat = math.MaxFloat64 MaxFloat Float = math.MaxFloat64
Pi = math.Pi Pi Float = math.Pi
RadDegrees = 57.2958 RadDegrees Float = 57.2958
//PiRad = Pi * Rad //PiRad = Pi * Rad
EqualityThreshold = 1e-9 EqualityThreshold Float = 1e-9
) )
func IsNan(v Float) bool { func IsNan(v Float) bool {

View file

@ -76,6 +76,15 @@ func (t Triangle) GetVertices() Vectors {
type Triangles []Triangle type Triangles []Triangle
func (ts Triangles) ContainsPoint(pt Vector) bool {
for _, t := range ts {
if t.ContainsPoint(pt) {
return true
}
}
return false
}
func (ts Triangles) GetContainedPoints( func (ts Triangles) GetContainedPoints(
pts Vectors, pts Vectors,
) Vectors { ) Vectors {

View file

@ -8,7 +8,7 @@ type Object interface {
OnStart(Context) OnStart(Context)
OnUpdate(Context) OnUpdate(Context)
OnDelete(Context) OnDelete(Context)
GetTags() map[string]struct{} GetTags() TagMap
} }

View file

@ -1,14 +1,16 @@
package ox package ox
//import "time"
import "surdeus.su/core/gg" import "surdeus.su/core/gg"
import "surdeus.su/core/gg/ax" import "surdeus.su/core/gg/ax"
var _ = gg.Drawer(&AnimatedSprite{})
// The type implements animated sprites. // The type implements animated sprites.
type AnimatedSprite struct { type AnimatedSprite struct {
Sprite Sprite
animations ax.AnimationSet animations ax.AnimationSet
animationId ax.AnimationId animationId ax.AnimationID
currentFrame int currentFrame int
@ -19,36 +21,40 @@ type AnimatedSprite struct {
} }
func NewAnimatedSprite( func NewAnimatedSprite(
) *AnimatedSprite { animations ax.AnimationSet,
ret := &AnimatedSprite{} timeBetweenFrames gg.Duration,
) AnimatedSprite {
ret := AnimatedSprite{}
ret.animations = animations
ret.timeBetweenFrames = timeBetweenFrames
return ret return ret
} }
// Change current animation to the specified one. // Change current animation to the specified one.
func (as *AnimatedSprite) Animate(id ax.AnimationId) bool { func (as *AnimatedSprite) Animate(id ax.AnimationID) bool {
if as.AnimationId == id { if as.animationId == id {
return true return true
} }
_, ok := as.Animations[id] _, ok := as.animations[id]
if ok { if ok {
as.duration = 0 as.duration = 0
as.AnimationId = id as.animationId = id
} }
return ok return ok
} }
func (as *AnimatedSprite) Draw(c Context) []EVertex { func (as *AnimatedSprite) Draw(c gg.Context) *gg.Drawing {
as.duration += c.DrawDT() as.duration += c.Engine().DrawDT()
frames := as.Animations[as.AnimationId] frames := as.animations[as.animationId]
fullTime := Duration(len(frames)) * as.TimeBetweenFrames fullTime := gg.Duration(len(frames)) * as.timeBetweenFrames
if as.duration > fullTime { if as.duration > fullTime {
as.duration -= fullTime as.duration -= fullTime
} }
as.Images[0] = frames[ as.Images[0] = frames[
(as.duration/as.TimeBetweenFrames) % (as.duration/as.timeBetweenFrames) %
Duration(len(frames)), gg.Duration(len(frames)),
] ]
return as.Sprite.Draw(c) return as.Sprite.Draw(c)

View file

@ -5,9 +5,8 @@ import "surdeus.su/core/gg/mx"
// Default camera implementation. // Default camera implementation.
var _ = gg.Camera(&Camera{})
type Camera struct { type Camera struct {
ObjectImpl
// The Transform to interact with // The Transform to interact with
// to change camera position, rotation etc. // to change camera position, rotation etc.
Transform Transform
@ -18,13 +17,13 @@ type Camera struct {
// The bufferization implementation // The bufferization implementation
// to keep everything fast. // to keep everything fast.
absMatrice realMatrice absMatrice, realMatrice mx.Matrice
} }
// Returns the new camera // Returns the new camera
// with default settings. // with default settings.
func NewCamera() *Camera { func NewCamera() Camera {
ret := &Camera{} ret := Camera{}
ret.Transform = T() ret.Transform = T()
return ret return ret
} }
@ -37,7 +36,7 @@ func (c *Camera) GetRealMatrice(ctx gg.Context) mx.Matrice {
// Bufferization // Bufferization
// so we do not need to recalculate // so we do not need to recalculate
// Transform again. // Transform again.
if !c.Transform.Dirty() { if !c.Transform.IsDirty() {
return c.realMatrice return c.realMatrice
} }
@ -50,7 +49,7 @@ func (c *Camera) GetRealMatrice(ctx gg.Context) mx.Matrice {
g.Translate(-position.X, -position.Y) g.Translate(-position.X, -position.Y)
g.Rotate(rotation) g.Rotate(rotation)
size := ctx.Engine.AbsWinSize() size := ctx.Engine().GetAbsWinSize()
g.Translate(around.X * size.X, around.Y * size.Y) g.Translate(around.X * size.X, around.Y * size.Y)
g.Scale(scale.X, scale.Y) g.Scale(scale.X, scale.Y)
@ -63,14 +62,21 @@ func (c *Camera) GetRealMatrice(ctx gg.Context) mx.Matrice {
// inside engine representation, // inside engine representation,
// get the position of cursor inside the world // get the position of cursor inside the world
// basing on its window position. // basing on its window position.
func (c *Camera) GetAbsMatrice(ctx gg.Context) mx.Matrice { func (camera *Camera) GetAbsMatrice(ctx gg.Context) mx.Matrice {
if !c.Transform.Dirty() { if !camera.Transform.IsDirty() {
return c.absMatrice return camera.absMatrice
} }
m := c.GetRealMatrice(ctx) m := camera.GetRealMatrice(ctx)
m.Invert() m.Invert()
c.absMatrice = m camera.absMatrice = m
return m return m
} }
func (camera *Camera) GetAbsWinSize(
ctx gg.Context,
) mx.Vector {
return ctx.Engine().GetRealWinSize().
Div(camera.GetScale())
}

View file

@ -5,27 +5,28 @@ import (
) )
import "surdeus.su/core/gg" import "surdeus.su/core/gg"
import "surdeus.su/core/gg/mx"
type Circle struct { type Circle struct {
ObjectImpl ObjectImpl
gg.Transform mx.Circle
Visibility Visibility
Colority Colority
Antialiasity Antialiasity
Layer gg.Layer
Radius Float
} }
func (circle *Circle) Draw(c *Context) []EVertex { func (circle *Circle) Draw(c gg.Context) gg.Drawing {
rPos := circle.Position().Apply(c.Camera.RealMatrix()) center := circle.Center.
Apply(c.Camera().GetRealMatrice(c))
vector.DrawFilledCircle( vector.DrawFilledCircle(
c.Image, c.Image(),
float32(rPos.X), float32(rPos.Y), float32(center.X), float32(center.Y),
float32(circle.Radius), float32(circle.Radius),
circle.Color, circle.Color,
circle.Antialias, circle.Antialias,
) )
return nil return gg.Drawing{}
} }

View file

@ -1,5 +1,15 @@
package ox package ox
import "surdeus.su/core/gg"
type Drawity struct {
Visibility
Colority
Shaderity
Floatity
Layerity
}
// Feat to emded for turning antialias on and off. // Feat to emded for turning antialias on and off.
type Antialiasity struct { type Antialiasity struct {
@ -14,18 +24,32 @@ func (v Visibility) IsVisible() bool {
return v.Visible return v.Visible
} }
func (v Visibility) ToggleVisibility() bool {
v.Visible = !v.Visible
return v.IsVisible()
}
// Feat to embed to make colorful objects. // Feat to embed to make colorful objects.
type Colority struct { type Colority struct {
Color Color Color gg.Color
} }
// The structure to embed into shaderable // The structure to embed into shaderable
// objects. // objects.
type Shaderity struct { type Shaderity struct {
ShaderOptions ShaderOptions gg.ShaderOptions
} }
func (s *Shaderity) GetShaderOptions( func (s Shaderity) GetShaderOptions(
) *ShaderOptions { ) *gg.ShaderOptions {
return &s.ShaderOptions return &s.ShaderOptions
} }
type Floatity struct {
Floating bool
}
func (s Floatity) IsFloating() bool {
return s.Floating
}
type Layerity = gg.Layer

View file

@ -1,12 +1,25 @@
package ox package ox
import "surdeus.su/core/gg"
type DrawerImpl struct{}
func (o DrawerImpl) Draw(c gg.Context) *gg.Drawing {
return nil
}
func (o DrawerImpl) GetLayer() gg.Layer {return 0}
func (o DrawerImpl) IsVisible() bool {return false}
type BeherImpl struct{}
func (o BeherImpl) OnStart(c gg.Context) {}
func (o BeherImpl) OnUpdate(c gg.Context) {}
func (o BeherImpl) OnDelete(c gg.Context) {}
func (o BeherImpl) GetTags() gg.TagMap {return nil}
// The standard empty implementation // The standard empty implementation
// of the Object interface to embed. // of the Object interface to embed
type ObjectImpl struct {} // so you do not need to implement everything.
func (o ObjectImpl) OnStart(c Context) {} var _ = gg.Object(ObjectImpl{})
func (o ObjectImpl) OnUpdate(c Context) {} type ObjectImpl struct {
func (o ObjectImpl) OnDelete(c Context) {} DrawerImpl
func (o ObjectImpl) GetTags() map[string]struct{}{return nil} BeherImpl
func (o ObjectImpl) Draw(c Context) {} }
func (o ObjectImpl) GetLayer() Layer {return 0}
func (o ObjectImpl) IsVisible() bool {return false}

View file

@ -12,15 +12,18 @@ type Polygon struct {
mx.Triangles mx.Triangles
} }
func (p Polygon) ContainedPoints(pts Points) (Points) { func (p Polygon) GetContainedPoints(
return p.MakeTriangles().ContainedPoints(pts) pts mx.Vectors,
) (mx.Vectors) {
return p.MakeTriangles().
GetContainedPoints(pts)
} }
func (p Polygon) MakeTriangles() Triangles { func (p Polygon) MakeTriangles() mx.Triangles {
m := p.Transform.GetMatrice() m := p.Transform.GetMatrice()
ret := make(Triangles, len(p.Triangles)) ret := make(mx.Triangles, len(p.Triangles))
for i, t := range p.Triangles { for i, t := range p.Triangles {
ret[i] = Triangle{ ret[i] = mx.Triangle{
t[0].Apply(m), t[0].Apply(m),
t[1].Apply(m), t[1].Apply(m),
t[2].Apply(m), t[2].Apply(m),
@ -38,21 +41,18 @@ func (p Polygon) GetEdges() mx.Lines {
return p.MakeTriangles().GetEdges() return p.MakeTriangles().GetEdges()
} }
var _ = gg.Drawer(&DrawablePolygon{})
// Polygon that can be drawn. // Polygon that can be drawn.
type DrawablePolygon struct { type DrawablePolygon struct {
Polygon Polygon
ShaderOptions
Visibility Drawity
Colority
} }
func (p *DrawablePolygon) Draw(c *Context) gg.Drawing { func (p *DrawablePolygon) Draw(c gg.Context) *gg.Drawing {
ret := gg.Drawing{ tri := &DrawableTriangles{}
EVertices: (&DrawableTriangles{ tri.Triangles = p.MakeTriangles()
Colority: p.Colority, tri.Drawity = p.Drawity
Triangles: p.MakeTriangles(), return tri.Draw(c)
}).MakeEVertices(c),
}
return ret
} }

View file

@ -13,30 +13,30 @@ import "surdeus.su/core/gg/mx"
// way to move, rotate and scale it. // way to move, rotate and scale it.
type Rectangle struct { type Rectangle struct {
ObjectImpl ObjectImpl
gg.Transform Transform
Width, Height Float Width, Height mx.Float
} }
// Return points of vertices of the rectangle. // Return points of vertices of the rectangle.
func (r Rectangle) Vertices() mx.Vectors { func (r Rectangle) Vertices() mx.Vectors {
t := r.Transform t := r.Transform
wh := V(r.Width, r.Height) wh := mx.Vector{r.Width, r.Height}
t.SetAround(t.Around().Mul(wh)) t.SetAround(t.GetAround().Mul(wh))
m := t.Matrix() m := t.GetMatrice()
p1 := V(0, 0).Apply(m) p1 := mx.Vector{0, 0}.Apply(m)
p2 := V(wh.X, 0).Apply(m) p2 := mx.Vector{wh.X, 0}.Apply(m)
p3 := V(wh.X, wh.Y).Apply(m) p3 := mx.Vector{wh.X, wh.Y}.Apply(m)
p4 := V(0, wh.Y).Apply(m) p4 := mx.Vector{0, wh.Y}.Apply(m)
return mx.Vectors{p1, p2, p3, p4} return mx.Vectors{p1, p2, p3, p4}
} }
func (r Rectangle) Edges() mx.Lines { func (r Rectangle) Edges() mx.Lines {
vs := r.Vertices() vs := r.Vertices()
return Lines{ return mx.Lines{
Edge{vs[0], vs[1]}, mx.Line{vs[0], vs[1]},
Edge{vs[1], vs[2]}, mx.Line{vs[1], vs[2]},
Edge{vs[2], vs[3]}, mx.Line{vs[2], vs[3]},
Edge{vs[3], vs[0]}, mx.Line{vs[3], vs[0]},
} }
} }
@ -55,6 +55,11 @@ func (r Rectangle) MakeTriangles() mx.Triangles {
} }
// Check whether the rectangle contains the point. // Check whether the rectangle contains the point.
func (r Rectangle) ContainsPoint(pt mx.Vector) bool {
return r.MakeTriangles().ContainsPoint(pt)
}
// Get the points that are contained in the rectangle.
func (r Rectangle) GetContainedPoints( func (r Rectangle) GetContainedPoints(
pts mx.Vectors, pts mx.Vectors,
) (mx.Vectors) { ) (mx.Vectors) {
@ -64,19 +69,14 @@ func (r Rectangle) GetContainedPoints(
// The type describes rectangle that can be drawn. // The type describes rectangle that can be drawn.
type DrawableRectangle struct { type DrawableRectangle struct {
Rectangle Rectangle
ShaderOptions Drawity
// Solid color of the rectangle.
// Will be ignored if the Shader
// field is not nil.
Colority
} }
func (r *DrawableRectangle) Draw(c *Context) []EVertex { func (r *DrawableRectangle) Draw(c gg.Context) *gg.Drawing {
return (&DrawableTriangles{ tri := &DrawableTriangles{}
Colority: r.Colority, tri.Drawity = r.Drawity
Triangles: r.MakeTriangles(), tri.Triangles = r.MakeTriangles()
}).MakeEVertices(c) return tri.Draw(c)
/*// Use the Color as base image if no is provided. /*// Use the Color as base image if no is provided.
//var did bool //var did bool

View file

@ -5,22 +5,21 @@ import (
//"fmt" //"fmt"
) )
import "surdeus.su/core/gg"
import "surdeus.su/core/gg/mx" import "surdeus.su/core/gg/mx"
import "surdeus.su/core/gg"
var _ = gg.Drawer(&Sprite{})
type Sprite struct { type Sprite struct {
ObjectImpl Transform
gg.Transform
ShaderOptions Drawity
Floating bool
Visibility
} }
var ( var (
//spritesOp DrawImageOptions //spritesOp DrawImageOptions
) )
func (s *Sprite) Draw(c Context) []EVertex { func (s *Sprite) Draw(c gg.Context) *gg.Drawing {
// Nothing to draw. // Nothing to draw.
if s.Images[0] == nil { if s.Images[0] == nil {
return nil return nil
@ -28,13 +27,13 @@ func (s *Sprite) Draw(c Context) []EVertex {
t := s.GetRectangleToDraw().Transform t := s.GetRectangleToDraw().Transform
m := t.GetMatrice() m := t.GetMatrice()
if !s.Floating { if !s.IsFloating() {
m.Concat(c.Camera.GetRealMatrix()) m.Concat(c.Camera().GetRealMatrice(c))
} }
// Drawing without shader. // Drawing without shader.
if s.Shader == nil { if s.Shader == nil {
c.DrawImage(s.Images[0], &ebiten.DrawImageOptions{ c.Image().DrawImage(s.Images[0], &ebiten.DrawImageOptions{
GeoM: m, GeoM: m,
}) })
return nil return nil
@ -42,7 +41,7 @@ func (s *Sprite) Draw(c Context) []EVertex {
w, h := s.Images[0].Size() w, h := s.Images[0].Size()
// Drawing with shader. // Drawing with shader.
c.DrawRectShader( c.Image().DrawRectShader(
w, h, w, h,
s.Shader, s.Shader,
&ebiten.DrawRectShaderOptions{ &ebiten.DrawRectShaderOptions{
@ -63,8 +62,8 @@ func (s *Sprite) GetRectangleToDraw() Rectangle {
w, h := s.Images[0].Size() w, h := s.Images[0].Size()
t := s.Transform t := s.Transform
t.SetAround( t.SetAround(
t.Around().Mul( t.GetAround().Mul(
V(Float(w), Float(h)), mx.Vector{mx.Float(w), mx.Float(h)},
), ),
) )
@ -87,15 +86,15 @@ func (s *Sprite) GetRectangle() Rectangle {
return Rectangle{ return Rectangle{
Transform: t, Transform: t,
Width: Float(w), Width: mx.Float(w),
Height: Float(h), Height: mx.Float(h),
} }
} }
// Get triangles of the rectangle that contains the sprite // Get triangles of the rectangle that contains the sprite
// and has the same widght and height. // and has the same widght and height.
func (s *Sprite) MakeTriangles() Triangles { func (s *Sprite) MakeTriangles() mx.Triangles {
return s.Rectangle().MakeTriangles() return s.GetRectangle().MakeTriangles()
} }
func (s *Sprite) Vertices() mx.Vectors { func (s *Sprite) Vertices() mx.Vectors {
@ -106,10 +105,14 @@ func (s *Sprite) Edges() mx.Lines {
return s.GetRectangle().Edges() return s.GetRectangle().Edges()
} }
func (s *Sprite) ContainsPoint(pt mx.Vector) bool { func (s *Sprite) ContainsPoint(
pt mx.Vector,
) bool {
return s.GetRectangle().ContainsPoint(pt) return s.GetRectangle().ContainsPoint(pt)
} }
func (s *Sprite) GetContainedPoints(pts mx.Vectors) Points { func (s *Sprite) GetContainedPoints(
return s.Rectangle().GetContainedPoints(pts) pts mx.Vectors,
) mx.Vectors {
return s.GetRectangle().GetContainedPoints(pts)
} }

View file

@ -1,25 +1,36 @@
package ox package ox
import "surdeus.su/core/gg/mx" //import "surdeus.su/core/gg/mx"
import "surdeus.su/core/gg" import "surdeus.su/core/gg"
import "github.com/hajimehoshi/ebiten/v2/text"
import "github.com/hajimehoshi/ebiten/v2"
// The type implements basic drawable text. // The type implements basic drawable text.
// (Now needs to implement rotation, scaling etc, cause now only position) // (Now needs to implement rotation, scaling etc, cause now only position)
type Text struct { type Text struct {
ObjectImpl ObjectImpl
mx.Transform Transform
Data string
Face Face
Colority Colority
Visibility Visibility
Shaderity
Floatity
Face gg.Face
Data string
} }
func (txt *Text) Draw(c gg.Context) []EVertex { func (txt *Text) Draw(c gg.Context) *gg.Drawing {
m := txt.Matrix() m := txt.Transform.GetMatrice()
m.Concat(c.Camera.RealMatrix()) if !txt.IsFloating() {
m.Concat(c.Camera().GetRealMatrice(c))
}
//x, y := txt.Position.XY() //x, y := txt.Position.XY()
//text.Draw(c.Image) //text.Draw(c.Image)
text.DrawWithOptions(c.Image, txt.Data, txt.Face, text.DrawWithOptions(
c.Image(),
txt.Data,
txt.Face,
&ebiten.DrawImageOptions{ &ebiten.DrawImageOptions{
GeoM: m, GeoM: m,
}, },

View file

@ -43,7 +43,7 @@ func T() Transform {
// Returns whether it needs to be recalculated // Returns whether it needs to be recalculated
// or not. // or not.
func (t *Transform) IsDirty() bool { func (t *Transform) IsDirty() bool {
return t.dirty return t.dirty || t.parentDirty
} }
// For implementing the Transformer on embedding. // For implementing the Transformer on embedding.

View file

@ -1,20 +1,35 @@
package ox package ox
import "surdeus.su/core/gg/mx"
import "surdeus.su/core/gg"
//import "github.com/hajimehoshi/ebiten/v2"
type DrawableTriangles struct { type DrawableTriangles struct {
Triangles mx.Triangles
Colority
Drawity
} }
func (r *DrawableTriangles) MakeEVertices(c *Context) []EVertex { func (r *DrawableTriangles) MakeVertices(
m := c.Camera.RealMatrix() c gg.Context,
vs := make([]ebiten.Vertex, len(r.Triangles) * 3) ) gg.Vertices {
var buf Vertex m := c.Camera().GetRealMatrice(c)
vs := make(gg.Vertices, len(r.Triangles) * 3)
var buf gg.Vertice
buf.Color = r.Color buf.Color = r.Color
for i := range r.Triangles { for i := range r.Triangles {
for j := range r.Triangles[i] { for j := range r.Triangles[i] {
buf.Dst = r.Triangles[i][j].Apply(m) buf.Dst = r.Triangles[i][j].Apply(m)
vs[i*3 + j] = buf.Ebiten() vs[i*3 + j] = buf
} }
} }
return vs return vs
} }
func (r *DrawableTriangles) Draw(
c gg.Context,
) *gg.Drawing {
return &gg.Drawing{
Vertices: r.MakeVertices(c),
}
}

5
tag.go Normal file
View file

@ -0,0 +1,5 @@
package gg
type Tag int64
type TagMap map[Tag] struct{}

View file

@ -4,8 +4,6 @@ import (
//"strings" //"strings"
"golang.org/x/image/font" "golang.org/x/image/font"
"golang.org/x/image/font/opentype" "golang.org/x/image/font/opentype"
//"github.com/hajimehoshi/ebiten/v2/text"
//"github.com/hajimehoshi/ebiten/v2"
"io" "io"
//"fmt" //"fmt"
) )

4
vector.go Normal file
View file

@ -0,0 +1,4 @@
package gg
//import "surdeus.su/core/gg/mx"

View file

@ -12,15 +12,26 @@ type Vertice struct {
Color Color
} }
// Convert the vertice into the Ebiten's type.
func (v Vertice) ToAPI() EVertice { func (v Vertice) ToAPI() EVertice {
r, g, b, a := v.RGBA()
return EVertice { return EVertice {
DstX: float32(v.Dst.X), DstX: float32(v.Dst.X),
DstY: float32(v.Dst.Y), DstY: float32(v.Dst.Y),
SrcX: float32(v.Src.X), SrcX: float32(v.Src.X),
SrcY: float32(v.Src.Y), SrcY: float32(v.Src.Y),
ColorR: float32(v.Color.R)/(float32(MaxColorValue)), ColorR: float32(r)/(float32(MaxColorValue)),
ColorG: float32(v.Color.G)/(float32(MaxColorValue)), ColorG: float32(g)/(float32(MaxColorValue)),
ColorB: float32(v.Color.B)/(float32(MaxColorValue)), ColorB: float32(b)/(float32(MaxColorValue)),
ColorA: float32(v.Color.A)/(float32(MaxColorValue)), ColorA: float32(a)/(float32(MaxColorValue)),
} }
} }
type Vertices []Vertice
func (vs Vertices) ToAPI() []EVertice {
ret := make([]EVertice, len(vs))
for i, v := range vs {
ret[i] = v.ToAPI()
}
return ret
}