package main // veja: // The relationship between chaos, fractal and physics // https://www.youtube.com/watch?v=C5Jkgvw-Z6E import ( // "fmt" "fmt" "math" "math/rand" "strconv" // "math/rand" rl "github.com/gen2brain/raylib-go/raylib" ) type quadnode struct { topleft, bottomright rl.Vector2 magnet *magnet parent *quadnode nodes []*quadnode } func newQuadTree() *quadnode { return &quadnode{ topleft: rl.NewVector2(0, 0), bottomright: rl.NewVector2(windowWidth, windowHeight), nodes: nil, } } func (q *quadnode) subdivide() { halfX := q.bottomright.X/2 halfY := q.bottomright.X/2 q.nodes = []*quadnode{ { topleft: q.topleft, bottomright: rl.Vector2{X: halfX, Y: halfY}, parent: q, }, { topleft: rl.Vector2{X: halfX, Y: q.topleft.Y}, bottomright: rl.Vector2{X: q.bottomright.X, Y: halfY}, parent: q, }, { topleft: rl.Vector2{X: q.topleft.X, Y: halfY}, bottomright: rl.Vector2{X: halfX, Y: q.bottomright.Y}, parent: q, }, { topleft: rl.Vector2{X: halfX, Y: halfY}, bottomright: q.bottomright, parent: q, }, } } func (q *quadnode) drawBoundaries() { if q.nodes == nil { return } for _, node := range q.nodes { node.drawBoundaries() size := rl.Vector2Subtract(node.bottomright, node.topleft) rl.DrawRectangleLines( int32(node.topleft.X), int32(node.topleft.Y), int32(size.X), int32(size.Y), rl.Green, ) } } type magnet struct { pos rl.Vector2 speed rl.Vector2 color rl.Color mass float32 radius float32 } // type ball struct { // pos rl.Vector2 // originGrid rl.Vector2 // radius float32 // speed rl.Vector2 // steps int // } // parâmetros const initalMagnetCount = 10 const windowWidth = 700 const windowHeight = 700 const magnetRadius = 5 const gravConst float32 = 10 func tick(magnets []*magnet) { for _, a := range magnets { for _, b := range magnets { if a == b { continue } // não creio que isso esteja certo porem isso quaqueja que nem um pato direction := rl.Vector2Normalize(rl.Vector2Subtract(a.pos, b.pos)) distance := rl.Vector2Distance(a.pos, b.pos) distanceSquared := math.Pow(float64(distance), 2) force := gravConst / float32(distanceSquared) acceleration := rl.Vector2Scale(direction, force) if distance < magnetRadius*2 { continue } // f = m * a forceA := rl.Vector2Scale(acceleration, a.mass) forceB := rl.Vector2Scale(acceleration, b.mass) a.speed = rl.Vector2Add(a.speed, rl.Vector2Negate(forceB)) b.speed = rl.Vector2Add(b.speed, forceA) } } for _, magnet := range magnets { magnet.pos = rl.Vector2Add(magnet.pos, magnet.speed) } } func (m *magnet) update(magnets []*magnet) { magnetsPull := rl.Vector2{} for _, magnet := range magnets { if m == magnet { continue } direction := rl.Vector2Normalize(rl.Vector2Subtract(m.pos, magnet.pos)) distance := rl.Vector2Distance(magnet.pos, m.pos) if (distance < magnetRadius*2 + 10) { direction = rl.Vector2Negate(direction) // continue } distanceSquared := math.Pow(float64(distance), 2) force := gravConst / float32(distanceSquared) acceleration := rl.Vector2Scale(direction, -force) magnetsPull = rl.Vector2Add(magnetsPull, acceleration) } m.speed = rl.Vector2Add(m.speed, magnetsPull) newPos := rl.Vector2Add(m.speed, m.pos) // x, y := insideArea(newPos) // if !x { newPos.X = -newPos.X; m.speed.X = 0 } // if !y { newPos.Y = -newPos.Y; m.speed.Y = 0 } m.pos = newPos } func newMagnet(x, y, mass float32) *magnet { newMagnet := magnet{ pos: rl.Vector2{X: x, Y: y}, color: rl.NewColor( uint8(rand.Int()), uint8(rand.Int()), uint8(rand.Int()), 255, ), mass: mass, radius: mass, } return &newMagnet } func randomMagnets(n int) []*magnet { var magnets []*magnet for i := 0; i < n; i++ { x := float32(rand.Intn(windowWidth - 100) + 50) y := float32(rand.Intn(windowHeight - 100) + 50) magnets = append(magnets, newMagnet(x, y, 1)) } return magnets } func main() { rl.InitWindow( windowWidth, windowHeight, "barnes hut", ) defer rl.CloseWindow() rl.SetTargetFPS(60) magnets := randomMagnets(initalMagnetCount) quadtree := newQuadTree() quadtree.subdivide() pause := true for !rl.WindowShouldClose() { rl.BeginDrawing() rl.ClearBackground(rl.Black) rl.DrawFPS(0, 0) rl.DrawText(strconv.Itoa(len(magnets)), 0, 20, 20, rl.White) if pause { rl.DrawText("pausado (E)", 0, 40, 20, rl.White) } { if rl.IsKeyPressed(rl.KeyR) { magnets = randomMagnets(initalMagnetCount) } if rl.IsKeyPressed(rl.KeyW) { magnets = append(magnets, randomMagnets(100)...) } if rl.IsKeyPressed(rl.KeyE) { pause = !pause } if rl.IsKeyPressed(rl.KeySpace) { mouse := rl.GetMousePosition() magnets = append(magnets, newMagnet(mouse.X, mouse.Y, 50)) } } if !pause { tick(magnets) } quadtree.drawBoundaries() for _, magnet := range magnets { rl.DrawCircleV(magnet.pos, magnet.radius+1, rl.White) rl.DrawCircleV(magnet.pos, magnet.radius, magnet.color) } rl.EndDrawing() } fmt.Println("hello world") }