feat: implemented the basic collider system.

This commit is contained in:
Andrey Parhomenko 2024-01-16 04:11:42 +03:00
parent f910d4f99b
commit 31940fa899
6 changed files with 128 additions and 34 deletions

View file

@ -2,7 +2,7 @@ package main
import ( import (
//"math/rand" //"math/rand"
//"fmt" "fmt"
"time" "time"
) )
@ -28,12 +28,24 @@ func NewPlayer() *Player {
ret.Visible = true ret.Visible = true
ret.Layer = PlayerL ret.Layer = PlayerL
ret.Collidable = true
ret.Resolvable = true
return ret return ret
} }
func (p *Player) Start(c *Context) { 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) { func (p *Player) Update(c *Context) {
if p.Spawned { if p.Spawned {
return return
@ -58,7 +70,7 @@ func (p *Player) Update(c *Context) {
case gg.KeyArrowRight: case gg.KeyArrowRight:
cam.Position.X += p.MoveSpeed * dt cam.Position.X += p.MoveSpeed * dt
case gg.KeyW: case gg.KeyW:
p.Position.Y += p.MoveSpeed * dt p.Position.Y -= p.MoveSpeed * dt*10
walking = true walking = true
p.Animate(Walk) p.Animate(Walk)
case gg.KeyA: case gg.KeyA:
@ -140,5 +152,26 @@ func (p *Player) Update(c *Context) {
ec.Offset.Y * dt * p.ScaleSpeed * 40, 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
}
}
}
} }

View file

@ -17,6 +17,9 @@ func NewRect() *Rect {
} }
ret.Layer = RectL ret.Layer = RectL
ret.Visible = true ret.Visible = true
ret.Collidable = true
ret.Width = 100
ret.Height = 200
return ret return ret
} }

View file

