mirror of
https://github.com/genxium/DelayNoMore
synced 2024-12-27 12:08:21 +00:00
157 lines
4.5 KiB
Go
157 lines
4.5 KiB
Go
|
package resolv
|
||
|
|
||
|
// Collision contains the results of an Object.Check() call, and represents a collision between an Object and cells that contain other Objects.
|
||
|
// The Objects array indicate the Objects collided with.
|
||
|
type Collision struct {
|
||
|
checkingObject *Object // The checking object
|
||
|
dx, dy float64 // The delta the checking object was moving on that caused this collision
|
||
|
Objects []*Object // Slice of objects that were collided with; sorted according to distance to calling Object.
|
||
|
Cells []*Cell // Slice of cells that were collided with; sorted according to distance to calling Object.
|
||
|
}
|
||
|
|
||
|
func NewCollision() *Collision {
|
||
|
return &Collision{
|
||
|
Objects: []*Object{},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// HasTags returns whether any objects within the Collision have all of the specified tags. This slice does not contain the Object that called Check().
|
||
|
func (cc *Collision) HasTags(tags ...string) bool {
|
||
|
|
||
|
for _, o := range cc.Objects {
|
||
|
|
||
|
if o == cc.checkingObject {
|
||
|
continue
|
||
|
}
|
||
|
if o.HasTags(tags...) {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// ObjectsByTags returns a slice of Objects from the cells reported by a Collision object by searching for Objects with a specific set of tags.
|
||
|
// This slice does not contain the Object that called Check().
|
||
|
func (cc *Collision) ObjectsByTags(tags ...string) []*Object {
|
||
|
|
||
|
objects := []*Object{}
|
||
|
|
||
|
for _, o := range cc.Objects {
|
||
|
|
||
|
if o == cc.checkingObject {
|
||
|
continue
|
||
|
}
|
||
|
if o.HasTags(tags...) {
|
||
|
objects = append(objects, o)
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return objects
|
||
|
|
||
|
}
|
||
|
|
||
|
// ContactWithObject returns the delta to move to come into contact with the specified Object.
|
||
|
func (cc *Collision) ContactWithObject(object *Object) Vector {
|
||
|
|
||
|
delta := Vector{0, 0}
|
||
|
|
||
|
if cc.dx < 0 {
|
||
|
delta[0] = object.X + object.W - cc.checkingObject.X
|
||
|
} else if cc.dx > 0 {
|
||
|
delta[0] = object.X - cc.checkingObject.W - cc.checkingObject.X
|
||
|
}
|
||
|
|
||
|
if cc.dy < 0 {
|
||
|
delta[1] = object.Y + object.H - cc.checkingObject.Y
|
||
|
} else if cc.dy > 0 {
|
||
|
delta[1] = object.Y - cc.checkingObject.H - cc.checkingObject.Y
|
||
|
}
|
||
|
|
||
|
return delta
|
||
|
|
||
|
}
|
||
|
|
||
|
// ContactWithCell returns the delta to move to come into contact with the specified Cell.
|
||
|
func (cc *Collision) ContactWithCell(cell *Cell) Vector {
|
||
|
|
||
|
delta := Vector{0, 0}
|
||
|
|
||
|
cx := float64(cell.X * cc.checkingObject.Space.CellWidth)
|
||
|
cy := float64(cell.Y * cc.checkingObject.Space.CellHeight)
|
||
|
|
||
|
if cc.dx < 0 {
|
||
|
delta[0] = cx + float64(cc.checkingObject.Space.CellWidth) - cc.checkingObject.X
|
||
|
} else if cc.dx > 0 {
|
||
|
delta[0] = cx - cc.checkingObject.W - cc.checkingObject.X
|
||
|
}
|
||
|
|
||
|
if cc.dy < 0 {
|
||
|
delta[1] = cy + float64(cc.checkingObject.Space.CellHeight) - cc.checkingObject.Y
|
||
|
} else if cc.dy > 0 {
|
||
|
delta[1] = cy - cc.checkingObject.H - cc.checkingObject.Y
|
||
|
}
|
||
|
|
||
|
return delta
|
||
|
|
||
|
}
|
||
|
|
||
|
// SlideAgainstCell returns how much distance the calling Object can slide to avoid a collision with the targetObject. This only works on vertical and horizontal axes (x and y directly),
|
||
|
// primarily for platformers / top-down games. avoidTags is a sequence of tags (as strings) to indicate when sliding is valid (i.e. if a Cell contains an Object that has the tag given in
|
||
|
// the avoidTags slice, then sliding CANNOT happen). If sliding is not able to be done for whatever reason, SlideAgainstCell returns nil.
|
||
|
func (cc *Collision) SlideAgainstCell(cell *Cell, avoidTags ...string) Vector {
|
||
|
|
||
|
sp := cc.checkingObject.Space
|
||
|
|
||
|
collidingCell := cc.Cells[0]
|
||
|
ccX, ccY := sp.SpaceToWorld(collidingCell.X, collidingCell.Y)
|
||
|
hX := float64(sp.CellWidth) / 2.0
|
||
|
hY := float64(sp.CellHeight) / 2.0
|
||
|
|
||
|
ccX += hX
|
||
|
ccY += hY
|
||
|
|
||
|
oX, oY := cc.checkingObject.Center()
|
||
|
|
||
|
diffX := oX - ccX
|
||
|
diffY := oY - ccY
|
||
|
|
||
|
left := sp.Cell(collidingCell.X-1, collidingCell.Y)
|
||
|
right := sp.Cell(collidingCell.X+1, collidingCell.Y)
|
||
|
up := sp.Cell(collidingCell.X, collidingCell.Y-1)
|
||
|
down := sp.Cell(collidingCell.X, collidingCell.Y+1)
|
||
|
|
||
|
slide := Vector{0, 0}
|
||
|
|
||
|
// Moving vertically
|
||
|
if cc.dy != 0 {
|
||
|
|
||
|
if diffX > 0 && (right == nil || !right.ContainsTags(avoidTags...)) {
|
||
|
// Slide right
|
||
|
slide[0] = ccX + hX - cc.checkingObject.X
|
||
|
} else if diffX < 0 && (left == nil || !left.ContainsTags(avoidTags...)) {
|
||
|
// Slide left
|
||
|
slide[0] = ccX - hX - (cc.checkingObject.X + cc.checkingObject.W)
|
||
|
} else {
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if cc.dx != 0 {
|
||
|
if diffY > 0 && (down == nil || !down.ContainsTags(avoidTags...)) {
|
||
|
// Slide down
|
||
|
slide[1] = ccY + hY - cc.checkingObject.Y
|
||
|
} else if diffY < 0 && (up == nil || !up.ContainsTags(avoidTags...)) {
|
||
|
// Slide up
|
||
|
slide[1] = ccY - hY - (cc.checkingObject.Y + cc.checkingObject.H)
|
||
|
} else {
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return slide
|
||
|
|
||
|
}
|