Experimenting with different collision resolutions.

This commit is contained in:
2025-11-28 16:48:32 -05:00
parent c8267a12a6
commit ab7bec94a8
2 changed files with 133 additions and 71 deletions

View File

@@ -17,7 +17,7 @@ import (
const (
GameWidth = 640
GameHeight = 360
GameParticleCount = 1000
GameParticleCount = 2000
GameGravity = 2
GameParticleRadius = 5
GameDamping = .7
@@ -36,6 +36,8 @@ type Game struct {
paused bool
renderquads bool
resolvecollisions bool
resolvers []func(particle *elements.Particle)
resolveridx int
}
func NewGame() *Game {
@@ -44,6 +46,7 @@ func NewGame() *Game {
paused: false,
renderquads: false,
resolvecollisions: false,
resolveridx: 0,
}
g.particlebox = &gamedata.Vector{
@@ -70,6 +73,9 @@ func NewGame() *Game {
},
}
g.resolvers = append(g.resolvers, g.ResolveCollisionsA)
g.resolvers = append(g.resolvers, g.ResolveCollisionsB)
//g.InitializeColliders()
g.InitializeParticles()
@@ -113,8 +119,12 @@ func (g *Game) RenderParticles(img *ebiten.Image) {
x0 := particle.Position.X - GameParticleRadius
y0 := particle.Position.Y - GameParticleRadius
//redness := float32(particle.Position.Y / g.particlebox.Y)
//blueness := 1 - redness
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(x0, y0)
//op.ColorScale.Scale(redness, 0, blueness, 1)
img.DrawImage(g.particlebuff, op)
//vector.FillCircle(img, float32(particle.Position.X), float32(particle.Position.Y), float32(particle.Radius), color.White, true)
@@ -178,17 +188,15 @@ func (g *Game) UpdateParticles() {
dt := GameDeltaTimeStep
/*
mx, my := ebiten.CursorPosition()
mpos := gamedata.Vector{X: float64(mx), Y: float64(my)}
maxdeflect := 40 * GameDeltaTimeStep * GameGravity
*/
for _, particle := range g.particles {
particle.Velocity.Y += GameGravity * dt
//if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
/*
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
delta := gamedata.Vector{
X: mpos.X - particle.Position.X,
@@ -215,13 +223,12 @@ func (g *Game) UpdateParticles() {
}
}
*/
particle.Position.X += particle.Velocity.X * dt
particle.Position.Y += particle.Velocity.Y * dt
if g.resolvecollisions {
g.ResolveCollisions(particle)
g.resolvers[g.resolveridx](particle)
}
g.BoundParticle(particle)
@@ -288,6 +295,17 @@ func (g *Game) ParseInputs() {
g.resolvecollisions = !g.resolvecollisions
}
if inpututil.IsKeyJustPressed(ebiten.KeyLeft) {
g.resolveridx = g.resolveridx - 1
if g.resolveridx < 0 {
g.resolveridx = len(g.resolvers) - 1
}
}
if inpututil.IsKeyJustPressed(ebiten.KeyRight) {
g.resolveridx = (g.resolveridx + 1) % len(g.resolvers)
}
}
func (g *Game) RebuildQuadtree() {
@@ -300,7 +318,7 @@ func (g *Game) RebuildQuadtree() {
}
}
func (g *Game) ResolveCollisions(particle *elements.Particle) {
func (g *Game) ResolveCollisionsA(particle *elements.Particle) {
//construct search quadrant from current particle
quadrant := quadtree.Quadrant{
Position: particle.Position,
@@ -349,3 +367,44 @@ func (g *Game) ResolveCollisions(particle *elements.Particle) {
}
}
}
func (g *Game) ResolveCollisionsB(particle *elements.Particle) {
//construct search quadrant from current particle
quadrant := quadtree.Quadrant{
Position: particle.Position,
Dimensions: particle.GetDimensions(),
}
//find list of possible maybe collisions, we inspect those in more detail
maybes := g.quadtree.FindAll(quadrant)
sqdist := float64(GameParticleRadius*GameParticleRadius) * 4
for _, p := range maybes {
if p == particle {
continue
}
pos := p.GetPosition()
delta := gamedata.Vector{
X: pos.X - particle.Position.X,
Y: pos.Y - particle.Position.Y,
}
dist2 := delta.X*delta.X + delta.Y*delta.Y
if dist2 < sqdist {
d := math.Sqrt(dist2)
overlap := GameParticleRadius*2 - d
theta := math.Atan2(delta.Y, delta.X)
pos.X += overlap * math.Cos(theta)
pos.Y += overlap * math.Sin(theta)
p.SetPosition(pos)
m := p.(*elements.Particle)
m.Velocity.X *= -1 * GameDamping
m.Velocity.Y *= -1 * GameDamping
}
}
}

View File

@@ -6,7 +6,7 @@ import (
)
const (
QuadtreeMaxColliders = 10
QuadtreeMaxColliders = 40
)
type Quadrant struct {
@@ -31,7 +31,9 @@ func (q *Quadtree) Insert(obj colliders.Collider) bool {
var result bool = false
//check that object meets containment criteria
if q.ContainsPoint(obj.GetPosition()) {
if !q.ContainsPoint(obj.GetPosition()) {
return result
}
//if we have children, we go deeper
if len(q.children) > 0 {
@@ -49,7 +51,7 @@ func (q *Quadtree) Insert(obj colliders.Collider) bool {
//otherwise we have to subdivide, reorganize, and add
result = q.SubdivideAndInsert(obj)
}
}
return result
}
@@ -67,7 +69,9 @@ func (q *Quadtree) ContainsPoint(p gamedata.Vector) bool {
func (q *Quadtree) Remove(obj colliders.Collider) bool {
var result bool = false
if q.ContainsPoint(obj.GetPosition()) {
if !q.ContainsPoint(obj.GetPosition()) {
return result
}
if len(q.colliders) > 0 {
//examine existing colliders
@@ -89,7 +93,6 @@ func (q *Quadtree) Remove(obj colliders.Collider) bool {
}
}
}
}
return result
}