package main import ( "fmt" "math/rand" "os" "runtime" "strconv" gui "github.com/gen2brain/raylib-go/raygui" rl "github.com/gen2brain/raylib-go/raylib" ) const ( screenWidth = 1280 screenHeight = 720 ballRadius = 12 squareSize = 128 debug = false ) var ( speed = 3 ballPos = rl.Vector2{X: 4096, Y: 4096} cameraPos = rl.Vector2{3500, 3800} ballColor = rl.Black squares = []rl.Vector2{{-200, 500}, {X: 640 - float32(squareSize), Y: 315}, {X: 640, Y: 315}, {X: 640 + float32(squareSize), Y: 315}, {X: 640, Y: 315 - float32(squareSize)}, {X: 640, Y: 315 - float32(squareSize)*2}} paints = []paint{} chatBoxText = "" inputText = "" loadedMap = "" ) func main() { userData := loadJson("account.json") checkUserDataValid(userData) ballColor = convertHex(userData["color"].(string)) rl.InitWindow(screenWidth, screenHeight, "balls offline") rl.InitAudioDevice() rl.SetTargetFPS(60) guessy := rl.LoadFont("./assets/font/guessy4.ttf") carlito := rl.LoadFont("./assets/font/carlito.ttf") notification := rl.LoadSound("./assets/sound/Notification.ogg") chatMessage := rl.LoadSound("./assets/sound/ChatMessage.ogg") gui.LoadStyle("./assets/bf.rgs") chatBoxText = userData["username"].(string) + " joined the game." rl.PlaySound(notification) rawMap, Error := os.ReadFile("./assets/maps/" + strconv.Itoa(rand.Intn(9)) + ".txt") loadedMap = string(rawMap) check(Error) for !rl.WindowShouldClose() { rl.BeginDrawing() rl.ClearBackground(rl.NewColor(128, 128, 128, 255)) drawMap(loadedMap) drawPaint() drawBall(ballPos, ballColor, rl.White) moveBall() usernamePosisiton := rl.Vector2Subtract(ballPos, rl.Vector2{ballRadius + 24, ballRadius + 40}) usernamePosisiton = rl.Vector2Subtract(usernamePosisiton, cameraPos) var spacing int = 21 drawTextShadow("Balls Offline", rl.Vector2{10, 5}, carlito) rl.DrawLine(10, 33, 120, 33, rl.White) drawTextShadow("Version: 0.0.0", rl.Vector2{10, float32(2*spacing + 1)}, carlito) drawTextShadow("Platform: "+runtime.GOOS, rl.Vector2{10, float32(3*spacing + 1)}, carlito) drawTextShadow("Client ID: none", rl.Vector2{10, float32(5*spacing + 1)}, carlito) x := strconv.FormatFloat(float64(ballPos.X), 'f', -1, 64) y := strconv.FormatFloat(float64(ballPos.Y), 'f', -1, 64) drawTextShadow("Position: "+x+" | "+y, rl.Vector2{10, float32(6*spacing + 1)}, carlito) drawTextShadow(userData["username"].(string), usernamePosisiton, guessy) if rl.IsKeyPressed(rl.KeyEnter) && inputText != "" { rl.PlaySound(chatMessage) chatBoxText = chatBoxText + "\n" + userData["username"].(string) + ": " + inputText inputText = "" } gui.TextBox(rl.NewRectangle(screenWidth-screenWidth/4, 0, screenWidth/4, 220), &chatBoxText, 100, false) gui.TextBox(rl.NewRectangle(screenWidth-screenWidth/4, 220, screenWidth/4, 20), &inputText, 100, true) rl.EndDrawing() } rl.CloseAudioDevice() rl.CloseWindow() } func drawPaint() { if debug { t := strconv.Itoa(len(paints)) rl.DrawText(t, 10, 10, 40, rl.Black) } for index, paintI := range paints { if len(paints) <= index { continue } if paintI.time > 1 { paints[index] = paint{time: paintI.time - 1, location: paintI.location} rl.DrawRectangleV(rl.Vector2Subtract(paintI.location, cameraPos), rl.Vector2{X: ballRadius - 2, Y: ballRadius - 2}, rl.NewColor(ballColor.R, ballColor.G, ballColor.R, uint8(paintI.time))) continue } paints = removePaint(paints, index) } } func drawSquares() { for index, element := range squares { debugLog(debug, fmt.Sprintln(index, element.X)) rl.DrawRectangleV(rl.Vector2{element.X - cameraPos.X, element.Y - cameraPos.Y}, rl.Vector2{X: float32(squareSize), Y: float32(squareSize)}, rl.LightGray) } } func draw() { paintedPaint := paint{255, ballPos} paints = append(paints, paintedPaint) } func moveBall() { if rl.IsKeyDown(rl.KeyLeftShift) { draw() } if rl.IsKeyDown(rl.KeyRight) && !checkCollision(rl.Vector2{X: ballPos.X + float32(speed), Y: ballPos.Y}) { ballPos.X = ballPos.X + float32(speed) cameraPos.X = cameraPos.X + float32(speed) } if rl.IsKeyDown(rl.KeyLeft) && !checkCollision(rl.Vector2{X: ballPos.X - float32(speed), Y: ballPos.Y}) { ballPos.X = ballPos.X - float32(speed) cameraPos.X = cameraPos.X - float32(speed) } if rl.IsKeyDown(rl.KeyUp) && !checkCollision(rl.Vector2{X: ballPos.X, Y: ballPos.Y - float32(speed)}) { ballPos.Y = ballPos.Y - float32(speed) cameraPos.Y = cameraPos.Y - float32(speed) } if rl.IsKeyDown(rl.KeyDown) && !checkCollision(rl.Vector2{X: ballPos.X, Y: ballPos.Y + float32(speed)}) { ballPos.Y = ballPos.Y + float32(speed) cameraPos.Y = cameraPos.Y + float32(speed) } } func drawBall(pos rl.Vector2, color, outline rl.Color) { rl.DrawCircleV(rl.Vector2Subtract(pos, cameraPos), ballRadius+1, outline) rl.DrawCircleV(rl.Vector2Subtract(pos, cameraPos), ballRadius, color) } func drawTextShadow(text string, textPos rl.Vector2, font rl.Font) { var textShadowPos rl.Vector2 = rl.Vector2{X: textPos.X + 2, Y: textPos.Y + 2} rl.DrawTextEx(font, text, textShadowPos, 20, 1, rl.Black) rl.DrawTextEx(font, text, textPos, 20, 1, rl.White) } func checkCollision(newPos rl.Vector2) bool { if debug { rl.DrawLineV(newPos, rl.Vector2{X: newPos.X, Y: screenWidth * 2}, rl.Green) rl.DrawLineV(newPos, rl.Vector2{X: newPos.X, Y: 0}, rl.Green) rl.DrawLineV(newPos, rl.Vector2{X: 0, Y: newPos.Y}, rl.Green) rl.DrawLineV(newPos, rl.Vector2{X: screenHeight * 2, Y: newPos.Y}, rl.Green) } for index, square := range squares { if debug { fmt.Println(index, square.X, rl.Vector2Distance(newPos, square)) rl.DrawLineV(newPos, square, rl.Purple) } if rl.CheckCollisionPointRec(newPos, rl.Rectangle{X: square.X, Y: square.Y, Width: float32(squareSize), Height: float32(squareSize)}) { if debug { rl.DrawText("colliding with obstacle", 10, 10, 40, rl.Black) } return true } } if newPos.X > float32(64*squareSize) { return true } if newPos.X < 0 { return true } if newPos.Y < 0 { return true } if newPos.Y > float32(64*squareSize) { return true } return false } type paint struct { time float32 location rl.Vector2 } func removePaint(slice []paint, index int) []paint { if len(slice) <= 2 { return make([]paint, 0) } return append(slice[:index], slice[index+1:]...) } func convertHex(hex string) rl.Color { hex1 := hex[0:2] hex2 := hex[2:4] hex3 := hex[4:6] decimal, err := strconv.ParseInt(hex1, 16, 64) checkLog(err) decimal2, err := strconv.ParseInt(hex2, 16, 64) checkLog(err) decimal3, err := strconv.ParseInt(hex3, 16, 64) checkLog(err) return rl.NewColor(uint8(decimal), uint8(decimal2), uint8(decimal3), 255) } func drawMap(mapRaw string) { var lines []string for i := 0; i < len(mapRaw); i += 64 { end := i + 64 if end > len(mapRaw) { end = len(mapRaw) } lines = append(lines, mapRaw[i:end]) } for y := range lines { for x := 0; x < len(lines[y]); x++ { fmt.Println(lines[0][0]) switch lines[y][x] { case 48: //air case 49: //path rl.DrawRectangleV(rl.Vector2{float32(x*squareSize) - cameraPos.X, float32(y*squareSize) - cameraPos.Y}, rl.Vector2{X: float32(squareSize), Y: float32(squareSize)}, rl.NewColor(133, 133, 133, 255)) case 50: //door rl.DrawRectangleV(rl.Vector2{float32(x*squareSize) - cameraPos.X, float32(y*squareSize) - cameraPos.Y}, rl.Vector2{X: float32(squareSize), Y: float32(squareSize)}, rl.NewColor(112, 122, 112, 255)) case 51: //glass rl.DrawRectangleV(rl.Vector2{float32(x*squareSize) - cameraPos.X, float32(y*squareSize) - cameraPos.Y}, rl.Vector2{X: float32(squareSize), Y: float32(squareSize)}, rl.NewColor(144, 144, 144, 255)) case 52: //wall rl.DrawRectangleV(rl.Vector2{float32(x*squareSize) - cameraPos.X, float32(y*squareSize) - cameraPos.Y}, rl.Vector2{X: float32(squareSize), Y: float32(squareSize)}, rl.NewColor(170, 170, 170, 255)) case 53: //liquid rl.DrawRectangleV(rl.Vector2{float32(x*squareSize) - cameraPos.X, float32(y*squareSize) - cameraPos.Y}, rl.Vector2{X: float32(squareSize), Y: float32(squareSize)}, rl.NewColor(205, 205, 205, 255)) } } } }