@ -12,14 +12,14 @@ package gg
type CollisionType int type CollisionType int
const ( const (
CollisionTypePhys CollisionType = iota PhysCollision CollisionType = iota
CollisionTypeTrigger TriggerCollision
) )
// The structure contains collision information. // The structure contains collision information.
type Collision struct { type Collision struct {
Type CollisionType Type CollisionType
What, With Objecter What, With Collider
// Points of Self contained in // Points of Self contained in
Points Points Points Points
Crosses []LineCross Crosses []LineCross
@ -28,19 +28,21 @@ type Collision struct {
// Implementing the interface lets the engine // Implementing the interface lets the engine
// to determine if the object collides with anything. // 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 { type Collider interface {
// Checks whether the object is collidable // Checks whether the object is collidable
CollisionType() CollisionType
IsCollidable() bool IsCollidable() bool
Verticer Verticer
Edger Edger
PointContainer PointContainer
} }
type Collidability struct { type Collidability struct {
Type CollisionType
Collidable bool Collidable bool
} }
func (c Collidability) CollisionType() CollisionType {
return c.Type
}
func (c Collidability) IsCollidable() bool { func (c Collidability) IsCollidable() bool {
return c.Collidable return c.Collidable
} }
@ -75,6 +77,9 @@ func Collide(c1, c2 Collider) (Collision, bool) {
crosses, doCross := es1.LineCrossWith(es2) crosses, doCross := es1.LineCrossWith(es2)
pts := c2.ContainedPoints(vertices) pts := c2.ContainedPoints(vertices)
return Collision{ return Collision{
Type: c2.CollisionType(),
What: c1,
With: c2,
Points: pts, Points: pts,
Crosses: crosses, Crosses: crosses,
}, len(pts) != 0 || doCross }, len(pts) != 0 || doCross
@ -83,9 +88,13 @@ func Collide(c1, c2 Collider) (Collision, bool) {
func GetCollisions(c Collider, cs []Collider) []Collision { func GetCollisions(c Collider, cs []Collider) []Collision {
ret := []Collision{} ret := []Collision{}
for _, ic := range cs { for _, ic := range cs {
if !ic.IsCollidable() || ic == c { if ic == c {
continue continue
} }
col, has := Collide(c, ic)
if has {
ret = append(ret, col)
}
} }
return ret return ret
} }

View file

@ -4,7 +4,7 @@ import (
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil" "github.com/hajimehoshi/ebiten/v2/inpututil"
"vultras.su/core/gods/maps" "vultras.su/core/gods/maps"
"fmt" //"fmt"
"time" "time"
"slices" "slices"
"sync" "sync"
@ -164,7 +164,12 @@ func (e *Engine) Spawn(b Objecter) error {
obj.input = make(chan *Context) obj.input = make(chan *Context)
go func() { go func() {
for c := range obj.input { for c := range obj.input {
b.Update(c) switch c.typ{
case updateContext :
b.Update(c)
case resolveContext :
b.Resolve(c)
}
e.wg.Done() e.wg.Done()
} }
}() }()
@ -300,7 +305,7 @@ func (e *engine) Update() error {
e.dt = time.Since(e.lastTime) e.dt = time.Since(e.lastTime)
e.runes = ebiten.AppendInputChars(e.runes[:0]) e.runes = ebiten.AppendInputChars(e.runes[:0])
fmt.Println("runes:", e.runes) //fmt.Println("runes:", e.runes)
// Buffering the context for faster. // Buffering the context for faster.
// Providing the events to the objects. // Providing the events to the objects.
// Maybe should think of the better way, // Maybe should think of the better way,
@ -325,16 +330,39 @@ func (e *engine) Update() error {
} }
func (e *engine) Resolve() { func (e *engine) Resolve() {
eng := (*Engine)(e)
type resHold struct{
Resolver Resolver
input chan *Context
}
colliders := []Collider{} colliders := []Collider{}
resolvers := []Resolver{}
resolvers := []resHold{}
for _, object := range e.Objects.store { for _, object := range e.Objects.store {
if object.IsCollidable() { if object.IsCollidable() {
colliders = append(colliders, object) colliders = append(colliders, object)
} }
if object.IsResolvable() { 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 ( var (

22
rect.go
View file

@ -17,12 +17,15 @@ type Rectangle struct {
// Return points of vertices of the rectangle. // Return points of vertices of the rectangle.
func (r Rectangle) Vertices() Vertices { 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) p1 := V(0, 0).Apply(m)
p2 := V(1, 0).Apply(m) p2 := V(wh.X, 0).Apply(m)
p3 := V(1, 1).Apply(m) p3 := V(wh.X, wh.Y).Apply(m)
p4 := V(0, 1).Apply(m) p4 := V(0, wh.Y).Apply(m)
return Points{p1, p2, p3, p4} return Vertices{p1, p2, p3, p4}
} }
func (r Rectangle) Edges() Edges { func (r Rectangle) Edges() Edges {
@ -63,15 +66,6 @@ type DrawableRectangle struct {
// Will be ignored if the Shader // Will be ignored if the Shader
// field is not nil. // field is not nil.
Colority 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 { func (r *DrawableRectangle) Draw(c *Context) []EVertex {

View file

@ -11,8 +11,6 @@ type Sprite struct {
ShaderOptions ShaderOptions
Floating bool Floating bool
Visibility Visibility
Collidability
Resolvability
} }
var ( var (
@ -25,7 +23,7 @@ func (s *Sprite) Draw(c *Context) []EVertex {
return nil return nil
} }
t := s.Rectangle().Transform t := s.RectangleToDraw().Transform
m := t.Matrix() m := t.Matrix()
if !s.Floating { if !s.Floating {
m.Concat(c.Camera.RealMatrix()) m.Concat(c.Camera.RealMatrix())
@ -49,10 +47,10 @@ func (s *Sprite) Draw(c *Context) []EVertex {
return nil return nil
} }
// Return the rectangle that contains the sprite. // Return the rectangle that contains the sprite to draw.
func (s *Sprite) Rectangle() Rectangle { func (s *Sprite) RectangleToDraw() Rectangle {
if s.Images[0] == nil { if s.Images[0] == nil {
panic("trying to get rectangle for nil image pointer") return Rectangle{}
} }
w, h := s.Images[0].Size() 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 // 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() Triangles {
return s.Rectangle().MakeTriangles() 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)
}