-
Notifications
You must be signed in to change notification settings - Fork 1
/
chain.go
103 lines (82 loc) · 2.47 KB
/
chain.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package main
import (
"github.com/hajimehoshi/ebiten/v2"
"github.com/jakecoffman/cp"
"github.com/jakecoffman/cpebiten"
"log"
)
const (
screenWidth = 600
screenHeight = 480
)
const (
chainCount = 8
linkCount = 10
)
func BreakableJointPostStepRemove(space *cp.Space, joint interface{}, _ interface{}) {
space.RemoveConstraint(joint.(*cp.Constraint))
}
func BreakableJointPostSolve(joint *cp.Constraint, space *cp.Space) {
dt := space.TimeStep()
// Convert the impulse to a force by dividing it by the timestep.
force := joint.Class.GetImpulse() / dt
maxForce := joint.MaxForce()
// If the force is almost as big as the joint's max force, break it.
if force > 0.9*maxForce {
space.AddPostStepCallback(BreakableJointPostStepRemove, joint, nil)
}
}
func NewGame() *cpebiten.Game {
space := cp.NewSpace()
space.Iterations = 30
space.SetGravity(cp.Vector{0, 100})
space.SleepTimeThreshold = 0.5
walls := []cp.Vector{
{0, 0}, {0, screenHeight},
{0, screenHeight}, {screenWidth, screenHeight},
{screenWidth, screenHeight}, {screenWidth, 0},
{screenWidth, 0}, {0, 0},
}
for i := 0; i < len(walls)-1; i += 2 {
cpebiten.AddWall(space, space.StaticBody, walls[i], walls[i+1], 0)
}
mass := 1.0
width := 20.0
height := 30.0
spacing := width * 0.3
var i, j float64
for i = 0; i < chainCount; i++ {
var prev *cp.Body
for j = 0; j < linkCount; j++ {
pos := cp.Vector{
X: screenWidth/2 + 40 * (i - (chainCount-1)/2.0),
Y: (j+0.5)*height + (j+1)*spacing,
}
shape := cpebiten.AddSegment(space, pos, mass, width, height)
breakingForce := 80000.0
var constraint *cp.Constraint
if prev == nil {
a, b := cp.Vector{0, -height / 2}, cp.Vector{pos.X, 0}
constraint = space.AddConstraint(cp.NewSlideJoint(shape.Body(), space.StaticBody, a, b, 0, spacing))
} else {
a, b := cp.Vector{0, - height / 2}, cp.Vector{0, height / 2}
constraint = space.AddConstraint(cp.NewSlideJoint(shape.Body(), prev, a, b, 0, spacing))
}
constraint.SetMaxForce(breakingForce)
constraint.PostSolve = BreakableJointPostSolve
constraint.SetCollideBodies(false)
prev = shape.Body()
}
}
radius := 15.0
circle := cpebiten.AddCircle(space, cp.Vector{screenWidth/2, screenHeight - 100}, 10, radius)
circle.Body().SetVelocity(0, -300)
return cpebiten.NewGame(space, 180)
}
func main() {
ebiten.SetWindowSize(screenWidth, screenHeight)
ebiten.SetWindowTitle("Contact Graph")
if err := ebiten.RunGame(NewGame()); err != nil {
log.Fatal(err)
}
}