Simplified resolv_tailored.

This commit is contained in:
genxium 2023-03-02 10:22:27 +08:00
parent 04d8013cbb
commit b9beee549f
10 changed files with 157 additions and 103 deletions

View File

@ -518,7 +518,7 @@
"array": [ "array": [
0, 0,
0, 0,
210.43877906529718, 210.4441731196186,
0, 0,
0, 0,
0, 0,

File diff suppressed because one or more lines are too long

View File

@ -7,7 +7,7 @@ import (
) )
const ( const (
MAX_FLOAT64 = 1.7e+308 MAX_FLOAT64 = resolv.MaxFloat64
MAX_INT32 = int32(999999999) MAX_INT32 = int32(999999999)
COLLISION_PLAYER_INDEX_PREFIX = (1 << 17) COLLISION_PLAYER_INDEX_PREFIX = (1 << 17)
COLLISION_BARRIER_INDEX_PREFIX = (1 << 16) COLLISION_BARRIER_INDEX_PREFIX = (1 << 16)

View File

@ -135,10 +135,10 @@ func (cc *Collision) SlideAgainstCell(cell *Cell, avoidTags ...string) Vector {
diffX := oX - ccX diffX := oX - ccX
diffY := oY - ccY diffY := oY - ccY
left := sp.Cell(collidingCell.X-1, collidingCell.Y) left := sp.GetCell(collidingCell.X-1, collidingCell.Y)
right := sp.Cell(collidingCell.X+1, collidingCell.Y) right := sp.GetCell(collidingCell.X+1, collidingCell.Y)
up := sp.Cell(collidingCell.X, collidingCell.Y-1) up := sp.GetCell(collidingCell.X, collidingCell.Y-1)
down := sp.Cell(collidingCell.X, collidingCell.Y+1) down := sp.GetCell(collidingCell.X, collidingCell.Y+1)
slide := Vector{0, 0} slide := Vector{0, 0}

View File

@ -1,9 +1,5 @@
package resolv package resolv
import (
"math"
)
// Object represents an object that can be spread across one or more Cells in a Space. An Object is essentially an AABB (Axis-Aligned Bounding Box) Rectangle. // Object represents an object that can be spread across one or more Cells in a Space. An Object is essentially an AABB (Axis-Aligned Bounding Box) Rectangle.
type Object struct { type Object struct {
Shape Shape // A shape for more specific collision-checking. Shape Shape // A shape for more specific collision-checking.
@ -93,7 +89,7 @@ func (obj *Object) Update() {
for x := cx; x <= ex; x++ { for x := cx; x <= ex; x++ {
c := obj.Space.Cell(x, y) c := obj.Space.GetCell(x, y)
if c != nil { if c != nil {
c.register(obj) c.register(obj)
@ -256,15 +252,15 @@ func (obj *Object) CheckAllWithHolder(dx, dy float64, cc *Collision) bool {
cc.checkingObject = obj cc.checkingObject = obj
if dx < 0 { if dx < 0 {
dx = math.Min(dx, -1) dx = Min(dx, -1)
} else if dx > 0 { } else if dx > 0 {
dx = math.Max(dx, 1) dx = Max(dx, 1)
} }
if dy < 0 { if dy < 0 {
dy = math.Min(dy, -1) dy = Min(dy, -1)
} else if dy > 0 { } else if dy > 0 {
dy = math.Max(dy, 1) dy = Max(dy, 1)
} }
cc.dx = dx cc.dx = dx
@ -279,7 +275,7 @@ func (obj *Object) CheckAllWithHolder(dx, dy float64, cc *Collision) bool {
for x := cx; x <= ex; x++ { for x := cx; x <= ex; x++ {
if c := obj.Space.Cell(x, y); c != nil { if c := obj.Space.GetCell(x, y); c != nil {
rb := c.Objects rb := c.Objects
for i := rb.StFrameId; i < rb.EdFrameId; i++ { for i := rb.StFrameId; i < rb.EdFrameId; i++ {

View File

@ -1,9 +1,10 @@
package resolv package resolv
const ( const (
RING_BUFF_CONSECUTIVE_SET = int32(0) // Declare type "int32" explicitly to prevent go2cs from transpiling them to "var"
RING_BUFF_NON_CONSECUTIVE_SET = int32(1) RING_BUFF_CONSECUTIVE_SET int32 = 0
RING_BUFF_FAILED_TO_SET = int32(2) RING_BUFF_NON_CONSECUTIVE_SET int32 = 1
RING_BUFF_FAILED_TO_SET int32 = 2
) )
type AnyObj interface{} type AnyObj interface{}

View File

@ -1,9 +1,5 @@
package resolv package resolv
import (
"math"
)
type Shape interface { type Shape interface {
// Intersection tests to see if a Shape intersects with the other given Shape. dx and dy are delta movement variables indicating // Intersection tests to see if a Shape intersects with the other given Shape. dx and dy are delta movement variables indicating
// movement to be applied before the intersection check (thereby allowing you to see if a Shape would collide with another if it // movement to be applied before the intersection check (thereby allowing you to see if a Shape would collide with another if it
@ -187,7 +183,7 @@ func (cp *ConvexPolygon) Bounds() (Vector, Vector) {
transformed := cp.Transformed() transformed := cp.Transformed()
topLeft := Vector{transformed[0][0], transformed[0][1]} topLeft := Vector{transformed[0][0], transformed[0][1]}
bottomRight := topLeft.Clone() bottomRight := Vector{transformed[0][0], transformed[0][1]}
for i := 0; i < len(transformed); i++ { for i := 0; i < len(transformed); i++ {
@ -224,8 +220,8 @@ func (cp *ConvexPolygon) SetPosition(x, y float64) {
// SetPositionVec allows you to set the position of the ConvexPolygon using a Vector. The offset of the vertices compared to the X and Y // SetPositionVec allows you to set the position of the ConvexPolygon using a Vector. The offset of the vertices compared to the X and Y
// position is relative to however you initially defined the polygon and added the vertices. // position is relative to however you initially defined the polygon and added the vertices.
func (cp *ConvexPolygon) SetPositionVec(vec Vector) { func (cp *ConvexPolygon) SetPositionVec(vec Vector) {
cp.X = vec.X() cp.X = vec.GetX()
cp.Y = vec.Y() cp.Y = vec.GetY()
} }
// Move translates the ConvexPolygon by the designated X and Y values. // Move translates the ConvexPolygon by the designated X and Y values.
@ -236,8 +232,8 @@ func (cp *ConvexPolygon) Move(x, y float64) {
// MoveVec translates the ConvexPolygon by the designated Vector. // MoveVec translates the ConvexPolygon by the designated Vector.
func (cp *ConvexPolygon) MoveVec(vec Vector) { func (cp *ConvexPolygon) MoveVec(vec Vector) {
cp.X += vec.X() cp.X += vec.GetX()
cp.Y += vec.Y() cp.Y += vec.GetY()
} }
// SATAxes returns the axes of the ConvexPolygon for SAT intersection testing. // SATAxes returns the axes of the ConvexPolygon for SAT intersection testing.
@ -403,22 +399,3 @@ func NewRectangle(x, y, w, h float64) *ConvexPolygon {
x, y+h, x, y+h,
) )
} }
type Projection struct {
Min, Max float64
}
// Overlapping returns whether a Projection is overlapping with the other, provided Projection. Credit to https://www.sevenson.com.au/programming/sat/
func (projection Projection) Overlapping(other Projection) bool {
return projection.Overlap(other) > 0
}
// Overlap returns the amount that a Projection is overlapping with the other, provided Projection. Credit to https://dyn4j.org/2010/01/sat/#sat-nointer
func (projection Projection) Overlap(other Projection) float64 {
return math.Min(projection.Max, other.Max) - math.Max(projection.Min, other.Min)
}
// IsInside returns whether the Projection is wholly inside of the other, provided Projection.
func (projection Projection) IsInside(other Projection) bool {
return projection.Min >= other.Min && projection.Max <= other.Max
}

View File

@ -0,0 +1,112 @@
package resolv
import "unsafe"
const (
uvnan = 0x7FF8000000000001
uvinf = 0x7FF0000000000000
uvneginf = 0xFFF0000000000000
uvone = 0x3FF0000000000000
mask = 0x7FF
shift = 64 - 11 - 1
bias = 1023
signMask = 1 << 63
fracMask = 1<<shift - 1
MaxFloat64 = 1.79e+308
magic32 = 0x5f3759df
magic64 = 0x5fe6eb50c7b537a9
)
func Max(a, b float64) float64 {
if a > b {
return a
} else {
return b
}
}
func Min(a, b float64) float64 {
if a < b {
return a
} else {
return b
}
}
func Floor(x float64) float64 {
if x == 0 || IsInf(x, 0) || IsNaN(x) {
return x
}
if x < 0 {
d, fract := Modf(-x)
if fract != 0.0 {
d = d + 1
}
return -d
}
d, _ := Modf(x)
return d
}
func Modf(f float64) (outval float64, frac float64) {
if f < 1 {
if f < 0 {
outval1, frac1 := Modf(-f)
return -outval1, -frac1
} else if f == 0 {
return f, f // Return -0, -0 when f == -0
}
return 0, f
}
x := Float64bits(f)
e := ((uint)(x>>shift))&mask - bias
// Keep the top 12+e bits, the integer part; clear the rest.
if e < 64-12 {
x &^= 1<<(64-12-e) - 1
}
outval = Float64frombits(x)
frac = f - outval
return
}
func Float32bits(f float32) uint32 { return *(*uint32)(unsafe.Pointer(&f)) }
func Float32frombits(b uint32) float32 { return *(*float32)(unsafe.Pointer(&b)) }
func Float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) }
func Float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) }
func NaN() float64 { return Float64frombits(uvnan) }
func IsNaN(f float64) (is bool) {
return f != f
}
func IsInf(f float64, sign int) bool {
return sign >= 0 && f > MaxFloat64 || sign <= 0 && f < -MaxFloat64
}
// FastInvSqrt reference https://medium.com/@adrien.za/fast-inverse-square-root-in-go-and-javascript-for-fun-6b891e74e5a8
func FastInvSqrt32(n float32) float32 {
if n < 0 {
return float32(NaN())
}
n2, th := n*0.5, float32(1.5)
b := Float32bits(n)
b = magic32 - (b >> 1)
f := Float32frombits(b)
f *= th - (n2 * f * f)
return f
}
func FastInvSqrt64(n float64) float64 {
if n < 0 {
return NaN()
}
n2, th := n*0.5, float64(1.5)
b := Float64bits(n)
b = magic64 - (b >> 1)
f := Float64frombits(b)
f *= th - (n2 * f * f)
return f
}

View File

@ -1,9 +1,5 @@
package resolv package resolv
import (
"math"
)
// Space represents a collision space. Internally, each Space contains a 2D array of Cells, with each Cell being the same size. Cells contain information on which // Space represents a collision space. Internally, each Space contains a 2D array of Cells, with each Cell being the same size. Cells contain information on which
// Objects occupy those spaces. // Objects occupy those spaces.
type Space struct { type Space struct {
@ -128,9 +124,7 @@ func (sp *Space) Resize(width, height int) {
} }
} }
// Cell returns the Cell at the given cellular / spatial (not world) X and Y position in the Space. If the X and Y position are func (sp *Space) GetCell(x, y int) *Cell {
// out of bounds, Cell() will return nil.
func (sp *Space) Cell(x, y int) *Cell {
if y >= 0 && y < len(sp.Cells) && x >= 0 && x < len(sp.Cells[y]) { if y >= 0 && y < len(sp.Cells) && x >= 0 && x < len(sp.Cells[y]) {
return sp.Cells[y][x] return sp.Cells[y][x]
@ -147,7 +141,7 @@ func (sp *Space) CheckCells(x, y, w, h int, tags ...string) *Object {
for iy := y; iy < y+h; iy++ { for iy := y; iy < y+h; iy++ {
cell := sp.Cell(ix, iy) cell := sp.GetCell(ix, iy)
if cell != nil { if cell != nil {
rb := cell.Objects rb := cell.Objects
@ -205,8 +199,8 @@ func (sp *Space) UnregisterAllObjects() {
// WorldToSpace converts from a world position (x, y) to a position in the Space (a grid-based position). // WorldToSpace converts from a world position (x, y) to a position in the Space (a grid-based position).
func (sp *Space) WorldToSpace(x, y float64) (int, int) { func (sp *Space) WorldToSpace(x, y float64) (int, int) {
// [WARNING] DON'T use "int(...)" syntax to convert float to int, it's not supported by go2cs! // [WARNING] DON'T use "int(...)" syntax to convert float to int, it's not supported by go2cs!
var fx int = (int)(math.Floor(x / float64(sp.CellWidth))) var fx int = (int)(Floor(x / float64(sp.CellWidth)))
var fy int = (int)(math.Floor(y / float64(sp.CellHeight))) var fy int = (int)(Floor(y / float64(sp.CellHeight)))
return fx, fy return fx, fy
} }
@ -233,8 +227,8 @@ func (sp *Space) Width() int {
func (sp *Space) CellsInLine(startX, startY, endX, endY int) []*Cell { func (sp *Space) CellsInLine(startX, startY, endX, endY int) []*Cell {
cells := []*Cell{} cells := []*Cell{}
cell := sp.Cell(startX, startY) cell := sp.GetCell(startX, startY)
endCell := sp.Cell(endX, endY) endCell := sp.GetCell(endX, endY)
if cell != nil && endCell != nil { if cell != nil && endCell != nil {
@ -263,7 +257,7 @@ func (sp *Space) CellsInLine(startX, startY, endX, endY int) []*Cell {
} }
cx, cy := sp.WorldToSpace(p[0], p[1]) cx, cy := sp.WorldToSpace(p[0], p[1])
c := sp.Cell(cx, cy) c := sp.GetCell(cx, cy)
if c != cell { if c != cell {
cell = c cell = c
} }

View File

@ -1,8 +1,6 @@
package resolv package resolv
import ( import "math"
"math"
)
// Vector is the definition of a row vector that contains scalars as // Vector is the definition of a row vector that contains scalars as
// 64 bit floats // 64 bit floats
@ -14,35 +12,13 @@ type Axis int
const ( const (
// the consts below are used to represent vector axis, they are useful // the consts below are used to represent vector axis, they are useful
// to lookup values within the vector. // to lookup values within the vector.
X Axis = iota X Axis = 0
Y Y Axis = 1
Z Z Axis = 2
) )
// Clone a vector
func Clone(v Vector) Vector {
return v.Clone()
}
// Clone a vector
func (v Vector) Clone() Vector {
clone := make(Vector, len(v))
copy(clone, v)
return clone
}
// Magnitude of a vector
func Magnitude(v Vector) float64 {
return v.Magnitude()
}
// Magnitude of a vector
func (v Vector) Magnitude() float64 {
return math.Sqrt(v.Magnitude2())
}
func (v Vector) Magnitude2() float64 { func (v Vector) Magnitude2() float64 {
var result float64 var result float64 = 0.
for _, scalar := range v { for _, scalar := range v {
result += scalar * scalar result += scalar * scalar
@ -51,21 +27,19 @@ func (v Vector) Magnitude2() float64 {
return result return result
} }
// Unit returns a direction vector with the length of one.
func Unit(v Vector) Vector {
return v.Clone().Unit()
}
// Unit returns a direction vector with the length of one. // Unit returns a direction vector with the length of one.
func (v Vector) Unit() Vector { func (v Vector) Unit() Vector {
l := v.Magnitude() l2 := v.Magnitude2()
if l2 < 1e-16 {
if l < 1e-8 {
return v return v
} }
l := math.Sqrt(l2)
//inv := FastInvSqrt64(l2) // "Fast Inverse Square Root" is arch dependent, it's by far non-trivial to use it in Golang as well as make it feasible in the transpiled JavaScript.
for i := 0; i < len(v); i++ { for i := 0; i < len(v); i++ {
v[i] = v[i] / l v[i] = v[i] / l
//v[i] = v[i] * inv
} }
return v return v
@ -73,7 +47,7 @@ func (v Vector) Unit() Vector {
// X is corresponding to doing a v[0] lookup, if index 0 does not exist yet, a // X is corresponding to doing a v[0] lookup, if index 0 does not exist yet, a
// 0 will be returned instead // 0 will be returned instead
func (v Vector) X() float64 { func (v Vector) GetX() float64 {
if len(v) < 1 { if len(v) < 1 {
return 0. return 0.
} }
@ -83,7 +57,7 @@ func (v Vector) X() float64 {
// Y is corresponding to doing a v[1] lookup, if index 1 does not exist yet, a // Y is corresponding to doing a v[1] lookup, if index 1 does not exist yet, a
// 0 will be returned instead // 0 will be returned instead
func (v Vector) Y() float64 { func (v Vector) GetY() float64 {
if len(v) < 2 { if len(v) < 2 {
return 0. return 0.
} }
@ -93,7 +67,7 @@ func (v Vector) Y() float64 {
// Z is corresponding to doing a v[2] lookup, if index 2 does not exist yet, a // Z is corresponding to doing a v[2] lookup, if index 2 does not exist yet, a
// 0 will be returned instead // 0 will be returned instead
func (v Vector) Z() float64 { func (v Vector) GetZ() float64 {
if len(v) < 3 { if len(v) < 3 {
return 0. return 0.
} }