feat: implemented the basic collider system.
This commit is contained in:
parent
f910d4f99b
commit
31940fa899
6 changed files with 128 additions and 34 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@ func NewRect() *Rect {
|
|||
}
|
||||
ret.Layer = RectL
|
||||
ret.Visible = true
|
||||
ret.Collidable = true
|
||||
ret.Width = 100
|
||||
ret.Height = 200
|
||||
|
||||
return ret
|
||||
}
|
||||
|
|
23
collider.go
23
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
|
||||
}
|
||||
|
|
38
engine.go
38
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 (
|
||||
|
|
22
rect.go
22
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 {
|
||||
|
|
39
sprite.go
39
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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue