func (obj *Object) Overlaps(other *Object) bool {
	return other.X <= obj.X+obj.W && other.X+other.W >= obj.X && other.Y <= obj.Y+obj.H && other.Y+other.H >= obj.Y
}
Overlaps returns if an Object overlaps another Object.
package resolv
import (
	"math"
	"sort"
	"github.com/kvartborg/vector"
)
type Object struct {
	Shape         Shape             
	Space         *Space            
	X, Y, W, H    float64           
	TouchingCells []*Cell           
	Data          interface{}       
	ignoreList    map[*Object]bool  
	tags          []string          
}
func NewObject(x, y, w, h float64, tags ...string) *Object {
	o := &Object{
		X:          x,
		Y:          y,
		W:          w,
		H:          h,
		tags:       []string{},
		ignoreList: map[*Object]bool{},
	}
	if len(tags) > 0 {
		o.AddTags(tags...)
	}
	return o
}
func (obj *Object) Clone() *Object {
	newObj := NewObject(obj.X, obj.Y, obj.W, obj.H, obj.Tags()...)
	newObj.Data = obj.Data
	if obj.Shape != nil {
		newObj.SetShape(obj.Shape.Clone())
	}
	for k := range obj.ignoreList {
		newObj.AddToIgnoreList(k)
	}
	return newObj
}
func (obj *Object) Update() {
	if obj.Space != nil {
		space := obj.Space
		obj.Space.Remove(obj)
		obj.Space = space
		cx, cy, ex, ey := obj.BoundsToSpace(0, 0)
		for y := cy; y <= ey; y++ {
			for x := cx; x <= ex; x++ {
				c := obj.Space.Cell(x, y)
				if c != nil {
					c.register(obj)
					obj.TouchingCells = append(obj.TouchingCells, c)
				}
			}
		}
	}
	if obj.Shape != nil {
		obj.Shape.SetPosition(obj.X, obj.Y)
	}
}
func (obj *Object) AddTags(tags ...string) {
	obj.tags = append(obj.tags, tags...)
}
func (obj *Object) RemoveTags(tags ...string) {
	for _, tag := range tags {
		for i, t := range obj.tags {
			if t == tag {
				obj.tags = append(obj.tags[:i], obj.tags[i+1:]...)
				break
			}
		}
	}
}
func (obj *Object) HasTags(tags ...string) bool {
	for _, tag := range tags {
		for _, t := range obj.tags {
			if t == tag {
				return true
			}
		}
	}
	return false
}
func (obj *Object) Tags() []string {
	return append([]string{}, obj.tags...)
}
func (obj *Object) SetShape(shape Shape) {
	if obj.Shape != shape {
		obj.Shape = shape
		obj.Update()
	}
}
func (obj *Object) BoundsToSpace(dx, dy float64) (int, int, int, int) {
	cx, cy := obj.Space.WorldToSpace(obj.X+dx, obj.Y+dy)
	ex, ey := obj.Space.WorldToSpace(obj.X+obj.W+dx-1, obj.Y+obj.H+dy-1)
	return cx, cy, ex, ey
}
func (obj *Object) SharesCells(other *Object) bool {
	for _, cell := range obj.TouchingCells {
		if cell.Contains(other) {
			return true
		}
	}
	return false
}
func (obj *Object) SharesCellsTags(tags ...string) bool {
	for _, cell := range obj.TouchingCells {
		if cell.ContainsTags(tags...) {
			return true
		}
	}
	return false
}
func (obj *Object) Center() (float64, float64) {
	return obj.X + (obj.W / 2.0), obj.Y + (obj.H / 2.0)
}
func (obj *Object) SetCenter(x, y float64) {
	obj.X = x - (obj.W / 2)
	obj.Y = y - (obj.H / 2)
}
func (obj *Object) CellPosition() (int, int) {
	return obj.Space.WorldToSpace(obj.Center())
}
func (obj *Object) SetRight(x float64) {
	obj.X = x - obj.W
}
func (obj *Object) SetBottom(y float64) {
	obj.Y = y - obj.H
}
func (obj *Object) Bottom() float64 {
	return obj.Y + obj.H
}
func (obj *Object) Right() float64 {
	return obj.X + obj.W
}
func (obj *Object) SetBounds(topLeft, bottomRight vector.Vector) {
	obj.X = topLeft[0]
	obj.Y = topLeft[1]
	obj.W = bottomRight[0] - obj.X
	obj.H = bottomRight[1] - obj.Y
}
func (obj *Object) Check(dx, dy float64, tags ...string) *Collision {
	if obj.Space == nil {
		return nil
	}
	cc := NewCollision()
	cc.checkingObject = obj
	if dx < 0 {
		dx = math.Min(dx, -1)
	} else if dx > 0 {
		dx = math.Max(dx, 1)
	}
	if dy < 0 {
		dy = math.Min(dy, -1)
	} else if dy > 0 {
		dy = math.Max(dy, 1)
	}
	cc.dx = dx
	cc.dy = dy
	cx, cy, ex, ey := obj.BoundsToSpace(dx, dy)
	objectsAdded := map[*Object]bool{}
	cellsAdded := map[*Cell]bool{}
	for y := cy; y <= ey; y++ {
		for x := cx; x <= ex; x++ {
			if c := obj.Space.Cell(x, y); c != nil {
				for _, o := range c.Objects {
					if ignored := obj.ignoreList[o]; o == obj || ignored {
						continue
					}
					if _, added := objectsAdded[o]; (len(tags) == 0 || o.HasTags(tags...)) && !added {
						cc.Objects = append(cc.Objects, o)
						objectsAdded[o] = true
						if _, added := cellsAdded[c]; !added {
							cc.Cells = append(cc.Cells, c)
							cellsAdded[c] = true
						}
						continue
					}
				}
			}
		}
	}
	if len(cc.Objects) == 0 {
		return nil
	}
	ox, oy := cc.checkingObject.Center()
	oc := vector.Vector{ox, oy}
	sort.Slice(cc.Objects, func(i, j int) bool {
		ix, iy := cc.Objects[i].Center()
		jx, jy := cc.Objects[j].Center()
		return vector.Vector{ix, iy}.Sub(oc).Magnitude() < vector.Vector{jx, jy}.Sub(oc).Magnitude()
	})
	cw := cc.checkingObject.Space.CellWidth
	ch := cc.checkingObject.Space.CellHeight
	sort.Slice(cc.Cells, func(i, j int) bool {
		return vector.Vector{float64(cc.Cells[i].X*cw + (cw / 2)), float64(cc.Cells[i].Y*ch + (ch / 2))}.Sub(oc).Magnitude() <
			vector.Vector{float64(cc.Cells[j].X*cw + (cw / 2)), float64(cc.Cells[j].Y*ch + (ch / 2))}.Sub(oc).Magnitude()
	})
	return cc
}