package main // veja: // The relationship between chaos, fractal and physics // https://www.youtube.com/watch?v=C5Jkgvw-Z6E import ( // "fmt" "fmt" "math" // "math/rand" rl "github.com/gen2brain/raylib-go/raylib" ) type magnet struct { pos rl.Vector2 color rl.Color force float32 radius float32 } type ball struct { pos rl.Vector2 originGrid rl.Vector2 radius float32 speed rl.Vector2 steps int } // parâmetros const windowWidth = 700 const windowHeight = 700 const gridDivision = 4 const verticalGrids = windowHeight/gridDivision const horizontalGrids = windowWidth/gridDivision const magnetsDistance float32 = 80 const magnetRadius = 10 const gravConst float32 = 50 const magnetsAngle = 30 const luminance = false const hideBalls = true const hideMagnets = false var startingBallSpeed = rl.Vector2{X: 0, Y: 0} // joga a bola em alguma diração // antes que ela comece a ser atraida pelos ímãs var cameraOffset = rl.Vector2{X: 0, Y: 0} func (ball *ball) update(magnets []magnet) (bool, rl.Color) { magnetsPull := rl.Vector2{} for _, magnet := range magnets { direction := rl.Vector2Normalize( rl.Vector2Subtract(ball.pos, magnet.pos), ) distance := rl.Vector2Distance(magnet.pos, ball.pos) distanceSquared := math.Pow(float64(distance), 2) force := gravConst / float32(distanceSquared) acceleration := rl.Vector2Scale(direction, -force) magnetsPull = rl.Vector2Add(magnetsPull, acceleration) } ball.speed = rl.Vector2Add(ball.speed, magnetsPull) ball.pos = rl.Vector2Add(ball.speed, ball.pos) // verificar se bola parou em cima de um ímã for _, magnet := range magnets { distance := rl.Vector2Distance(ball.pos, magnet.pos) insideMagnet := distance < magnet.radius /* + ball.radius */ // atRest := math.Abs(float64(rl.Vector2Length(ball.speed))) < 0.01 if insideMagnet /* && atRest */ { if luminance { magnet.color.A = uint8(ball.steps) } return true, magnet.color } } return false, rl.NewColor(0, 0, 0, 0) } // var colors = []rl.Color{ // rl.Red, rl.Green, rl.Blue, rl.Yellow, rl.NewColor(0, 255, 255, 255), // rl.Magenta, rl.White, // } func main() { rl.InitWindow( windowWidth, windowHeight, "magnets", ) defer rl.CloseWindow() // rl.SetTargetFPS(60) magnets := []magnet{ { color: rl.Red, radius: magnetRadius, // force: magnetForce, }, { color: rl.Gray, radius: magnetRadius, // force: magnetForce, }, { color: rl.White, radius: magnetRadius, // force: magnetForce, }, { color: rl.Yellow, radius: magnetRadius, // force: magnetForce, }, { color: rl.Magenta, radius: magnetRadius, // force: magnetForce, }, } // posiciona imas em volta de um circulo xCenter := float32(windowWidth / 2) + cameraOffset.X yCenter := float32(windowHeight / 2) + cameraOffset.Y for i := range magnets { angle := 2.0 * math.Pi * float64(i) / float64(len(magnets)) + magnetsAngle magnets[i].pos = rl.Vector2{ X: float32(math.Cos(angle)) * magnetsDistance + xCenter, Y: float32(math.Sin(angle)) * magnetsDistance + yCenter, } } grid := make([][]rl.Color, verticalGrids) for i := range grid { grid[i] = make([]rl.Color, horizontalGrids) for j := range grid[i] { grid[i][j] = rl.Black } } // ball := ball{ // pos: rl.Vector2{0, 0}, // originGrid: rl.Vector2{X: 0, Y: 0}, // } // gridSize := rl.Vector2{ X: float32(windowWidth / int32(verticalGrids)), Y: float32(windowHeight / int32(horizontalGrids)), } var fallingBall []*ball var fallingBallOrder []rl.Vector2 for y := range grid { for x := range grid[y] { fallingBallOrder = append(fallingBallOrder, rl.Vector2{ X: float32(x), Y: float32(y), }) } } // rand.Shuffle(len(fallingBallOrder), func(i, j int) { // fallingBallOrder[i], fallingBallOrder[j] = // fallingBallOrder[j], fallingBallOrder[i] // }) for _, randomGrid := range fallingBallOrder { x := randomGrid.X * gridSize.X + gridSize.X/2 y := randomGrid.Y * gridSize.Y + gridSize.Y/2 fallingBall = append(fallingBall, &ball{ pos: rl.Vector2{X: x, Y: y}, speed: startingBallSpeed, radius: magnetRadius/2, originGrid: randomGrid, }) } for !rl.WindowShouldClose() { rl.BeginDrawing() rl.ClearBackground(rl.Black) for y := range grid { for x := range grid[y] { pos := rl.Vector2{ X: gridSize.X * float32(x), Y: gridSize.Y * float32(y), } rl.DrawRectangleV(pos, gridSize, grid[y][x]) } } if !hideMagnets { for i := range magnets { rl.DrawCircleV(magnets[i].pos, magnetRadius+2, rl.Black) rl.DrawCircleV(magnets[i].pos, magnetRadius, magnets[i].color) } } if len(fallingBall) == 0 { rl.EndDrawing() continue } for i := 0; i < len(fallingBall); i++ { ball := fallingBall[i] if !hideBalls { // rl.DrawCircleV( // ball.pos, ball.radius/2+1, rl.Black, // ) // rl.DrawCircleV( // ball.pos, ball.radius/2, // rl.NewColor(100, 100, 100, 255), // ) // bolas são difíceis de se calcular =/ rl.DrawRectangleV( rl.Vector2{X: ball.pos.X-1, Y: ball.pos.Y-1 }, rl.Vector2{X: ball.radius+1, Y: ball.radius+1}, rl.Black, ) rl.DrawRectangleV( ball.pos, rl.Vector2{X: ball.radius, Y: ball.radius}, rl.NewColor(100, 100, 100, 255), ) } if hit, color := ball.update(magnets); hit { x := ball.originGrid.X y := ball.originGrid.Y grid[int(y)][int(x)] = color // remover bola fallingBall[i] = fallingBall[len(fallingBall)-1] fallingBall = fallingBall[:len(fallingBall)-1] } ball.steps += 1 } // fmt.Println("foo") rl.EndDrawing() } fmt.Println("hello world") }