From 31940fa8992e0c875b269e3fa290bb0c858e6a02 Mon Sep 17 00:00:00 2001 From: surdeus Date: Tue, 16 Jan 2024 04:11:42 +0300 Subject: [PATCH] feat: implemented the basic collider system. --- cmd/test/player.go | 37 +++++++++++++++++++++++++++++++++++-- cmd/test/rect.go | 3 +++ collider.go | 23 ++++++++++++++++------- engine.go | 38 +++++++++++++++++++++++++++++++++----- rect.go | 22 ++++++++-------------- sprite.go | 39 +++++++++++++++++++++++++++++++++------ 6 files changed, 128 insertions(+), 34 deletions(-) diff --git a/cmd/test/player.go b/cmd/test/player.go index f45b78a..5368126 100644 --- a/cmd/test/player.go +++ b/cmd/test/player.go @@ -2,7 +2,7 @@ package main import ( //"math/rand" - //"fmt" + "fmt" "time" ) @@ -28,12 +28,24 @@ func NewPlayer() *Player { ret.Visible = true ret.Layer = PlayerL + ret.Collidable = true + ret.Resolvable = true + return ret } func (p *Player) Start(c *Context) { } +func (p *Player) Draw(c *Context) []gg.EVertex { + return p.AnimatedSprite.Draw(c) + prect := &gg.DrawableRectangle{ + Rectangle: p.Rectangle(), + } + prect.Color = gg.Rgba(1, 1, 1, 1) + return prect.Draw(c) +} + func (p *Player) Update(c *Context) { if p.Spawned { return @@ -58,7 +70,7 @@ func (p *Player) Update(c *Context) { case gg.KeyArrowRight: cam.Position.X += p.MoveSpeed * dt case gg.KeyW: - p.Position.Y += p.MoveSpeed * dt + p.Position.Y -= p.MoveSpeed * dt*10 walking = true p.Animate(Walk) case gg.KeyA: @@ -140,5 +152,26 @@ func (p *Player) Update(c *Context) { ec.Offset.Y * dt * p.ScaleSpeed * 40, )) }} + + p.Position.Y += 2 +} + +func (p *Player) Resolve(c *Context) { + + col := c.Collisions[0] + fmt.Printf("frame[%d]: the col[0] len(%d): %T, %T\n", c.Frame(), len(c.Collisions), col.What, col.With) + switch col.Type{ + case gg.PhysCollision : + LOOP: + for { + p.Position.Y -= 0.2 + shit, collides := gg.Collide(p, col.With) + fmt.Println("shit:", shit) + fmt.Println("do:", collides) + if !collides { + break LOOP + } + } + } } diff --git a/cmd/test/rect.go b/cmd/test/rect.go index 7a70fdc..9f37d55 100644 --- a/cmd/test/rect.go +++ b/cmd/test/rect.go @@ -17,6 +17,9 @@ func NewRect() *Rect { } ret.Layer = RectL ret.Visible = true + ret.Collidable = true + ret.Width = 100 + ret.Height = 200 return ret } diff --git a/collider.go b/collider.go index 2f16c79..d1326c2 100644 --- a/collider.go +++ b/collider.go @@ -12,14 +12,14 @@ package gg type CollisionType int const ( - CollisionTypePhys CollisionType = iota - CollisionTypeTrigger + PhysCollision CollisionType = iota + TriggerCollision ) // The structure contains collision information. type Collision struct { Type CollisionType - What, With Objecter + What, With Collider // Points of Self contained in Points Points Crosses []LineCross @@ -28,19 +28,21 @@ type Collision struct { // Implementing the interface lets the engine // to determine if the object collides with anything. -// Mostly will use the Collide function with some -// inner structure field as first argument. -// The Collide method will be called on collisions. type Collider interface { // Checks whether the object is collidable + CollisionType() CollisionType IsCollidable() bool Verticer Edger PointContainer } type Collidability struct { + Type CollisionType Collidable bool } +func (c Collidability) CollisionType() CollisionType { + return c.Type +} func (c Collidability) IsCollidable() bool { return c.Collidable } @@ -75,6 +77,9 @@ func Collide(c1, c2 Collider) (Collision, bool) { crosses, doCross := es1.LineCrossWith(es2) pts := c2.ContainedPoints(vertices) return Collision{ + Type: c2.CollisionType(), + What: c1, + With: c2, Points: pts, Crosses: crosses, }, len(pts) != 0 || doCross @@ -83,9 +88,13 @@ func Collide(c1, c2 Collider) (Collision, bool) { func GetCollisions(c Collider, cs []Collider) []Collision { ret := []Collision{} for _, ic := range cs { - if !ic.IsCollidable() || ic == c { + if ic == c { continue } + col, has := Collide(c, ic) + if has { + ret = append(ret, col) + } } return ret } diff --git a/engine.go b/engine.go index 6a97039..4c211fa 100644 --- a/engine.go +++ b/engine.go @@ -4,7 +4,7 @@ import ( "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/inpututil" "vultras.su/core/gods/maps" - "fmt" + //"fmt" "time" "slices" "sync" @@ -164,7 +164,12 @@ func (e *Engine) Spawn(b Objecter) error { obj.input = make(chan *Context) go func() { for c := range obj.input { - b.Update(c) + switch c.typ{ + case updateContext : + b.Update(c) + case resolveContext : + b.Resolve(c) + } e.wg.Done() } }() @@ -300,7 +305,7 @@ func (e *engine) Update() error { e.dt = time.Since(e.lastTime) e.runes = ebiten.AppendInputChars(e.runes[:0]) - fmt.Println("runes:", e.runes) + //fmt.Println("runes:", e.runes) // Buffering the context for faster. // Providing the events to the objects. // Maybe should think of the better way, @@ -325,16 +330,39 @@ func (e *engine) Update() error { } func (e *engine) Resolve() { + eng := (*Engine)(e) + type resHold struct{ + Resolver Resolver + input chan *Context + } colliders := []Collider{} - resolvers := []Resolver{} + + resolvers := []resHold{} for _, object := range e.Objects.store { if object.IsCollidable() { colliders = append(colliders, object) } if object.IsResolvable() { - resolvers = append(resolvers, object) + resolvers = append(resolvers, resHold{ + object, + object.Input(), + }) } } + + for _, resolver := range resolvers { + cols := GetCollisions(resolver.Resolver, colliders) + if len(cols) > 0 { + c := &Context{ + typ: resolveContext, + Collisions: cols, + Engine: eng, + } + e.wg.Add(1) + resolver.input <- c + } + } + e.wg.Wait() } var ( diff --git a/rect.go b/rect.go index 4b70ea2..7badbc5 100644 --- a/rect.go +++ b/rect.go @@ -17,12 +17,15 @@ type Rectangle struct { // Return points of vertices of the rectangle. func (r Rectangle) Vertices() Vertices { - m := r.Matrix() + t := r.Transform + wh := V(r.Width, r.Height) + t.Around = t.Around.Scale(wh) + m := t.Matrix() p1 := V(0, 0).Apply(m) - p2 := V(1, 0).Apply(m) - p3 := V(1, 1).Apply(m) - p4 := V(0, 1).Apply(m) - return Points{p1, p2, p3, p4} + p2 := V(wh.X, 0).Apply(m) + p3 := V(wh.X, wh.Y).Apply(m) + p4 := V(0, wh.Y).Apply(m) + return Vertices{p1, p2, p3, p4} } func (r Rectangle) Edges() Edges { @@ -63,15 +66,6 @@ type DrawableRectangle struct { // Will be ignored if the Shader // field is not nil. Colority - - // Should be draw or not. - Visibility - Collidability -} - -// Check whether the drawable rectangle should be drawn. -func (r *DrawableRectangle) IsVisible() bool { - return r.Visible } func (r *DrawableRectangle) Draw(c *Context) []EVertex { diff --git a/sprite.go b/sprite.go index d0d8970..e6f159b 100644 --- a/sprite.go +++ b/sprite.go @@ -11,8 +11,6 @@ type Sprite struct { ShaderOptions Floating bool Visibility - Collidability - Resolvability } var ( @@ -25,7 +23,7 @@ func (s *Sprite) Draw(c *Context) []EVertex { return nil } - t := s.Rectangle().Transform + t := s.RectangleToDraw().Transform m := t.Matrix() if !s.Floating { m.Concat(c.Camera.RealMatrix()) @@ -49,10 +47,10 @@ func (s *Sprite) Draw(c *Context) []EVertex { return nil } -// Return the rectangle that contains the sprite. -func (s *Sprite) Rectangle() Rectangle { +// Return the rectangle that contains the sprite to draw. +func (s *Sprite) RectangleToDraw() Rectangle { if s.Images[0] == nil { - panic("trying to get rectangle for nil image pointer") + return Rectangle{} } w, h := s.Images[0].Size() @@ -65,9 +63,38 @@ func (s *Sprite) Rectangle() Rectangle { } } +// Return the rectangle that contains the sprite in the engine. +func (s *Sprite) Rectangle() Rectangle { + if s.Images[0] == nil { + return Rectangle{ + Transform: s.Transform, + } + } + + w, h := s.Images[0].Size() + t := s.Transform + + return Rectangle{ + Transform: t, + Width: Float(w), + Height: Float(h), + } +} + // Get triangles of the rectangle that contains the sprite // and has the same widght and height. func (s *Sprite) MakeTriangles() Triangles { return s.Rectangle().MakeTriangles() } +func (s *Sprite) Vertices() Vertices { + return s.Rectangle().Vertices() +} + +func (s *Sprite) Edges() Edges { + return s.Rectangle().Edges() +} + +func (s *Sprite) ContainedPoints(pts Points) Points { + return s.Rectangle().ContainedPoints(pts) +}