├── 2D_Advanced ├── menus_windows │ ├── README.md │ └── main.go ├── moving_spike_block │ ├── README.md │ ├── main.go │ └── tiles.png ├── tile_editor │ ├── README.md │ ├── main.go │ └── tiles.png └── tiled_dungeon_map_with_player │ ├── README.md │ ├── imgs.png │ └── main.go ├── 2D_Beginner ├── README.md ├── animated_character │ ├── README.md │ ├── anim.png │ └── main.go ├── exploding_blocks │ ├── README.md │ └── main.go ├── pixel_noise │ ├── README.md │ ├── gopher.png │ └── main.go ├── random_color_grid │ ├── README.md │ └── main.go ├── rec_collisions │ ├── README.md │ └── main.go ├── room_tiles │ ├── README.md │ ├── main.go │ └── tiles.png ├── stars_background │ ├── README.md │ └── main.go ├── text_cntr_scroll │ ├── README.md │ └── main.go └── vector2_collisions │ ├── README.md │ └── main.go ├── 2D_Intermediate ├── README.md ├── animated_logo │ ├── README.md │ ├── img │ │ ├── gologo.png │ │ └── raylib_logo │ │ │ ├── 00.png │ │ │ ├── 01.png │ │ │ ├── 02.png │ │ │ ├── 03.png │ │ │ ├── 04.png │ │ │ ├── 05.png │ │ │ ├── 06.png │ │ │ ├── 07.png │ │ │ ├── 08.png │ │ │ ├── 09.png │ │ │ ├── 10.png │ │ │ ├── 11.png │ │ │ ├── 12.png │ │ │ ├── 13.png │ │ │ ├── 14.png │ │ │ ├── 15.png │ │ │ ├── 16.png │ │ │ ├── 17.png │ │ │ ├── 18.png │ │ │ ├── 19.png │ │ │ ├── 20.png │ │ │ ├── 21.png │ │ │ ├── 22.png │ │ │ ├── 23.png │ │ │ ├── 24.png │ │ │ ├── 25.png │ │ │ ├── 26.png │ │ │ ├── 27.png │ │ │ ├── 28.png │ │ │ ├── 29.png │ │ │ ├── 30.png │ │ │ ├── 31.png │ │ │ ├── 32.png │ │ │ ├── 33.png │ │ │ ├── 34.png │ │ │ ├── 35.png │ │ │ ├── 36.png │ │ │ ├── 37.png │ │ │ ├── 38.png │ │ │ ├── 39.png │ │ │ ├── 40.png │ │ │ ├── 41.png │ │ │ ├── 42.png │ │ │ ├── 43.png │ │ │ ├── 44.png │ │ │ ├── 45.png │ │ │ ├── 46.png │ │ │ ├── 47.png │ │ │ ├── 48.png │ │ │ ├── 49.png │ │ │ ├── 50.png │ │ │ ├── 51.png │ │ │ ├── 52.png │ │ │ ├── 53.png │ │ │ ├── 54.png │ │ │ ├── 55.png │ │ │ └── 56.png │ └── main.go ├── candlelight │ ├── README.md │ ├── img.png │ └── main.go ├── chain_lightning │ ├── README.md │ └── main.go ├── motion_blur_scanlines │ ├── README.md │ ├── imgs.png │ └── main.go ├── move_to_point │ ├── README.md │ └── main.go ├── move_to_point_collisions │ ├── README.md │ └── main.go ├── moving_triangles │ ├── README.md │ └── main.go ├── orbiting │ ├── README.md │ └── main.go ├── player_bullets │ ├── README.md │ └── player_bullets.go ├── simple_dungeon_map │ ├── README.md │ └── main.go └── snow │ ├── README.md │ ├── imgs.png │ └── main.go ├── LICENSE └── README.md /2D_Advanced/menus_windows/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - MENUS & WINDOWS 3 | 4 | Demonstrates simple top/bottom, right/left sidebar, center and pop-up menu/windows. The colors can be changed and the menu positions can be changed by clicking in the relevant boxes of the sidebar window and the top/bottom menu/window. The center window can be moved by left mouse clicking and holding and the camera zoom and colors can be changed in the sidebar item list. View more at [unklnik.com](https://unklnik.com/posts/2d-menu-windows/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/32af1653-9429-43a3-a039-ebc368050b8f 7 | -------------------------------------------------------------------------------- /2D_Advanced/menus_windows/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math" 5 | "math/rand" 6 | 7 | rl "github.com/gen2brain/raylib-go/raylib" 8 | ) 9 | 10 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 11 | 12 | https://github.com/unklnik/raylib-go-more-examples 13 | 14 | */ 15 | 16 | var ( 17 | scrW, scrH int // SCREEN WIDTH & HEIGHT 18 | 19 | side, topbot, centr, poptb xmenu //MENU STRUCTS 20 | 21 | colNum int //COLOR NUMBER 22 | 23 | cnt, mouse, clickV2, cornerV2 rl.Vector2 //SCREEN CENTER/MOUSE POSITION/MOVE WINDOW VECTOR2s 24 | 25 | move bool //ON//OFF FOR MOVE WINDOW 26 | 27 | camCircs []xcirc //SLICE OF CIRCLE STRUCTS FOR CAMERA DISPLAY 28 | 29 | colors = []rl.Color{rl.Red, rl.Magenta, rl.Yellow, rl.Green, rl.Blue, rl.DarkBlue, rl.DarkGray, rl.Purple, rl.Orange} //SLICE OF COLORS 30 | 31 | delta, distX, distY float32 //FRAME TIME FOR POP UP MOVEMENT / DISTANCE FOR CENTER MENU MOVE 32 | 33 | camera rl.Camera2D //CAMERA OF BACKGROUND WINDOW 34 | ) 35 | 36 | // STRUCT WITH MENU INFORMATION 37 | type xmenu struct { 38 | rec, tabrec rl.Rectangle 39 | lr, tb, oc bool 40 | col rl.Color 41 | fd float32 42 | name string 43 | } 44 | 45 | // STRUCT WITH CIRCLE INFORMATION 46 | type xcirc struct { 47 | cnt rl.Vector2 48 | rad float32 49 | col rl.Color 50 | fd float32 51 | } 52 | 53 | func main() { 54 | 55 | rl.InitWindow(0, 0, "menus & windows - raylib go - https://github.com/unklnik/raylib-go-more-examples") 56 | rl.SetWindowState(rl.FlagBorderlessWindowedMode | rl.FlagMsaa4xHint) 57 | 58 | scrW, scrH = rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 59 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 60 | 61 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 62 | 63 | cnt = rl.NewVector2(float32(scrW/2), float32(scrH/2)) //SCREEN CENTER 64 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 65 | 66 | makeMenus() //MAKE INITAL MENUS/WINDOWS 67 | makeCircs() //MAKE BACKGROUND CIRCLES 68 | 69 | rl.SetTargetFPS(60) // NUMBER OF FRAMES DRAWN IN A SECOND 70 | 71 | for !rl.WindowShouldClose() { 72 | 73 | delta = rl.GetFrameTime() //GET FRAME TIME FOR USE LATER 74 | 75 | upMenus() //UPDATE MENUS 76 | 77 | mouse = rl.GetMousePosition() //GET POISITON OF MOUSE CURSOR 78 | 79 | rl.BeginDrawing() 80 | 81 | rl.ClearBackground(rl.Black) 82 | 83 | rl.BeginMode2D(camera) 84 | 85 | //DRAW CIRCLES IN CAMERA VIEW 86 | for i := 0; i < len(camCircs); i++ { 87 | rl.DrawCircleV(camCircs[i].cnt, camCircs[i].rad, rl.Fade(camCircs[i].col, camCircs[i].fd)) 88 | rl.DrawCircleLines(int32(camCircs[i].cnt.X), int32(camCircs[i].cnt.Y), camCircs[i].rad, camCircs[i].col) 89 | } 90 | 91 | rl.EndMode2D() 92 | 93 | //DRAW MENUS ABOVE LAYER OUTSIDE OF CAMERA 94 | drawMenus() 95 | 96 | rl.EndDrawing() 97 | } 98 | 99 | rl.CloseWindow() 100 | } 101 | 102 | // DRAW MENUS 103 | func drawMenus() { 104 | 105 | txs := int32(20) //TEXT SIZE 106 | titleBarH := float32(txs + txs/2) //HEIGHT OF WINDOW/MENU TITLE BAR 107 | 108 | //SIDE 109 | titleRec := rl.NewRectangle(side.rec.X, side.rec.Y, side.rec.Width, titleBarH) //TITLEBAR RECTANGLE 110 | rl.DrawRectangleRec(side.rec, rl.Fade(side.col, side.fd)) //DRAW SIDE MENU REC 111 | rl.DrawRectangleRec(titleRec, side.col) //DRAW SIDE MENU TITLE BAR 112 | side.tabrec = rl.NewRectangle(side.rec.X+side.rec.Width-titleRec.Height, side.rec.Y, titleRec.Height, titleRec.Height) // DEFINE RECTANLGE FOR MOVE LEFT/RIGHT SWITCH 113 | if side.lr { 114 | side.tabrec.X = side.rec.X //CHANGE POSITION BASED ON LEFT/RIGHT (L/R) 115 | } 116 | side.tabrec.X += 4 //MAKE SLIGHTLY SMALLER THAN TITLEBAR 117 | side.tabrec.Y += 4 118 | side.tabrec.Width -= 8 119 | side.tabrec.Height -= 8 120 | 121 | txlen := rl.MeasureText(side.name, txs) //FIND TEXT LENGTH FOR CENTER 122 | xtx := int32(side.rec.X+side.rec.Width/2) - txlen/2 123 | ytx := int32(titleRec.Y+titleRec.Height/2) - txs/2 124 | 125 | rl.DrawText(side.name, xtx, ytx, txs, rl.Black) //DRAW SIDE MENU TITLE 126 | 127 | rl.DrawRectangleRec(side.tabrec, rl.Black) // DRAW L/R SWITCH 128 | rl.DrawRectangleRec(side.tabrec, rl.Fade(side.col, side.fd)) 129 | rl.DrawRectangleLinesEx(side.tabrec, 1, rl.Black) 130 | 131 | // DRAW L/R SWITCH TEXT 132 | txt := ">>" 133 | if side.lr { 134 | txt = "<<" 135 | } 136 | txlen = rl.MeasureText(txt, txs) 137 | xtx = int32(side.tabrec.X+side.tabrec.Width/2) - txlen/2 138 | ytx = int32(side.tabrec.Y+side.tabrec.Height/2) - txs/2 139 | rl.DrawText(txt, xtx, ytx, txs, rl.Black) 140 | 141 | // L/R SWITCH ON/OFF 142 | if rl.CheckCollisionPointRec(mouse, side.tabrec) { 143 | if rl.IsMouseButtonPressed(rl.MouseButtonLeft) { 144 | side.lr = !side.lr 145 | } 146 | } 147 | 148 | //CAMERA ZOOM MENU ITEM 149 | ytx += titleRec.ToInt32().Height * 2 150 | txt = "camera zoom > click" 151 | txlen = rl.MeasureText(txt, txs) 152 | xtx = side.rec.ToInt32().X + side.rec.ToInt32().Width/2 - txlen/2 153 | backRec := rl.NewRectangle(side.rec.X, float32(ytx)-2, side.rec.Width, float32(txs)+4) 154 | if rl.CheckCollisionPointRec(mouse, backRec) { 155 | rl.DrawRectangleRec(backRec, side.col) 156 | if rl.IsMouseButtonPressed(rl.MouseLeftButton) { //IF MOUSE CLICK CHANGE CAMERA ZOOM 157 | if camera.Zoom == 1 { 158 | camera.Zoom = 1.5 159 | } else if camera.Zoom == 1.5 { 160 | camera.Zoom = 2 161 | } else if camera.Zoom == 2 { 162 | camera.Zoom = 0.5 163 | } else if camera.Zoom == 0.5 { 164 | camera.Zoom = 1 165 | } 166 | camera.Target = cnt 167 | camera.Offset.X = float32(scrW / 2) 168 | camera.Offset.Y = float32(scrH / 2) 169 | } 170 | } 171 | rl.DrawText(txt, xtx, ytx, txs, rl.Black) 172 | 173 | //COLORS MENU ITEM 174 | ytx += txs + txs/2 175 | txt = "colors > click" 176 | txlen = rl.MeasureText(txt, txs) 177 | xtx = side.rec.ToInt32().X + side.rec.ToInt32().Width/2 - txlen/2 178 | backRec = rl.NewRectangle(side.rec.X, float32(ytx)-2, side.rec.Width, float32(txs)+4) 179 | if rl.CheckCollisionPointRec(mouse, backRec) { 180 | rl.DrawRectangleRec(backRec, side.col) 181 | if rl.IsMouseButtonPressed(rl.MouseLeftButton) { //IF MOUSE CLICK CHANGE COLOR 182 | colNum++ 183 | if colNum == len(colors) { 184 | colNum = 0 185 | } 186 | side.col = colors[colNum] 187 | poptb.col = colors[colNum] 188 | topbot.col = colors[colNum] 189 | centr.col = colors[colNum] 190 | } 191 | } 192 | rl.DrawText(txt, xtx, ytx, txs, rl.Black) 193 | 194 | //CENTER 195 | titleRec = rl.NewRectangle(centr.rec.X, centr.rec.Y, centr.rec.Width, titleBarH) 196 | rl.DrawRectangleRec(centr.rec, rl.Fade(centr.col, centr.fd)) 197 | rl.DrawRectangleRec(titleRec, centr.col) 198 | if rl.CheckCollisionPointRec(mouse, titleRec) { 199 | 200 | if rl.IsMouseButtonPressed(rl.MouseButtonLeft) { 201 | clickV2 = rl.GetMousePosition() //GET MOUSE POSITION AT CLICK 202 | cornerV2 = rl.NewVector2(centr.rec.X, centr.rec.Y) //GET WINDOW TOP LEFT CORNER POSITION 203 | distX = clickV2.X - cornerV2.X //CALCULATE DISTANCE FROM MOUSE X TO CORNER X 204 | distY = clickV2.Y - cornerV2.Y //CALCULATE DISTANCE FROM MOUSE Y TO CORNER Y 205 | } 206 | 207 | //MOVE WINDOW ON/OFF 208 | if rl.IsMouseButtonDown(rl.MouseButtonLeft) { 209 | move = true 210 | } else { 211 | move = false 212 | } 213 | 214 | } 215 | 216 | //DRAW WINDOW TITLE 217 | txlen = rl.MeasureText(centr.name, txs) 218 | xtx = int32(centr.rec.X+centr.rec.Width/2) - txlen/2 219 | ytx = int32(titleRec.Y+titleRec.Height/2) - txs/2 220 | rl.DrawText(centr.name, xtx, ytx, txs, rl.Black) 221 | 222 | //TOP/BOT 223 | rl.DrawRectangleRec(topbot.rec, rl.Fade(topbot.col, topbot.fd)) 224 | siz := topbot.rec.Height / 2 225 | topbot.tabrec = rl.NewRectangle(topbot.rec.X+topbot.rec.Width-(siz+siz/2), topbot.rec.Y+siz/2, siz, siz) 226 | rl.DrawRectangleRec(topbot.tabrec, topbot.col) 227 | v1, v2, v3 := rl.Vector2{}, rl.Vector2{}, rl.Vector2{} 228 | siz = siz / 2 229 | //DRAW TRIANGLE FOR TOP/BOTTOM SWITCH 230 | if topbot.tb { 231 | v1 = rl.NewVector2(topbot.tabrec.X+topbot.tabrec.Width/2, topbot.tabrec.Y+topbot.tabrec.Height/2) 232 | v1.X -= siz / 2 233 | v1.Y += siz / 2 234 | v2 = v1 235 | v2.X += siz 236 | v3 = rl.NewVector2(topbot.tabrec.X+topbot.tabrec.Width/2, topbot.tabrec.Y+topbot.tabrec.Height/2) 237 | v3.Y -= siz / 2 238 | if rl.CheckCollisionPointRec(mouse, topbot.tabrec) { 239 | rl.DrawTriangle(v2, v3, v1, rl.Green) 240 | } else { 241 | rl.DrawTriangle(v2, v3, v1, rl.Black) 242 | } 243 | } else { 244 | v1 = rl.NewVector2(topbot.tabrec.X+topbot.tabrec.Width/2, topbot.tabrec.Y+topbot.tabrec.Height/2) 245 | v1.X -= siz / 2 246 | v1.Y -= siz / 2 247 | v2 = v1 248 | v2.X += siz 249 | v3 = rl.NewVector2(topbot.tabrec.X+topbot.tabrec.Width/2, topbot.tabrec.Y+topbot.tabrec.Height/2) 250 | v3.Y += siz / 2 251 | if rl.CheckCollisionPointRec(mouse, topbot.tabrec) { 252 | rl.DrawTriangle(v3, v2, v1, rl.Green) 253 | } else { 254 | rl.DrawTriangle(v3, v2, v1, rl.Black) 255 | } 256 | } 257 | 258 | if rl.CheckCollisionPointRec(mouse, topbot.tabrec) { 259 | if rl.IsMouseButtonPressed(rl.MouseLeftButton) { 260 | //CHANGE POP UP MENU POSITION IF TOP/BOTTOM WINDOW CHANGES 261 | topbot.tb = !topbot.tb 262 | poptb.tb = !poptb.tb 263 | if poptb.tb { 264 | poptb.rec.Y -= float32(scrH) + (poptb.rec.Height - (float32(scrH) - poptb.rec.Y)) 265 | poptb.tabrec.Y = poptb.rec.Y + poptb.rec.Height 266 | } else { 267 | poptb.rec.Y += float32(scrH) + float32(math.Abs(float64(poptb.rec.Y))) 268 | poptb.tabrec.Y = poptb.rec.Y - poptb.tabrec.Height 269 | } 270 | } 271 | } 272 | 273 | //DRAW SIDE BAR TOP/BOTTOM SHADOW 274 | if side.lr { 275 | rl.DrawLine(topbot.rec.ToInt32().X+topbot.rec.ToInt32().Width, topbot.rec.ToInt32().Y, topbot.rec.ToInt32().X+topbot.rec.ToInt32().Width, topbot.rec.ToInt32().Y+topbot.rec.ToInt32().Height, rl.Black) 276 | rl.DrawRectangleGradientH(topbot.rec.ToInt32().X+topbot.rec.ToInt32().Width-4, topbot.rec.ToInt32().Y, 4, topbot.rec.ToInt32().Height, rl.Blank, rl.Black) 277 | } else { 278 | rl.DrawLine(topbot.rec.ToInt32().X+1, topbot.rec.ToInt32().Y, topbot.rec.ToInt32().X+1, topbot.rec.ToInt32().Y+topbot.rec.ToInt32().Height, rl.Black) 279 | rl.DrawRectangleGradientH(topbot.rec.ToInt32().X+1, topbot.rec.ToInt32().Y, 4, topbot.rec.ToInt32().Height, rl.Black, rl.Blank) 280 | } 281 | 282 | //POP TOP/BOT 283 | rl.DrawRectangleRec(poptb.rec, rl.Fade(poptb.col, poptb.fd)) 284 | rl.DrawRectangleRec(poptb.tabrec, poptb.col) 285 | if rl.CheckCollisionPointRec(mouse, poptb.tabrec) { 286 | if rl.IsMouseButtonPressed(rl.MouseLeftButton) { 287 | poptb.oc = !poptb.oc //CHANGE OPEN CLOSE (OC) IF CLICKED 288 | } 289 | } 290 | txt = "click" 291 | txs = int32(30) 292 | txlen = rl.MeasureText(txt, txs) 293 | xtx = poptb.tabrec.ToInt32().X + poptb.tabrec.ToInt32().Width/2 - txlen/2 294 | ytx = poptb.tabrec.ToInt32().Y + poptb.tabrec.ToInt32().Height/2 - txs/2 295 | rl.DrawText(txt, xtx-1, ytx+1, txs, rl.Black) 296 | rl.DrawText(txt, xtx, ytx, txs, rl.Black) 297 | 298 | } 299 | 300 | func upMenus() { 301 | 302 | //CENTER WINDOW MOVE 303 | if move { 304 | if centr.rec.X >= 0 && centr.rec.X <= float32(scrW)-centr.rec.Width { 305 | centr.rec.X = rl.GetMousePosition().X - distX 306 | } 307 | if centr.rec.Y >= 0 && centr.rec.Y <= float32(scrH)-centr.rec.Height { 308 | centr.rec.Y = rl.GetMousePosition().Y - distY 309 | } 310 | } 311 | //KEEP WINDOW WITHIN SCREEN 312 | if centr.rec.Y < 0 { 313 | centr.rec.Y = 0 314 | } 315 | if centr.rec.Y > float32(scrH)-centr.rec.Height { 316 | centr.rec.Y = float32(scrH) - centr.rec.Height 317 | } 318 | if centr.rec.X < 0 { 319 | centr.rec.X = 0 320 | } 321 | if centr.rec.X > float32(scrW)-centr.rec.Width { 322 | centr.rec.X = float32(scrW) - centr.rec.Width 323 | } 324 | 325 | //POP TOP/BOT POSITION RELATIVE TO SIDEAR POSITION 326 | if side.lr { 327 | poptb.rec.X = 100 328 | } else { 329 | poptb.rec.X = float32(scrW) - (poptb.rec.Width + 100) 330 | } 331 | poptb.tabrec.X = poptb.rec.X 332 | 333 | //MOVE POP UP MENU WINDOW UP/DOWN 334 | popSpd := float32(8) + delta 335 | if poptb.oc && topbot.tb { 336 | if poptb.rec.Y < 0 { 337 | poptb.rec.Y += popSpd 338 | poptb.tabrec.Y += popSpd 339 | } 340 | if poptb.rec.Y > 0 { 341 | poptb.rec.Y = 0 342 | poptb.tabrec.Y = poptb.rec.Height 343 | } 344 | } else if !poptb.oc && topbot.tb { 345 | if poptb.rec.Y > -poptb.rec.Height { 346 | poptb.rec.Y -= popSpd 347 | poptb.tabrec.Y -= popSpd 348 | } 349 | if poptb.rec.Y < -poptb.rec.Height { 350 | poptb.rec.Y = -poptb.rec.Height 351 | poptb.tabrec.Y = 0 352 | } 353 | } else if poptb.oc && !topbot.tb { 354 | if poptb.rec.Y > float32(scrH)-poptb.rec.Height { 355 | poptb.rec.Y -= popSpd 356 | poptb.tabrec.Y -= popSpd 357 | } 358 | if poptb.rec.Y < float32(scrH)-poptb.rec.Height { 359 | poptb.rec.Y = float32(scrH) - poptb.rec.Height 360 | poptb.tabrec.Y = poptb.rec.Y - poptb.tabrec.Height 361 | } 362 | } else if !poptb.oc && !topbot.tb { 363 | if poptb.rec.Y < float32(scrH) { 364 | poptb.rec.Y += popSpd 365 | poptb.tabrec.Y += popSpd 366 | } 367 | if poptb.rec.Y > float32(scrH) { 368 | poptb.rec.Y = float32(scrH) 369 | poptb.tabrec.Y = poptb.rec.Y - poptb.tabrec.Height 370 | } 371 | } 372 | 373 | //TOP/BOT POSITION CHANGE 374 | if topbot.tb { 375 | topbot.rec.Y = float32(scrH) - topbot.rec.Height 376 | } else { 377 | topbot.rec.Y = 0 378 | } 379 | 380 | //SIDE POSITION CHANGE 381 | if side.lr { 382 | topbot.rec.X = 0 383 | side.rec.X = float32(scrW) - side.rec.Width 384 | } else { 385 | topbot.rec.X = side.rec.Width 386 | side.rec.X = 0 387 | } 388 | 389 | } 390 | 391 | func makeMenus() { 392 | 393 | //FILL THE MENU STRUCTS 394 | colNum = rInt(0, len(colors)) 395 | col := colors[colNum] 396 | fd := float32(0.5) 397 | 398 | //SIDE 399 | side.col = col 400 | side.fd = fd 401 | side.rec = rl.NewRectangle(0, 0, 300, float32(scrH)) 402 | side.name = "side" 403 | 404 | //TOP/BOT 405 | topbot.col = col 406 | topbot.fd = fd 407 | topbot.rec = rl.NewRectangle(0, 0, float32(scrW), 50) 408 | topbot.rec.Width -= side.rec.Width 409 | topbot.name = "top/bottom" 410 | 411 | //CENTER 412 | centr.col = col 413 | centr.fd = fd 414 | centr.rec = rl.NewRectangle(cnt.X-200, cnt.Y-100, 400, 200) 415 | centr.name = "center - click hold drag moves" 416 | 417 | //POP TOP/BOT 418 | poptb.col = col 419 | poptb.fd = fd 420 | poptb.rec = rl.NewRectangle(float32(scrW)-300, float32(scrH), 200, 300) 421 | tabsiz := poptb.rec.Width / 2 422 | poptb.tabrec = rl.NewRectangle(poptb.rec.X, poptb.rec.Y-tabsiz/2, tabsiz, tabsiz/2) 423 | } 424 | 425 | // CREATE BACKGROUND CIRCLES 426 | func makeCircs() { 427 | num := rInt(25, 31) 428 | for num > 0 { 429 | zcirc := xcirc{} 430 | zcirc.col = ranCol() 431 | zcirc.fd = rF32(0.2, 1.1) 432 | zcirc.cnt = rl.NewVector2(rF32(0, float32(scrW)), rF32(0, float32(scrH))) 433 | zcirc.rad = rF32(10, 101) 434 | camCircs = append(camCircs, zcirc) 435 | num-- 436 | } 437 | } 438 | 439 | // RETURNS RANDOM COLOR 440 | func ranCol() rl.Color { 441 | return rl.NewColor(uint8(rInt(0, 256)), uint8(rInt(0, 256)), uint8(rInt(0, 256)), 255) 442 | } 443 | 444 | // RETURNS RANDOM INTEGER FOR USE WITH RANDOMCOLOR 445 | func rInt(min, max int) int { 446 | return min + rand.Intn(max-min) 447 | } 448 | 449 | // RETURNS RANDOM FLOAT32 450 | func rF32(min, max float32) float32 { 451 | min2 := float64(min) 452 | max2 := float64(max) 453 | return float32(min2 + rand.Float64()*(max2-min2)) 454 | } 455 | -------------------------------------------------------------------------------- /2D_Advanced/moving_spike_block/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - MOVING SPIKE BLOCK 3 | 4 | This demonstrates how to create a moving block with four spikes that move along with the block and cause damage when the moving spikes collide with the player rectangle. WASD keys move the player, SPACE key to create a new room, UP arrow key to change zoom and F1 key to turn on debug mode which will display rectangle outlines instead of images. View more at [unklnik.com](https://unklnik.com/posts/2d-moving-spike-block/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/14b1d084-312e-4bec-aaa8-8b3963d73317 7 | -------------------------------------------------------------------------------- /2D_Advanced/moving_spike_block/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "math/rand" 7 | 8 | rl "github.com/gen2brain/raylib-go/raylib" 9 | ) 10 | 11 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 12 | 13 | https://github.com/unklnik/raylib-go-more-examples 14 | 15 | */ 16 | 17 | var ( 18 | tiles rl.Texture2D //IMG TEXTURE WITH TILES 19 | size = float32(32) //TILE SIZE CHANGE FOR LARGER/SMALLER IMG DISPLAY SIZE 20 | cnt rl.Vector2 //SCREEN CENTER VECTOR2 21 | wallTile = rl.NewRectangle(16, 0, 16, 16) //DEFINES RECTANGLE OF WALL BLOCK IMAGE 22 | spikeTile = rl.NewRectangle(1, 2, 13, 13) //DEFINES RECTANGLE OF SPIKE IMAGE 23 | innerRec rl.Rectangle //INNER RECTANGLE OF ROOM 24 | bloks []xblok //SLICE OF WALL BLOCKS 25 | debug bool //USED TO TURN ON/OFF DEBUGGING MODE 26 | playerRec rl.Rectangle //PLAYER RECTANGLE 27 | playerCollisT int32 //COLLISION TIMER FOR PLAYER VERSUS SPIKES 28 | fps = int32(60) //FRAMES PER SECOND 29 | playerSpd = float32(8) //MAX SPEED OF PLAYER MOVEMENT 30 | ) 31 | 32 | // STRUCT CONTAINS DATA OF WALL BLOCKS 33 | type xblok struct { 34 | rec, img rl.Rectangle //RECTANGLE & IMAGE 35 | spikes, spikesOnOff bool //WHETHER BLOCK HAS SPIKES & IF SPIKES MOVE UP/DOWN LEFT/RIGHT 36 | spikeRecs []rl.Rectangle //RECTANGLES FOR THE 4 SPIKE IMAGES 37 | spd, dirX, dirY float32 //MAX SPEED & MOVEMENT DIRECTION OF MOVING BLOCKS 38 | } 39 | 40 | func main() { 41 | 42 | rl.InitWindow(0, 0, "moving spike block - raylib go - https://github.com/unklnik/raylib-go-more-examples") 43 | scrW, scrH := rl.GetScreenWidth(), rl.GetScreenHeight() //GET SCREEN SIZES 44 | rl.SetWindowSize(scrW, scrH) //SET WINDOW SIZE 45 | rl.SetWindowState(rl.FlagBorderlessWindowedMode) 46 | //rl.ToggleFullscreen() //UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 47 | 48 | cnt = rl.NewVector2(float32(scrW/2), float32(scrH/2)) //FIND SCREEN CENTER 49 | 50 | camera := rl.Camera2D{} //DEFINES THE CAMERA 51 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 52 | 53 | tiles = rl.LoadTexture("tiles.png") //LOAD IMAGES FROM FILE 54 | 55 | makeRoom() //MAKE INITIAL ROOM SEE FUNCTION BELOW 56 | 57 | rl.SetTargetFPS(fps) // NUMBER OF FRAMES DRAWN IN A SECOND 58 | 59 | for !rl.WindowShouldClose() { 60 | 61 | //DEBUG TURNS OFF IMAGES & DISPLAYS RECTANGLE OUTLINES 62 | if rl.IsKeyPressed(rl.KeyF1) { 63 | debug = !debug 64 | } 65 | 66 | if rl.IsKeyPressed(rl.KeyUp) { //CHANGE CAMERA ZOOM KEYS 67 | if camera.Zoom == 0.5 { 68 | camera.Zoom = 1 69 | } else if camera.Zoom == 1 { 70 | camera.Zoom = 1.5 71 | } else if camera.Zoom == 1.5 { 72 | camera.Zoom = 2 73 | } else if camera.Zoom == 2 { 74 | camera.Zoom = 0.5 75 | } 76 | 77 | camera.Target = cnt //SET THE CAMERA TARGET TO CENTER 78 | camera.Offset.X = float32(scrW / 2) //ADJUST FOR ZOOM 79 | camera.Offset.Y = float32(scrH / 2) //ADJUST FOR ZOOM 80 | } 81 | 82 | if rl.IsKeyPressed(rl.KeySpace) { //MAKE A NEW ROOM IF SPACE KEY IS PRESSED 83 | makeRoom() 84 | } 85 | 86 | //MOVE PLAYER 87 | if rl.IsKeyDown(rl.KeyW) { //UP 88 | if checkplayermove(1) { //CHECK FOR OTHER WALL BLOCK COLLISIONS SEE FUNCTION BELOW 89 | playerRec.Y -= playerSpd 90 | } 91 | } 92 | if rl.IsKeyDown(rl.KeyS) { //DOWN 93 | if checkplayermove(3) { 94 | playerRec.Y += playerSpd 95 | } 96 | } 97 | if rl.IsKeyDown(rl.KeyA) { //LEFT 98 | if checkplayermove(4) { 99 | playerRec.X -= playerSpd 100 | } 101 | } 102 | if rl.IsKeyDown(rl.KeyD) { //RIGHT 103 | if checkplayermove(2) { 104 | playerRec.X += playerSpd 105 | } 106 | } 107 | 108 | rl.BeginDrawing() 109 | 110 | rl.ClearBackground(rl.Black) 111 | 112 | rl.BeginMode2D(camera) 113 | 114 | for i := 0; i < len(bloks); i++ { 115 | 116 | //MOVE SPIKES 117 | if bloks[i].spikes { 118 | if bloks[i].spikesOnOff { 119 | bloks[i].spikeRecs[0].Y++ //UP SPIKE 120 | bloks[i].spikeRecs[1].X-- //RIGHT SPIKE 121 | bloks[i].spikeRecs[2].Y-- //DOWN SPIKE 122 | bloks[i].spikeRecs[3].X++ //LEFT SPIKE 123 | //IF SPIKE BLOCK REACHES BORDER CHANGE DIRECTION 124 | if bloks[i].spikeRecs[0].Y >= bloks[i].rec.Y { 125 | bloks[i].spikeRecs[0].Y = bloks[i].rec.Y 126 | bloks[i].spikesOnOff = false 127 | } 128 | } else { 129 | bloks[i].spikeRecs[0].Y-- //UP SPIKE 130 | bloks[i].spikeRecs[1].X++ //RIGHT SPIKE 131 | bloks[i].spikeRecs[2].Y++ //DOWN SPIKE 132 | bloks[i].spikeRecs[3].X-- //LEFT SPIKE 133 | //IF SPIKE BLOCK REACHES BORDER CHANGE DIRECTION 134 | if bloks[i].spikeRecs[0].Y <= bloks[i].rec.Y-bloks[i].spikeRecs[0].Height { 135 | bloks[i].spikeRecs[0].Y = bloks[i].rec.Y - bloks[i].spikeRecs[0].Height 136 | bloks[i].spikesOnOff = true 137 | } 138 | } 139 | 140 | //DRAW SPIKES 141 | for j := 0; j < len(bloks[i].spikeRecs); j++ { 142 | drawRec := bloks[i].spikeRecs[j] 143 | drawRec.X += drawRec.Width / 2 144 | drawRec.Y += drawRec.Height / 2 145 | 146 | //DRAW LINES NOT IMAGES IF DEBUG IS ON 147 | if debug { 148 | rl.DrawRectangleLinesEx(bloks[i].spikeRecs[j], 1, rl.Red) 149 | } else { 150 | rl.DrawTexturePro(tiles, spikeTile, drawRec, rl.NewVector2(drawRec.Width/2, drawRec.Height/2), float32(j)*90, rl.White) 151 | } 152 | //CHECK COLLISION OF SPIKE REC VERSUS PLAYER 153 | if rl.CheckCollisionRecs(bloks[i].spikeRecs[j], playerRec) && playerCollisT == 0 { 154 | playerCollisT = fps * 2 155 | } 156 | } 157 | } 158 | 159 | //DRAW WALL BLOKS 160 | if debug { 161 | rl.DrawRectangleLinesEx(bloks[i].rec, 1, rl.Orange) 162 | } else { 163 | rl.DrawTexturePro(tiles, bloks[i].img, bloks[i].rec, rl.Vector2Zero(), 0, rl.White) 164 | } 165 | 166 | //DRAW PLAYER 167 | if playerCollisT > 0 { //IF COLLISION TIMER LARGER THAN ZERO DECREASE TIMER & DRAW RED 168 | if debug { 169 | rl.DrawRectangleLinesEx(playerRec, 2, rl.Red) 170 | } else { 171 | rl.DrawRectangleRec(playerRec, rl.Red) 172 | } 173 | playerCollisT-- 174 | } else { //DRAW GREEN PLAYER IF COLLISION HAS NOT HAPPENED 175 | if debug { 176 | rl.DrawRectangleLinesEx(playerRec, 2, rl.Green) 177 | } else { 178 | rl.DrawRectangleRec(playerRec, rl.Green) 179 | } 180 | } 181 | 182 | //MOVE SPIKE BLOK 183 | if bloks[i].dirX != 0 || bloks[i].dirY != 0 { 184 | moveBlok(i) //SEE FUNCTION BELOW 185 | } 186 | } 187 | 188 | //DRAW INNER REC DEBUG 189 | if debug { 190 | rl.DrawRectangleLinesEx(innerRec, 2, rl.Magenta) 191 | } 192 | 193 | rl.EndMode2D() 194 | 195 | //DRAW TEXT 196 | rl.DrawText("camera zoom "+fmt.Sprintf("%.1f", camera.Zoom)+" press UP ARROW key to change", 10, 10, 20, rl.White) 197 | rl.DrawText("press SPACE key to make a new room", 10, 40, 20, rl.White) 198 | rl.DrawText("press F1 key to change to debug mode", 10, 70, 20, rl.White) 199 | rl.DrawText("WASD keys move player to collide with spikes", 10, 100, 20, rl.White) 200 | 201 | rl.EndDrawing() 202 | } 203 | 204 | rl.UnloadTexture(tiles) //UNLOAD FROM MEMORY 205 | 206 | rl.CloseWindow() 207 | } 208 | func moveBlok(blokNum int) { //MOVE SPIKE BLOCK FUNCTION 209 | 210 | canmove := true 211 | checkRec := bloks[blokNum].rec //CREATE DUPLICATE CHECK RECTANGLE 212 | checkRec.X += bloks[blokNum].dirX //MOVE X TO NEXT POSITION 213 | checkRec.Y += bloks[blokNum].dirY //MOVE Y TO NEXT POSITION 214 | 215 | //CHECK FOR COLLISIONS OF CHECK RECTANGLE VERSUS OTHER WALL BLOCKS 216 | for i := 0; i < len(bloks); i++ { 217 | if i != blokNum { //MAKE SURE IT DOES NOT CHECK FOR COLLISIONS WITH ITSELF 218 | if rl.CheckCollisionRecs(checkRec, bloks[i].rec) { 219 | canmove = false 220 | } 221 | } 222 | } 223 | 224 | //CHECK FOR COLLISIONS OF CHECK RECTANGLE VERSUS PLAYER RECTANGLE 225 | if canmove { 226 | if rl.CheckCollisionRecs(checkRec, playerRec) { 227 | canmove = false 228 | } 229 | } 230 | 231 | //IF BLOCK CAN MOVE THEN MOVE TO NEXT POSITION 232 | if canmove { 233 | bloks[blokNum].rec = checkRec 234 | //IF BLOCK HAS SPIKES THEN MOVE SPIKE RECTANGLES 235 | if len(bloks[blokNum].spikeRecs) > 0 { 236 | for i := 0; i < len(bloks[blokNum].spikeRecs); i++ { 237 | bloks[blokNum].spikeRecs[i].X += bloks[blokNum].dirX 238 | bloks[blokNum].spikeRecs[i].Y += bloks[blokNum].dirY 239 | } 240 | } 241 | } else { //IF CANNOT MOVE THEN CHANGE DIRECTION 242 | if bloks[blokNum].dirX < 0 { 243 | bloks[blokNum].dirX = rF32(2, bloks[blokNum].spd) 244 | } else { 245 | bloks[blokNum].dirX = rF32(-bloks[blokNum].spd, -2) 246 | } 247 | if bloks[blokNum].dirY < 0 { 248 | bloks[blokNum].dirY = rF32(2, bloks[blokNum].spd) 249 | } else { 250 | bloks[blokNum].dirY = rF32(-bloks[blokNum].spd, -2) 251 | } 252 | } 253 | 254 | } 255 | func checkplayermove(direc int) bool { 256 | 257 | canmove := true 258 | checkRec := playerRec //CREATE DUPLICATE CHECK RECTANGLE 259 | switch direc { 260 | //MOVE CHECK RECTANGLE TO NEXT POSITION 261 | case 1: //UP 262 | checkRec.Y -= playerSpd 263 | case 2: //RIGHT 264 | checkRec.X += playerSpd 265 | case 3: //DOWN 266 | checkRec.Y += playerSpd 267 | case 4: //LEFT 268 | checkRec.X -= playerSpd 269 | } 270 | //CHECK FOR COLLISIONS WITH WALL BLOCKS 271 | for i := 0; i < len(bloks); i++ { 272 | if rl.CheckCollisionRecs(checkRec, bloks[i].rec) { 273 | canmove = false 274 | } 275 | } 276 | 277 | return canmove 278 | 279 | } 280 | func makeRoom() { //MAKES ROOM 281 | 282 | bloks = nil //CLEARS ANY PREVIOUSLY MADE ROOM 283 | 284 | Wnum := rInt(20, 31) //NUMBER OF BLOCKS WIDE 285 | Hnum := rInt(20, 31) //NUMBER OF BLOCKS HIGH 286 | W := float32(Wnum) * size //TOTAL WIDTH IN PIXELS 287 | H := float32(Hnum) * size //TOTAL HEIGHT IN PIXELS 288 | 289 | x := cnt.X - W/2 //LEFT X OF ROOM RECTANGLE 290 | y := cnt.Y - H/2 //TOP Y OF ROOM RECTANGLE 291 | 292 | innerRec = rl.NewRectangle(x, y, W, H) //INNER ROOM RECTANGLE 293 | 294 | playerRec = rl.NewRectangle(x+size, y+size, size*2, size*2) //CREATE PLAYER IN TOP LEFT CORNER 295 | 296 | x -= size //MOVE X LEFT BY BLOCK SIZE FOR BORDER OF LEFT & RIGHT INNER REC SIDES 297 | x2 := x + W + (size * 2) //RIGHT WALL X 298 | x3 := x //X VALUE FOR ADDING BLOCKS 299 | y -= size //MOVE Y UP BY BLOCK SIZE FOR BORDER OF TOP & BOTTOM INNER REC SIDES 300 | y2 := y + H //BOTTOM WALL Y 301 | y3 := y2 //Y VALUE FOR ADDING BLOCKS 302 | 303 | zblok := xblok{} //EMPTY BLOCK STRUCT 304 | zblok.img = wallTile //DEFINE IMAGE 305 | 306 | for x3 < x2 { 307 | zblok.rec = rl.NewRectangle(x3, y, size, size) //DEFINE TOP WALL BLOCK 308 | bloks = append(bloks, zblok) //ADD TOP WALL BLOCK 309 | zblok.rec.Y += H + size //MOVE Y TO BOTTOM WALL POSITION 310 | bloks = append(bloks, zblok) //ADD BOTTOM WALL BLOCK 311 | x3 += size //MOVE RIGHT ONE BLOCK 312 | } 313 | x3 = x 314 | for y3 > y { 315 | zblok.rec = rl.NewRectangle(x3, y3, size, size) //DEFINE LEFT WALL BLOCK 316 | bloks = append(bloks, zblok) //ADD LEFT WALL BLOCK 317 | zblok.rec.X += W + size //MOVE X TO RIGHT WALL POSITION 318 | bloks = append(bloks, zblok) //ADD RIGHT WALL BLOCK 319 | y3 -= size //MOVE DOWN ONE BLOCK 320 | } 321 | 322 | //CENTER SPIKE BLOK 323 | zblok.rec = rl.NewRectangle(cnt.X-size/2, cnt.Y-size/2, size, size) //DEFINE CENTER BLOCK 324 | zblok.spikes = true //TURN ON SPIKES 325 | 326 | for i := 0; i < 4; i++ { //CREATE FOUR CENTER RECTANGLES SMALLER THAN MAIN BLOCK RECTANGLE 327 | spikeRec := zblok.rec 328 | spikeRec.X += size / 8 329 | spikeRec.Y += size / 8 330 | spikeRec.Width -= size / 4 331 | spikeRec.Height -= size / 4 332 | zblok.spikeRecs = append(zblok.spikeRecs, spikeRec) 333 | } 334 | zblok.spd = 8 //MAX MOVEMENT SPEED OF BLOCK 335 | for { 336 | //SET DIRECTIONS FOR X & Y MOVEMENT 337 | if flipcoin() { 338 | zblok.dirX = rF32(-zblok.spd, zblok.spd) 339 | } else { 340 | zblok.dirY = rF32(-zblok.spd, zblok.spd) 341 | } 342 | //MAKE SURE IT DOES NOT MOVE TO SLOWLY 343 | if getabs(zblok.dirX) > 2 && getabs(zblok.dirY) > 2 { 344 | break 345 | } 346 | } 347 | bloks = append(bloks, zblok) //ADD MOVE BLOCK TO SLICE 348 | } 349 | 350 | // SIMULATES A COIN FLIP 351 | func flipcoin() bool { 352 | onoff := false 353 | choose := rInt(0, 100001) 354 | if choose > 50000 { 355 | onoff = true 356 | } 357 | return onoff 358 | } 359 | 360 | // RETURNS A RANDOM FLOAT32 361 | func rF32(min, max float32) float32 { 362 | min2 := float64(min) 363 | max2 := float64(max) 364 | return float32(min2 + rand.Float64()*(max2-min2)) 365 | } 366 | 367 | // RETURNS THE ABSOLUTE VALUE OF A NUMBER (NOT NEGATIVE) 368 | func getabs(value float32) float32 { 369 | value2 := float64(value) 370 | value = float32(math.Abs(value2)) 371 | return value 372 | } 373 | 374 | // RETURNS A RANDOM INTEGER 375 | func rInt(min, max int) int { 376 | return min + rand.Intn(max-min) 377 | } 378 | -------------------------------------------------------------------------------- /2D_Advanced/moving_spike_block/tiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Advanced/moving_spike_block/tiles.png -------------------------------------------------------------------------------- /2D_Advanced/tile_editor/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - SIMPLE TILE EDITOR 3 | 4 | This demonstrates how to extract images from a tile sheet and use in a simple editor that allows you to place tiles in a grid. You can choose different tiles, change colors and clear the screen. View more at [unklnik.com](https://unklnik.com/posts/2d-tile-editor/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/85eb603a-d8e8-4494-b21b-55d9e8f09b1a 7 | -------------------------------------------------------------------------------- /2D_Advanced/tile_editor/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | 7 | rl "github.com/gen2brain/raylib-go/raylib" 8 | ) 9 | 10 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 11 | 12 | https://github.com/unklnik/raylib-go-more-examples 13 | 14 | */ 15 | 16 | var ( 17 | tileImgs rl.Texture2D //IMG TEXTURE WITH TILES 18 | size = float32(32) //TILE SIZE CHANGE FOR LARGER/SMALLER IMG DISPLAY SIZE 19 | gridW = 20 //WIDTH HEIGHT GRID 20 | gridA int //GRID AREA 21 | cnt rl.Vector2 //SCREEN CENTER VECTOR2 22 | scrW, scrH int //SCREEN WIDTH HEIGHT 23 | tiles []blok //SLICE OF TILE BLOCK STRUCTS 24 | tileRecs []rl.Rectangle //SLICE OF TILE RECTANGLE POSITIONS IN TEXTURE 25 | gridDots, gridLines bool //TURN ON OFF GRID LINES & DOTS 26 | mouseposScreen, mouseposCam rl.Vector2 //MOUSE POSITION VECTOR 2 27 | blinkFade = float32(1) //FADE OF SELECT BOX FOR BLINKING 28 | blinkOnOff bool //FADE IN/OUT BOOLEAN 29 | tileNum, colorNum int //CURRENT SELECTED TILE IMAGE & COLOR 30 | 31 | tileColors = []rl.Color{rl.Green, rl.White, rl.SkyBlue, rl.Orange, rl.Red, rl.LightGray, rl.Lime, rl.DarkBlue, rl.Blue, rl.Brown, rl.Beige, rl.DarkGreen, rl.Purple, rl.Pink, rl.Magenta, rl.DarkBrown, rl.DarkPurple, rl.Yellow, rl.Gold, rl.Violet} //COLORS FOR TILES 32 | ) 33 | 34 | type blok struct { //STRUCT THAT HOLDS EACH TILE INFORMATION 35 | img, rec rl.Rectangle //IMAGE & DRAW RECTANGLES 36 | color rl.Color 37 | } 38 | 39 | func main() { 40 | 41 | rl.InitWindow(0, 0, "tile editor - raylib go - https://github.com/unklnik/raylib-go-more-examples") 42 | scrW, scrH = rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 43 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 44 | 45 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES 46 | //rl.SetWindowState(rl.FlagBorderlessWindowedMode) // UNCOMMENT IF YOU HAVE DISPLAY ISSUES 47 | 48 | cnt = rl.NewVector2(float32(scrW/2), float32(scrH/2)) //FIND SCREEN CENTER 49 | 50 | camera := rl.Camera2D{} // DEFINES THE CAMERA 51 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 52 | 53 | tileImgs = rl.LoadTexture("tiles.png") //LOAD IMAGES FROM FILE 54 | 55 | gridDots = true //TURN ON GRID DOTS BY DEFAULT 56 | 57 | makegridtiles() //MAKE GRID & TILE RECTANGLES FUNCTION BELOW 58 | 59 | rl.SetTargetFPS(60) // NUMBER OF FRAMES DRAWN IN A SECOND 60 | 61 | for !rl.WindowShouldClose() { 62 | 63 | mouseposScreen = rl.GetMousePosition() //GET MOUSE POSITION SCREEN 64 | mouseposCam = rl.GetScreenToWorld2D(mouseposScreen, camera) //GET MOUSE CURSOR POSITION IN CAMERA SPACE 65 | if blinkOnOff { //FADE IN/OUT ON/OFF 66 | if blinkFade < 1 { 67 | blinkFade += 0.05 68 | } else { 69 | blinkOnOff = false 70 | } 71 | } else { 72 | if blinkFade > 0.1 { 73 | blinkFade -= 0.05 74 | } else { 75 | blinkOnOff = true 76 | } 77 | } 78 | 79 | if rl.IsKeyPressed(rl.KeySpace) { //SET ALL TILE COLORS TO BLANK 80 | for i := 0; i < len(tiles); i++ { 81 | tiles[i].color = rl.Blank 82 | } 83 | } 84 | if rl.IsKeyPressed(rl.KeyUp) { //CHANGE CAMERA ZOOM KEYS 85 | if camera.Zoom == 0.5 { 86 | camera.Zoom = 1 87 | } else if camera.Zoom == 1 { 88 | camera.Zoom = 1.5 89 | } else if camera.Zoom == 1.5 { 90 | camera.Zoom = 2 91 | } else if camera.Zoom == 2 { 92 | camera.Zoom = 0.5 93 | } 94 | 95 | camera.Target = cnt //SET THE CAMERA TARGET TO CENTER 96 | camera.Offset.X = float32(scrW / 2) //ADJUST FOR ZOOM 97 | camera.Offset.Y = float32(scrH / 2) //ADJUST FOR ZOOM 98 | } 99 | 100 | rl.BeginDrawing() 101 | 102 | rl.ClearBackground(rl.Black) 103 | 104 | rl.BeginMode2D(camera) 105 | 106 | //DRAW BLOKS 107 | for i := 0; i < len(tiles); i++ { 108 | if tiles[i].color != rl.Blank { //IF TILE NOT CLEAR THEN DRAW IMAGE 109 | rl.DrawTexturePro(tileImgs, tiles[i].img, tiles[i].rec, rl.Vector2Zero(), 0, tiles[i].color) 110 | } 111 | if rl.CheckCollisionPointRec(mouseposCam, tiles[i].rec) { //IF MOUSE HOVERS DRAW BLINKING REC 112 | rl.DrawRectangleRec(tiles[i].rec, rl.Fade(rl.Green, blinkFade)) 113 | if rl.IsMouseButtonDown(rl.MouseButtonLeft) { //IF MOUSE LEFT ASSIGN CURRENT COLOR IMAGE 114 | tiles[i].color = tileColors[colorNum] 115 | tiles[i].img = tileRecs[tileNum] 116 | } else if rl.IsMouseButtonDown(rl.MouseRightButton) { //RIGHT CLICK CLEAR 117 | tiles[i].color = rl.Blank 118 | } 119 | } 120 | } 121 | //DRAW GRID 122 | if gridLines { //DRAW RECTANGLE OUTLINE IF GRIDTILES ON 123 | for i := 0; i < len(tiles); i++ { 124 | rl.DrawRectangleLinesEx(tiles[i].rec, 1, rl.Fade(rl.Green, 0.3)) 125 | } 126 | } 127 | if gridDots { //DRAW RECTANGLE CORNER VECTOR2 IF GRIDDOTS ON 128 | for i := 0; i < len(tiles); i++ { 129 | v1 := rl.NewVector2(tiles[i].rec.X, tiles[i].rec.Y) 130 | v2 := rl.NewVector2(tiles[i].rec.X+size, tiles[i].rec.Y) 131 | v3 := rl.NewVector2(tiles[i].rec.X+size, tiles[i].rec.Y+size) 132 | v4 := rl.NewVector2(tiles[i].rec.X, tiles[i].rec.Y+size) 133 | rl.DrawCircleV(v1, 2, rl.Green) 134 | rl.DrawCircleV(v2, 2, rl.Green) 135 | rl.DrawCircleV(v3, 2, rl.Green) 136 | rl.DrawCircleV(v4, 2, rl.Green) 137 | } 138 | } 139 | 140 | rl.EndMode2D() 141 | 142 | //DRAW TEXT 143 | rl.DrawText("camera zoom "+fmt.Sprintf("%.1f", camera.Zoom)+" press UP ARROW key to change", 10, 10, 20, rl.White) 144 | rl.DrawText("LEFT ARROW key grid dots on/off | RIGHT ARROW key grid lines on/off", 10, 40, 20, rl.White) 145 | rl.DrawText("mouse LEFT draw RIGHT delete / press SPACE key to clear tiles", 10, 70, 20, rl.White) 146 | 147 | drawmenu() 148 | 149 | rl.EndDrawing() 150 | } 151 | 152 | rl.UnloadTexture(tileImgs) //UNLOAD FROM MEMORY 153 | 154 | rl.CloseWindow() 155 | } 156 | func drawmenu() { //RIGHT SIDE MENU 157 | 158 | txt := "lines" 159 | txtlen := rl.MeasureText(txt, 20) //MEASURE TO CENTER TEXT 160 | x := float32(scrW - 150) //OFFSET FROM SCREEN RIGHT EDGE 161 | y := float32(50) 162 | 163 | rec := rl.NewRectangle(x, y, 100, 30) //LINES ON/OFF MENU BUTTON 164 | if gridLines { 165 | rl.DrawRectangleRec(rec, rl.Green) 166 | } else { 167 | rl.DrawRectangleLinesEx(rec, 4, rl.Red) 168 | } 169 | if rl.CheckCollisionPointRec(mouseposScreen, rec) && rl.IsMouseButtonPressed(rl.MouseButtonLeft) || rl.IsKeyPressed(rl.KeyRight) { //IF LEFT CLICK GRIDLINES ON/OFF 170 | gridLines = !gridLines 171 | } 172 | txtx := rec.ToInt32().X + rec.ToInt32().Width/2 - txtlen/2 173 | txty := rec.ToInt32().Y + 5 174 | rl.DrawText(txt, txtx-2, txty+2, 20, rl.Black) 175 | rl.DrawText(txt, txtx, txty, 20, rl.White) 176 | 177 | y = rec.Y + rec.Height + 10 178 | txt = "dots" 179 | 180 | rec = rl.NewRectangle(x, y, 100, 30) 181 | if gridDots { 182 | rl.DrawRectangleRec(rec, rl.Green) 183 | } else { 184 | rl.DrawRectangleLinesEx(rec, 4, rl.Red) 185 | } 186 | if rl.CheckCollisionPointRec(mouseposScreen, rec) && rl.IsMouseButtonPressed(rl.MouseButtonLeft) || rl.IsKeyPressed(rl.KeyLeft) { //IF LEFT CLICK GRIDDOTS ON/OFF 187 | gridDots = !gridDots 188 | } 189 | txtx = rec.ToInt32().X + rec.ToInt32().Width/2 - txtlen/2 190 | txty = rec.ToInt32().Y + 5 191 | rl.DrawText(txt, txtx-2, txty+2, 20, rl.Black) 192 | rl.DrawText(txt, txtx, txty, 20, rl.White) 193 | 194 | y = rec.Y + rec.Height + size 195 | yorig := y //SAVE ORIGINAL Y VALUE 196 | x -= size 197 | 198 | for i := 0; i < len(tileRecs); i++ { //DRAW TEXTURE IMAGES 199 | rec = rl.NewRectangle(x, y, size, size) 200 | rl.DrawTexturePro(tileImgs, tileRecs[i], rec, rl.Vector2Zero(), 0, rl.White) 201 | if rl.CheckCollisionPointRec(mouseposScreen, rec) && rl.IsMouseButtonPressed(rl.MouseLeftButton) { 202 | tileNum = i 203 | } 204 | if tileNum == i { 205 | rl.DrawRectangleLinesEx(rec, 4, rl.Fade(rl.Red, blinkFade)) 206 | } 207 | y += size + 8 //+8 PIXEL SPACING 208 | if i == (len(tileRecs)/2)-1 { 209 | x += size + 8 210 | y = yorig //IF REACHES HALFWAY THEN RETURN TO TOP 211 | } 212 | 213 | } 214 | 215 | y = yorig 216 | x += size + 8 217 | 218 | for i := 0; i < len(tileColors); i++ { //DRAW COLORS 219 | rec = rl.NewRectangle(x, y, size, size) 220 | rl.DrawRectangleRec(rec, tileColors[i]) 221 | if rl.CheckCollisionPointRec(mouseposScreen, rec) && rl.IsMouseButtonPressed(rl.MouseLeftButton) { 222 | colorNum = i 223 | } 224 | if colorNum == i { 225 | if tileColors[i] == rl.Red || tileColors[i] == rl.Violet || tileColors[i] == rl.Magenta || tileColors[i] == rl.Pink || tileColors[i] == rl.Purple { 226 | rl.DrawRectangleLinesEx(rec, 4, rl.Fade(rl.Yellow, blinkFade)) 227 | } else { 228 | rl.DrawRectangleLinesEx(rec, 4, rl.Fade(rl.Red, blinkFade)) 229 | } 230 | } 231 | y += size + 8 232 | if i == (len(tileRecs)/2)-1 { 233 | x += size + 8 234 | y = yorig 235 | } 236 | 237 | } 238 | 239 | } 240 | func makegridtiles() { 241 | 242 | gridA = gridW * gridW //CALCULATE GRID AREA 243 | 244 | x := cnt.X - (float32(gridW/2) * size) //OFFSET FROM CENTER 245 | xorig := x 246 | y := cnt.Y - (float32(gridW/2) * size) 247 | 248 | count := 0 //COUNT USED TO DETERMINE END OF LINE MOVE TO NEXT LINE 249 | 250 | for i := 0; i < gridA; i++ { 251 | newTile := blok{} //CREATE AN EMPTY TILE BLOCK 252 | newTile.rec = rl.NewRectangle(x, y, size, size) //DEFINE THE RECTANGLE 253 | tiles = append(tiles, newTile) //ADD TO SLICE 254 | 255 | x += size //MOVE X BY SIZE OF TILE 256 | count++ //INCREASE COUNT 257 | if count == gridW { //IF COUNT = GRID WIDTH 258 | count = 0 //RESET LINE COUNT 259 | x = xorig //RETURN X TO ORIGINAL POSITION 260 | y += size //MOVE Y DOWN BY TILE SIZE 261 | } 262 | } 263 | 264 | //CREATE TILE IMAGE RECTANGLES 265 | x = 0 //SET X AND Y TO TOP LEFT CORNER (0,0) OF TILE SHEET 266 | y = 0 267 | 268 | for { 269 | tileRecs = append(tileRecs, rl.NewRectangle(x, y, 16, 16)) //ADD TO SLICE 270 | x += 16 //MOVE X BY WIDTH OF 1 TILE 16 PIXELS 271 | if x >= float32(tileImgs.Width) { //IF X = WIDTH OF IMAGE MOVE TO NEXT LINE 272 | x = 0 273 | y += 16 274 | } 275 | if y >= float32(tileImgs.Height) { //IF Y = HEIGHT OF IMAGE BREAK 276 | break 277 | } 278 | } 279 | 280 | } 281 | 282 | // RETURNS A RANDOM INTEGER 283 | func rInt(min, max int) int { 284 | return min + rand.Intn(max-min) 285 | } 286 | -------------------------------------------------------------------------------- /2D_Advanced/tile_editor/tiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Advanced/tile_editor/tiles.png -------------------------------------------------------------------------------- /2D_Advanced/tiled_dungeon_map_with_player/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - TILED DUNGEON MAP WITH PLAYER 3 | 4 | Demonstrates how to create a simple dungeon map of room rectangles for use in top-down games. This expands on the [Simple Dungeon Map Example](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Intermediate/simple_dungeon_map) which should be used as a starting point. Creates random dungeons and tiles the floors and walls and adds a player that moves and is animated. W A S D keys move player, SPACE to make a new map, UP ARROW to change the camera zoom, RIGHT ARROW to turn colors on/off and DOWN ARROW to turn on/off debug mode. Every map will be different from the next map and you can change the number of rooms and map size easily to allow for creation of larger or smaller maps. View more at [unklnik.com](https://unklnik.com/posts/2d-tiled-dungeon-map-with-player/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/37569bb1-ec8a-4381-8abc-4988c5ea78bf 7 | -------------------------------------------------------------------------------- /2D_Advanced/tiled_dungeon_map_with_player/imgs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Advanced/tiled_dungeon_map_with_player/imgs.png -------------------------------------------------------------------------------- /2D_Advanced/tiled_dungeon_map_with_player/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | 7 | rl "github.com/gen2brain/raylib-go/raylib" 8 | ) 9 | 10 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 11 | 12 | https://github.com/unklnik/raylib-go-more-examples 13 | 14 | */ 15 | 16 | var ( 17 | scrW, scrH int // SCREEN WIDTH & HEIGHT 18 | cnt rl.Vector2 // SCREEN CENTER 19 | rooms []rl.Rectangle // SLICE OF ROOM RECTANGLES 20 | baseUnit = float32(32) // BASE UNIT FOR DETERMINING SIZES FOR TILING 21 | min, max = 3, 12 // MIN MAX TILE SIZE OR ROOM SIDES 22 | borderRec rl.Rectangle // BORDER RECTANGLE TO ENSURE ROOMS REMAIN ON SCREEN 23 | camera rl.Camera2D // 2D CAMERA 24 | debug, colors bool // ON/OFF FOR DEBUG & COLORS 25 | floortile, walltile rl.Rectangle // CURRENT DUNGEON FLOOR & WALL TILE IMAGES 26 | tiles []tile // SLICE OF CURRENT DUNGEON TILES 27 | imgs rl.Texture2D // IMAGE 28 | floorimgs, wallimgs []rl.Rectangle // SLICES OF ALL AVAILABLE FLOOR & WALL IMAGES 29 | player xplayer // DEFINE PLAYER 30 | frames int32 // USED TO COUNT FRAMES 31 | delta float32 //FRAME TIME 32 | ) 33 | 34 | type tile struct { // TILE STRUCT 35 | im, rec rl.Rectangle // IMAGE 36 | fd float32 37 | col rl.Color 38 | solid bool 39 | } 40 | type ximg struct { //IMAGE STRUCT FOR USE WITH PLAYER ANIMATIONS 41 | rec rl.Rectangle 42 | frames, startX float32 //NUMBER OF ANIMATION FRAMES & START X POSITION OF ANIMATION LOOP 43 | } 44 | type xplayer struct { //PLAYER 45 | rec, collisrec rl.Rectangle 46 | im rl.Rectangle 47 | walkimgs []ximg 48 | direc int 49 | spd float32 50 | } 51 | 52 | func main() { 53 | 54 | rl.InitWindow(0, 0, "simple dungeon map - raylib go - https://github.com/unklnik/raylib-go-more-examples") 55 | scrW, scrH = rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 56 | rl.SetWindowState(rl.FlagBorderlessWindowedMode) //SET WINDOW STATE 57 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 58 | 59 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 60 | 61 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 62 | 63 | cnt = rl.NewVector2(float32(scrW/2), float32(scrH/2)) //SCREEN CENTER 64 | 65 | borderRec = rl.NewRectangle(0, 0, float32(scrW), float32(scrH)) //DEFINE BORDER RECTANGLE 66 | // MAKE BORDER REC SLIGHLTLY SMALLER SO ROOMS DONT REACH EDGES FOR TILING 67 | borderRec.X += baseUnit 68 | borderRec.Y += baseUnit 69 | borderRec.Width -= baseUnit * 2 70 | borderRec.Height -= baseUnit * 2 71 | 72 | makeimgs() //CREATE IMAGES SEE FUNC BELOW 73 | makerooms() //CREATE INITIAL SLICE OF ROOMS SEE FUNC BELOW 74 | makeplayer() //CREATE PLAYER SEE FUNC BELOW 75 | 76 | rl.SetTargetFPS(60) // NUMBER OF FRAMES DRAWN IN A SECOND 77 | 78 | for !rl.WindowShouldClose() { 79 | delta = rl.GetFrameTime() //GET FRAME TIME FOR SMOOTHER MOVEMENT 80 | frames++ //COUNT THE FRAMES 81 | 82 | inp() //CAPTURE INPUT 83 | upanims() //UPDATE PLAYER ANIMATIONS 84 | 85 | rl.BeginDrawing() 86 | 87 | rl.ClearBackground(rl.Black) 88 | 89 | rl.BeginMode2D(camera) 90 | 91 | for i := 0; i < len(tiles); i++ { //RANGE OVER SLICE OF TILES & DRAW IMAGES 92 | if colors { //IF COLORS ON DRAW COLORS 93 | rl.DrawTexturePro(imgs, tiles[i].im, tiles[i].rec, rl.Vector2Zero(), 0, rl.Fade(tiles[i].col, tiles[i].fd)) 94 | } else { //ELSE DRAW WHITE 95 | rl.DrawTexturePro(imgs, tiles[i].im, tiles[i].rec, rl.Vector2Zero(), 0, rl.Fade(rl.White, tiles[i].fd)) 96 | } 97 | } 98 | 99 | if debug { //DRAWS THE UNDERLYING ROOM STRUCTURE 100 | rl.DrawRectangleLinesEx(borderRec, 2, rl.Magenta) // DRAW BORDER RECTANGLE 101 | for i := 0; i < len(rooms); i++ { // DRAW SLICE OF ROOM RECTANGLES 102 | rl.DrawRectangleRec(rooms[i], rl.Fade(rl.Green, 0.2)) 103 | rl.DrawRectangleLinesEx(rooms[i], 1, rl.White) 104 | rl.DrawText("room "+fmt.Sprint(i), rooms[i].ToInt32().X+8, rooms[i].ToInt32().Y+8, 20, rl.White) // DRAW ROOM NUMBER TEXT 105 | } 106 | } 107 | 108 | //DRAW PLAYER 109 | shadowRec := player.rec //CREATE A DUPLICATE PLAYER REC & MOVE FOR USE AS SHADOW 110 | shadowRec.X -= 4 111 | shadowRec.Y += 4 112 | //DRAW SHADOW REC 113 | rl.DrawTexturePro(imgs, player.im, shadowRec, rl.Vector2Zero(), 0, rl.Fade(rl.Black, 0.7)) 114 | //DRAW PLAYER REC 115 | rl.DrawTexturePro(imgs, player.im, player.rec, rl.Vector2Zero(), 0, rl.White) 116 | //IF DEBUG ON DRAW PLAYER IMG REC & PLAYER COLLISION REC 117 | if debug { 118 | rl.DrawRectangleLinesEx(player.rec, 2, rl.Green) 119 | rl.DrawRectangleLinesEx(player.collisrec, 2, rl.Red) 120 | } 121 | rl.EndMode2D() 122 | //MESSAGE TEXT 123 | rl.DrawText("PRESS SPACE TO MAKE NEW MAP / UP ARROW CHANGE ZOOM", 10, 10, 20, rl.White) 124 | rl.DrawText("RIGHT ARROW CHANGE COLORS / DOWN ARROW SHOW DEBUG", 10, 40, 20, rl.White) 125 | rl.DrawText("W A S D KEYS MOVE PLAYER", 10, 70, 20, rl.White) 126 | 127 | rl.EndDrawing() 128 | } 129 | 130 | rl.CloseWindow() 131 | } 132 | func inp() { 133 | 134 | //CHANGE ZOOM 135 | if rl.IsKeyPressed(rl.KeyUp) { 136 | if camera.Zoom == 1 { 137 | camera.Zoom = 2 138 | } else if camera.Zoom == 2 { 139 | camera.Zoom = 0.5 140 | } else if camera.Zoom == 0.5 { 141 | camera.Zoom = 1 142 | } 143 | camera.Target = cnt 144 | camera.Offset.X = float32(scrW / 2) 145 | camera.Offset.Y = float32(scrH / 2) 146 | } 147 | //SWITCH ON/OFF COLORS 148 | if rl.IsKeyPressed(rl.KeyRight) { 149 | colors = !colors 150 | } 151 | //SWITCH ON/OFF DEBUG 152 | if rl.IsKeyPressed(rl.KeyDown) { 153 | debug = !debug 154 | } 155 | //MAKE NEW ROOMS & RESET PLAYER 156 | if rl.IsKeyPressed(rl.KeySpace) { 157 | makerooms() //PRESS SPACE TO MAKE NEW SET OF ROOMS 158 | makeplayer() 159 | } 160 | //MOVE PLAYER 161 | if rl.IsKeyDown(rl.KeyW) { //UP 162 | player.direc = 1 163 | player.im = player.walkimgs[1].rec //CHANGE PLAYER IMAGE BASED ON DIRECTION 164 | moveplayer(player.direc) 165 | } 166 | if rl.IsKeyDown(rl.KeyD) { //RIGHT 167 | player.direc = 2 168 | player.im = player.walkimgs[0].rec 169 | moveplayer(player.direc) 170 | 171 | } 172 | if rl.IsKeyDown(rl.KeyS) { //DOWN 173 | player.direc = 3 174 | player.im = player.walkimgs[3].rec 175 | moveplayer(player.direc) 176 | 177 | } 178 | if rl.IsKeyDown(rl.KeyA) { //LEFT 179 | player.direc = 4 180 | player.im = player.walkimgs[2].rec 181 | moveplayer(player.direc) 182 | } 183 | 184 | } 185 | func upanims() { 186 | if frames%3 == 0 { 187 | switch player.direc { //UPDATE ANIMATION BASED ON PLAYER DIRECTION 188 | case 1: //UP 189 | player.walkimgs[1].rec.X += player.walkimgs[1].rec.Width 190 | //IF PLAYER IMG REC X IS LARGER THAN START IMAGE X + WIDTH * FRAMES THEN RESET TO START X 191 | if player.walkimgs[1].rec.X > player.walkimgs[1].startX+(player.walkimgs[1].frames*player.walkimgs[1].rec.Width) { 192 | player.walkimgs[1].rec.X = player.walkimgs[1].startX 193 | } 194 | case 2: //RIGHT 195 | player.walkimgs[0].rec.X += player.walkimgs[0].rec.Width 196 | if player.walkimgs[0].rec.X > player.walkimgs[0].startX+(player.walkimgs[0].frames*player.walkimgs[0].rec.Width) { 197 | player.walkimgs[0].rec.X = player.walkimgs[0].startX 198 | } 199 | case 3: //DOWN 200 | player.walkimgs[3].rec.X += player.walkimgs[3].rec.Width 201 | if player.walkimgs[3].rec.X > player.walkimgs[3].startX+(player.walkimgs[3].frames*player.walkimgs[3].rec.Width) { 202 | player.walkimgs[3].rec.X = player.walkimgs[3].startX 203 | } 204 | case 4: //LEFT 205 | player.walkimgs[2].rec.X += player.walkimgs[2].rec.Width 206 | if player.walkimgs[2].rec.X > player.walkimgs[2].startX+(player.walkimgs[2].frames*player.walkimgs[2].rec.Width) { 207 | player.walkimgs[2].rec.X = player.walkimgs[2].startX 208 | } 209 | } 210 | } 211 | 212 | } 213 | func moveplayer(direc int) { 214 | 215 | checkrec := player.collisrec //DUPLICATE PLAYER COLLISION REC 216 | //MOVE DUPLICATE REC TO PLAYERS NEXT POSITION + DELTA 217 | switch player.direc { 218 | case 1: //UP 219 | checkrec.Y -= player.spd + delta 220 | case 2: //RIGHT 221 | checkrec.X += player.spd + delta 222 | case 3: //DOWN 223 | checkrec.Y += player.spd + delta 224 | case 4: //LEFT 225 | checkrec.X -= player.spd + delta 226 | } 227 | 228 | canmove := true 229 | //RANGE OF TILES IF TILE IS SOLID & PLAYER COLLIDES THEN PLAYER CANNOT MOVE 230 | for i := 0; i < len(tiles); i++ { 231 | if tiles[i].solid { 232 | if rl.CheckCollisionRecs(checkrec, tiles[i].rec) { 233 | canmove = false 234 | break 235 | } 236 | } 237 | } 238 | //IF PLAYER CAN MOVE THEN MOVE PLAYER IMAGE REC & PLAYER COLLISION REC 239 | if canmove { 240 | switch player.direc { 241 | case 1: //UP 242 | player.collisrec.Y -= player.spd 243 | player.rec.Y -= player.spd + delta 244 | case 2: //RIGHT 245 | player.collisrec.X += player.spd 246 | player.rec.X += player.spd + delta 247 | case 3: //DOWN 248 | player.collisrec.Y += player.spd 249 | player.rec.Y += player.spd + delta 250 | case 4: //LEFT 251 | player.collisrec.X -= player.spd 252 | player.rec.X -= player.spd + delta 253 | } 254 | } 255 | 256 | } 257 | func makerooms() { 258 | rooms = nil // CLEAR ROOM SLICE 259 | Wnum := rInt(min, max) // NUMBER TO TILES IN ROOM WALL WIDTH 260 | Hnum := rInt(min, max) // NUMBER OF TILES IN ROOM WALL HEIGHT 261 | 262 | W := float32(Wnum) * baseUnit // CALCULATE WIDTH 263 | H := float32(Hnum) * baseUnit // CALCULATE HEIGHT 264 | rooms = append(rooms, rl.NewRectangle(cnt.X-W/2, cnt.Y-H/2, W, H)) // CREATE CENTER ROOM REC 265 | 266 | num := rInt(7, 15) // RANDOM NUMBER OF ROOMS 267 | //num = 1 268 | countbreak := 100 // COUNT TO BREAK LOOP IF ROOMS CANNOT BE FOUND 269 | chooseroom := 0 // NUMBER OF BASE ROOM THAT NEXT ROOM IS ATTACHED TO 270 | 271 | for num > 0 { 272 | 273 | Wnum = rInt(min, max) 274 | Hnum = rInt(min, max) 275 | 276 | W = float32(Wnum) * baseUnit 277 | H = float32(Hnum) * baseUnit 278 | 279 | if len(rooms) > 1 { // IF MORE THAN ONE ROOM RANDOMLY CHOOSE NEXT BASE ROOM FROM EXISTING ROOMS 280 | chooseroom = rInt(0, len(rooms)) 281 | } 282 | x := rooms[chooseroom].X // SET X VALUE FOR NEXT REC FROM BASE REC 283 | y := rooms[chooseroom].Y // SET Y VALUE FOR NEXT REC FROM BASE REC 284 | 285 | choose := rInt(1, 5) // CHOOSE SIDE OF BASE REC TO ATTACH NEXT REC TO 286 | 287 | numWprevRoom := int(rooms[chooseroom].Width / baseUnit) // DETERMINE NUMBER OF TILES IN PREVIOUS ROOM WIDTH 288 | numHprevRoom := int(rooms[chooseroom].Height / baseUnit) // DETERMINE NUMBER OF TILES IN PREVIOUS ROOM HEIGHT 289 | 290 | switch choose { 291 | case 1: //ABOVE 292 | y -= H //MOVE NEW REC ABOVE 293 | if W <= rooms[chooseroom].Width { // IF WIDTH SMALLER THAN PREV REC 294 | change := rInt(-(Wnum - 1), Wnum) // DETERMINE RANDOM X MOVEMENT LEFT/RIGHT LEAVING A ONE TILE SPACE FOR DOOR/PASSAGE 295 | x += float32(change) * baseUnit 296 | } else { // IF WIDTH LARGER THAN PREV REC 297 | change := rInt(-(Wnum - 1), numWprevRoom) // DETERMINE RANDOM X MOVEMENT LEFT/RIGHT LEAVING A ONE TILE SPACE FOR DOOR/PASSAGE 298 | x += float32(change) * baseUnit 299 | } 300 | rec := rl.NewRectangle(x, y, W, H) 301 | if checkaddroom(rec) { // CHECK IF REC COLLIDES WITH OTHER RECS OR BORDER FUNCTION BELOW 302 | rooms = append(rooms, rec) 303 | num-- 304 | } 305 | case 2: //RIGHT 306 | x += rooms[chooseroom].Width //MOVE NEW REC RIGHT 307 | if H <= rooms[chooseroom].Height { // IF HEIGHT SMALLER THAN PREV REC 308 | change := rInt(-(Hnum - 1), Hnum) // DETERMINE RANDOM Y MOVEMENT UP/DOWN LEAVING A ONE TILE SPACE FOR DOOR/PASSAGE 309 | y += float32(change) * baseUnit 310 | } else { 311 | change := rInt(-(Hnum - 1), numHprevRoom) // DETERMINE RANDOM Y MOVEMENT UP/DOWN LEAVING A ONE TILE SPACE FOR DOOR/PASSAGE 312 | y += float32(change) * baseUnit 313 | } 314 | rec := rl.NewRectangle(x, y, W, H) 315 | if checkaddroom(rec) { // CHECK IF REC COLLIDES WITH OTHER RECS OR BORDER FUNCTION BELOW 316 | rooms = append(rooms, rec) 317 | num-- 318 | } 319 | case 3: //BELOW 320 | y += rooms[chooseroom].Height 321 | if W <= rooms[chooseroom].Width { 322 | change := rInt(-(Wnum - 1), Wnum) 323 | x += float32(change) * baseUnit 324 | } else { 325 | change := rInt(-(Wnum - 1), numWprevRoom) 326 | x += float32(change) * baseUnit 327 | } 328 | rec := rl.NewRectangle(x, y, W, H) 329 | if checkaddroom(rec) { 330 | rooms = append(rooms, rec) 331 | num-- 332 | } 333 | case 4: //LEFT 334 | x -= W 335 | if H <= rooms[chooseroom].Height { 336 | change := rInt(-(Hnum - 1), Hnum) 337 | y += float32(change) * baseUnit 338 | } else { 339 | change := rInt(-(Hnum - 1), numHprevRoom) 340 | y += float32(change) * baseUnit 341 | } 342 | rec := rl.NewRectangle(x, y, W, H) 343 | if checkaddroom(rec) { 344 | rooms = append(rooms, rec) 345 | num-- 346 | } 347 | 348 | } 349 | countbreak-- 350 | if countbreak == 0 { 351 | break 352 | } 353 | } 354 | 355 | maketiles() 356 | } 357 | func maketiles() { 358 | 359 | tiles = nil //CLEAR SLICE FOR RE-MAKING LEVEL WHILST GAME IS RUNNING 360 | 361 | floortile = floorimgs[rInt(0, len(floorimgs))] //SELECT RANDOM FLOOR TILE IMAGE 362 | walltile = wallimgs[rInt(0, len(wallimgs))] //SELECT RANDOM WALL TILE IMAGE 363 | 364 | for i := 0; i < len(rooms); i++ { 365 | //WALL TILES 366 | x := rooms[i].X //START X 367 | y := rooms[i].Y //START Y 368 | x -= baseUnit //MOVE 1 BASE UNIT OUTSIDE ROOM BOUNDARY RECTANGLE 369 | y -= baseUnit //MOVE 1 BASE UNIT OUTSIDE ROOM BOUNDARY RECTANGLE 370 | for x <= rooms[i].X+rooms[i].Width { //TOP & BOTTOM ROOM REC WALLS 371 | ztile := tile{} 372 | ztile.im = walltile 373 | ztile.solid = true //SET WALLS SOLID FOR COLLISIONS 374 | ztile.fd = rF32(0.7, 0.9) //CREATES LESS UNIFORM COLOR EFFECT 375 | ztile.rec = rl.NewRectangle(x, y, baseUnit, baseUnit) 376 | ztile.col = col_random() //ADD A RANDOM COLOR 377 | if checkaddrec(ztile.rec) { //CHECK FUNC SEE BELOW 378 | tiles = append(tiles, ztile) //ADD ROOM REC TOP WALL TILE 379 | } 380 | ztile.rec.Y += rooms[i].Height + baseUnit //MOVE Y FOR BOTTOM WALL TILE SAME X VALUE 381 | ztile.col = col_random() //CHANGE COLOR 382 | if checkaddrec(ztile.rec) { 383 | tiles = append(tiles, ztile) 384 | } 385 | x += baseUnit //MOVE ALONG WALL 386 | } 387 | 388 | x = rooms[i].X 389 | y = rooms[i].Y 390 | x -= baseUnit 391 | for y <= rooms[i].Y+rooms[i].Height-baseUnit { //LEFT & RIGHT ROOM REC WALLS 392 | ztile := tile{} 393 | ztile.im = walltile 394 | ztile.solid = true 395 | ztile.fd = rF32(0.7, 0.9) 396 | ztile.rec = rl.NewRectangle(x, y, baseUnit, baseUnit) 397 | ztile.col = col_random() 398 | if checkaddrec(ztile.rec) { 399 | tiles = append(tiles, ztile) 400 | } 401 | ztile.rec.X += rooms[i].Width + baseUnit 402 | ztile.col = col_random() 403 | if checkaddrec(ztile.rec) { 404 | tiles = append(tiles, ztile) 405 | } 406 | y += baseUnit 407 | } 408 | //FLOOR TILES 409 | x = rooms[i].X 410 | y = rooms[i].Y 411 | for y < rooms[i].Y+rooms[i].Height { //FILL ROOM RECS WITH FLOOR TILES 412 | ztile := tile{} 413 | ztile.im = floortile 414 | ztile.fd = rF32(0.1, 0.4) 415 | ztile.rec = rl.NewRectangle(x, y, baseUnit, baseUnit) 416 | ztile.col = col_random() 417 | tiles = append(tiles, ztile) 418 | x += baseUnit 419 | //IF X REACHES ROOM RIGHT BOUNDARY MOVE Y DOWN 1 BASE UNIT & X BACK TO ROOM REC X 420 | if x >= rooms[i].X+rooms[i].Width { 421 | x = rooms[i].X 422 | y += baseUnit 423 | } 424 | } 425 | } 426 | } 427 | func makeimgs() { 428 | imgs = rl.LoadTexture("imgs.png") 429 | x := float32(0) 430 | y := float32(0) 431 | 432 | //ADD FLOOR IMAGE RECTANGLES TO SLICE 433 | for i := 0; i < 12; i++ { 434 | floorimgs = append(floorimgs, rl.NewRectangle(x, y, 16, 16)) 435 | x += 16 436 | } 437 | x = float32(0) 438 | y = float32(16) 439 | //ADD WALL IMAGE RECTANGLES TO SLICE 440 | for i := 0; i < 12; i++ { 441 | wallimgs = append(wallimgs, rl.NewRectangle(x, y, 16, 16)) 442 | x += 16 443 | } 444 | } 445 | func makeplayer() { 446 | player = xplayer{} 447 | size := baseUnit * 2 //PLAYER SIZE 448 | //CENTER PLAYER IN THE MIDDLE OF THE 1ST ROOM REC 449 | player.rec = rl.NewRectangle((rooms[0].X+rooms[0].Width/2)-size/2, (rooms[0].Y+rooms[0].Height/2)-size/2, size, size) 450 | //CREATE A COLLISION RECTANGLE THE SIZE OF THE DRAWN IMAGE 451 | player.collisrec = player.rec 452 | player.collisrec.X += size / 4 453 | player.collisrec.Y += size / 4 454 | player.collisrec.Width -= size / 2 455 | player.collisrec.Height -= size / 2 456 | player.spd = 4 //MOVEMENT SPEED 457 | 458 | //ADD PLAYER MOVEMENT ANIMATION IMAGES 459 | zimg := ximg{} 460 | zimg.frames = 8 461 | zimg.rec = rl.NewRectangle(0, 32, 32, 32) 462 | zimg.startX = zimg.rec.X 463 | player.walkimgs = append(player.walkimgs, zimg) 464 | zimg.rec.Y += zimg.rec.Height 465 | player.walkimgs = append(player.walkimgs, zimg) 466 | zimg.rec.Y += zimg.rec.Height 467 | player.walkimgs = append(player.walkimgs, zimg) 468 | zimg.rec.Y += zimg.rec.Height 469 | player.walkimgs = append(player.walkimgs, zimg) 470 | 471 | //SET START PLAYER IMAGE 472 | player.im = player.walkimgs[0].rec 473 | 474 | } 475 | func checkaddrec(rec rl.Rectangle) bool { 476 | canadd := true 477 | //RANGE OVER ROOM RECS IF TILE REC IS INSIDE A ROOM REC THEN DON'T ADD 478 | for i := 0; i < len(rooms); i++ { 479 | if rl.CheckCollisionRecs(rec, rooms[i]) { 480 | canadd = false 481 | } 482 | } 483 | return canadd 484 | } 485 | func checkaddroom(rec rl.Rectangle) bool { 486 | canadd := true 487 | 488 | // CREATE VECTOR2 OF 4 CORNERS OF NEW ROOM RECTANGLE 489 | v1 := rl.NewVector2(rec.X, rec.Y) 490 | v2 := v1 491 | v2.X += rec.Width 492 | v3 := v2 493 | v3.Y += rec.Height 494 | v4 := v3 495 | v4.X -= rec.Width 496 | 497 | if !rl.CheckCollisionPointRec(v1, borderRec) || !rl.CheckCollisionPointRec(v2, borderRec) || !rl.CheckCollisionPointRec(v3, borderRec) || !rl.CheckCollisionPointRec(v4, borderRec) { 498 | canadd = false // IF A CORNER EXITS BORDER DON'T ADD 499 | } 500 | 501 | if canadd { 502 | for i := 0; i < len(rooms); i++ { 503 | if rl.CheckCollisionRecs(rec, rooms[i]) { 504 | canadd = false // NEW ROOM REC COLLIDES WITH EXISTING ROOM REC DON'T ADD 505 | } 506 | } 507 | } 508 | 509 | return canadd 510 | } 511 | 512 | // RETURNS RANDOM INTEGER 513 | func rInt(min, max int) int { 514 | return min + rand.Intn(max-min) 515 | } 516 | 517 | // RETURNS RANDOM FLOAT32 518 | func rF32(min, max float32) float32 { 519 | min2 := float64(min) 520 | max2 := float64(max) 521 | return float32(min2 + rand.Float64()*(max2-min2)) 522 | } 523 | 524 | // RETURNS RANDOM COLOR 525 | func col_random() rl.Color { 526 | return rl.NewColor(uint8(rInt(0, 256)), uint8(rInt(0, 256)), uint8(rInt(0, 256)), 255) 527 | } 528 | -------------------------------------------------------------------------------- /2D_Beginner/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D BEGINNER EXAMPLES 3 | These examples are intended for anyone that is just starting to get into games programming, the basics of using Raylib and Go to create simple things. These are very easy and help you better understand how Raylib works if you haven't used it. Read the comments if you are not sure what the code is doing. These examples are very basic building blocks that will allow you to create more complex things as you progress. If you find these too easy or already know everything here then move on to the [2D Intermediate Examples](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Intermediate). 4 | 5 | -------------------------------------------------------------------------------- /2D_Beginner/animated_character/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - SIMPLE ANIMATED CHARACTER 3 | 4 | This demonstrates a basic animated sprite character with change of speed, zoom and color. UP key to change zoom, DOWN key to change color, RIGHT key to increase speed, LEFT key to decrease speed. View more at [unklnik.com](https://unklnik.com/posts/2d-animated-character/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/0e6a2449-4388-45ee-9b14-31c2f070ee3c 7 | -------------------------------------------------------------------------------- /2D_Beginner/animated_character/anim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Beginner/animated_character/anim.png -------------------------------------------------------------------------------- /2D_Beginner/animated_character/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | rl "github.com/gen2brain/raylib-go/raylib" 5 | ) 6 | 7 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 8 | 9 | https://github.com/unklnik/raylib-go-more-examples 10 | 11 | */ 12 | 13 | var ( 14 | anim rl.Texture2D //TEXTURE TO LOAD IMAGE 15 | animFrames = float32(4) //5 FRAMES IN IMAGE SUBTRACT ONE AS COUNT STARTS FROM ZERO 16 | animFrameWidth = float32(16) //16X16 RECTANGLE OF EACH FRAME 17 | currentAnimFrameNum float32 //THE NUMBER OF THE FRAME TO DRAW 18 | animDrawRec rl.Rectangle //THE PART OF THE IMAGE TEXTURE TO DRAW IN EACH FRAME 19 | animX float32 //LEFT X VALUE OF FIRST FRAME 20 | animColor = rl.White //COLOUR IMAGE IS DRAWN 21 | animSpeed = 6 //FRAMES BETWEEN ANIM CHANGES 22 | cntr rl.Vector2 //CENTER OF SCREEN 23 | frames int //FRAME COUNT OF GAME 24 | fps = int32(60) //FRAMES PER SECOND OF GAME 25 | ) 26 | 27 | func main() { 28 | 29 | rl.InitWindow(0, 0, "animated character - raylib go - https://github.com/unklnik/raylib-go-more-examples") 30 | scrW, scrH := rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 31 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 32 | 33 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 34 | 35 | cntr = rl.NewVector2(float32(scrW/2), float32(scrH/2)) //CENTER OF SCREEN 36 | 37 | anim = rl.LoadTexture("anim.png") //LOAD THE IMAGE FILE 38 | animDrawRec = rl.NewRectangle(0, 0, animFrameWidth, animFrameWidth) //DEFINE FRAME 1 (ZERO) RECTANGLE 39 | animX = animDrawRec.X //SET THE HOLDER VARIABLE TO THE FIRST FRAME REC X VALUE 40 | 41 | camera := rl.Camera2D{} // DEFINES THE CAMERA 42 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 43 | 44 | rl.SetTargetFPS(fps) // NUMBER OF FRAMES DRAWN IN A SECOND 45 | 46 | for !rl.WindowShouldClose() { 47 | 48 | frames++ //INCREASE FRAME COUNTER ONCE PER FRAME DRAWN 49 | 50 | //IF NUMBER OF FRAMES DIVIDES EXACLTY BY ANIM SPEED CHANGE CURRENT ANIM FRAME NUM 51 | if frames%animSpeed == 0 { 52 | currentAnimFrameNum++ 53 | if currentAnimFrameNum > float32(animFrames) { //SET TO ZERO IF REACHES MAX FRAMES 54 | currentAnimFrameNum = 0 55 | animDrawRec.X = animX //RETURN DRAW REC X TO FIRST FRAME X 56 | } 57 | } 58 | 59 | /*MOVE THE DRAW RECTANGLE BY MULTIPLYING CURRENT FRAME NUM BY ANIM REC WIDTH. AS THE ANIM STARTS AT (0,0) WHEN CURRENT FRAME IS 0 ANIM REC X WILL ALSO BE ZERO. HOWEVER USING animX IS A BETTER METHOD WHEN YOU ARE WORKING WITH MANY IMAGES */ 60 | animDrawRec.X = currentAnimFrameNum * animFrameWidth 61 | 62 | if rl.IsKeyPressed(rl.KeyRight) { //INCREASE SPEED 63 | if animSpeed > 4 { 64 | animSpeed -= 2 65 | } 66 | } else if rl.IsKeyPressed(rl.KeyLeft) { //DECREASE SPEED 67 | if animSpeed < 30 { 68 | animSpeed += 2 69 | } 70 | } 71 | 72 | if rl.IsKeyPressed(rl.KeyUp) { //CHANGE ZOOM 73 | if camera.Zoom == 1 { 74 | camera.Zoom = 1.5 75 | } else if camera.Zoom == 1.5 { 76 | camera.Zoom = 2 77 | } else if camera.Zoom == 2 { 78 | camera.Zoom = 1 79 | } 80 | 81 | //ADJUST CAMERA TO CENTER IMAGE AFTER CHANGE IN ZOOM 82 | camera.Target = cntr 83 | camera.Offset.X = float32(scrW / 2) 84 | camera.Offset.Y = float32(scrH / 2) 85 | } 86 | 87 | if rl.IsKeyPressed(rl.KeyDown) { //CHANGE COLOR 88 | if animColor == rl.White { 89 | animColor = rl.Magenta 90 | } else if animColor == rl.Magenta { 91 | animColor = rl.Green 92 | } else if animColor == rl.Green { 93 | animColor = rl.Orange 94 | } else if animColor == rl.Orange { 95 | animColor = rl.SkyBlue 96 | } else if animColor == rl.SkyBlue { 97 | animColor = rl.White 98 | } 99 | } 100 | 101 | rl.BeginDrawing() 102 | 103 | rl.ClearBackground(rl.Black) 104 | 105 | rl.BeginMode2D(camera) 106 | 107 | //CHANGE THIS FOR SMALLER/LARGER IMAGE 108 | size := float32(64) 109 | //THE RECTANGLE THAT DRAWS TO SCREEN 110 | destRec := rl.NewRectangle(cntr.X-size/2, cntr.Y-size/2, size, size) 111 | //DRAW TO SCREEN 112 | rl.DrawTexturePro(anim, animDrawRec, destRec, rl.Vector2Zero(), 0, animColor) 113 | 114 | /* NOTE THIS METHOD IS NOT TO BE USED FOR IMAGES THAT ROTATE AS THE ORIGIN IS SET AS THE TOP LEFT CORNER Vector2Zero() MEANS TOP LEFT OF IMAGE (0,0) AND THE IMAGE WILL ROTATE AROUND THIS POINT */ 115 | 116 | rl.EndMode2D() 117 | 118 | rl.DrawText("UP key to change zoom", 10, 10, 10, rl.White) 119 | rl.DrawText("DOWN key to change color", 10, 24, 10, rl.White) 120 | rl.DrawText("RIGHT key to increase speed", 10, 38, 10, rl.White) 121 | rl.DrawText("LEFT key to decrease speed", 10, 52, 10, rl.White) 122 | 123 | rl.EndDrawing() 124 | } 125 | 126 | rl.CloseWindow() 127 | } 128 | -------------------------------------------------------------------------------- /2D_Beginner/exploding_blocks/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - SIMPLE EXPLODING BLOCKS 3 | 4 | Easy way to create the effect of blocks exploding using slices of block structs that contain fade, color, rectangles and movement direction. SPACE key to explode blocks and then wait for the timer to end which will reset the animation. View more at [unklnik.com](https://unklnik.com/posts/2d-exploding-blocks/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/0f820da2-91d3-463c-bb9f-19e8d407b031 7 | -------------------------------------------------------------------------------- /2D_Beginner/exploding_blocks/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | 7 | rl "github.com/gen2brain/raylib-go/raylib" 8 | ) 9 | 10 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 11 | 12 | https://github.com/unklnik/raylib-go-more-examples 13 | 14 | */ 15 | 16 | var ( 17 | bloks []blok //SLICE OF BLOKS SEE STRUCT BELOW 18 | blokbits []blok //SLICE OF BLOK PIECES WHEN EXPLODING 19 | size = float32(32) //GRID RECTANGLE WIDTH & HEIGHT 20 | fps = int32(60) //FRAMES PER SECOND 21 | timer int32 //EXPLOSION TIMER 22 | scrW, scrH int //SCREEN WIDTH & HEIGHT 23 | ) 24 | 25 | type blok struct { // BLOK STRUCT 26 | col rl.Color //COLOR 27 | cnt rl.Vector2 //CENTER 28 | rec rl.Rectangle //RECTANGLE 29 | fade, velX, velY float32 //OPACITY MOVEMENT SPEED X & Y 30 | } 31 | 32 | func main() { 33 | 34 | rl.InitWindow(0, 0, "exploding blocks - raylib go - https://github.com/unklnik/raylib-go-more-examples") 35 | scrW, scrH = rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 36 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 37 | 38 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 39 | 40 | makebloks() //MAKE INITIAL BLOCKS 41 | 42 | camera := rl.Camera2D{} // DEFINES THE CAMERA 43 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 44 | 45 | rl.SetTargetFPS(fps) // NUMBER OF FRAMES DRAWN IN A SECOND 46 | 47 | for !rl.WindowShouldClose() { 48 | 49 | if rl.IsKeyPressed(rl.KeySpace) && timer == 0 { // KEY TO EXPLODE 50 | explode() 51 | timer = fps + fps/2 //SET TIMER TO 1 AND A HALF SECONDS 52 | } 53 | 54 | if timer > 0 { //COUNTDOWN TIMER 55 | timer-- 56 | if timer == 1 { //MAKE NEW BLOCKS 57 | makebloks() 58 | } 59 | } 60 | 61 | rl.BeginDrawing() 62 | 63 | rl.ClearBackground(rl.Black) 64 | 65 | rl.BeginMode2D(camera) 66 | 67 | if timer > 0 { // IF TIMER IS LARGER THAN ZERO DRAW EXPLOSION PIECES 68 | for i := 0; i < len(blokbits); i++ { //DRAWS THE LIST OF BLOCKS 69 | rl.DrawRectangleRec(blokbits[i].rec, rl.Fade(blokbits[i].col, blokbits[i].fade)) 70 | if blokbits[i].fade > 0 { 71 | blokbits[i].fade -= 0.01 //FADE OUT EXPLOSION PIECES 72 | blokbits[i].rec.X += blokbits[i].velX //MOVE X EXPLOSION PIECES 73 | blokbits[i].rec.Y += blokbits[i].velY //MOVE Y EXPLOSION PIECES 74 | } 75 | } 76 | rl.DrawText("time till blocks respawn: "+fmt.Sprint(timer), 10, 10, 10, rl.White) 77 | } else { // IF TIMER IS ZERO DRAW BLOCKS 78 | for i := 0; i < len(bloks); i++ { //DRAWS THE LIST OF BLOCKS 79 | rl.DrawRectangleRec(bloks[i].rec, bloks[i].col) 80 | } 81 | rl.DrawText("press SPACE key to explode", 10, 10, 10, rl.White) 82 | } 83 | 84 | rl.EndMode2D() 85 | 86 | rl.EndDrawing() 87 | } 88 | 89 | rl.CloseWindow() 90 | } 91 | 92 | func makebloks() { //MAKES THE BLOCKS THAT EXPLODE 93 | bloks = nil //CLEARS THE SLICE 94 | num := rInt(4, 8) //RANDOM NUMBER OF BLOCKS 95 | for num > 0 { 96 | newBlok := blok{} 97 | newBlok.col = ranCol() //RANDOM COLOR SEE FUNCTION BELOW 98 | siz := rF32(64, 256) //RANDOM SIZE 99 | newBlok.rec = rl.NewRectangle(rF32(0, float32(scrW)-siz), rF32(0, float32(scrH)-siz), siz, siz) 100 | newBlok.cnt = rl.NewVector2(newBlok.rec.X+siz/2, newBlok.rec.Y+siz/2) //CENTER FOR EXPLOSION PIECES 101 | bloks = append(bloks, newBlok) //ADD TO SLICE 102 | num-- 103 | } 104 | } 105 | func explode() { //MAKES THE EXPLOSION PIECES 106 | 107 | blokbits = nil 108 | for i := 0; i < len(bloks); i++ { 109 | 110 | num := rInt(15, 25) //RANDOM NUMBER OF EXPLOSION PIECES 111 | for num > 0 { 112 | newBlok := blok{} 113 | newBlok.col = ranCol() 114 | siz := rF32(8, 32) //RANDOM SIZE SMALLER THAN BLOCK 115 | //MAKE THE RECTANGLE USING THE CENTER OF THE INITIAL BLOCK 116 | newBlok.rec = rl.NewRectangle(bloks[i].cnt.X-siz/2, bloks[i].cnt.Y-siz/2, siz, siz) 117 | newBlok.fade = rF32(0.5, 0.8) //RANDOM OPACITY 118 | newBlok.velX = rF32(-32, 32) //RANDOM X MOVEMENT 119 | newBlok.velY = rF32(-32, 32) //RANDOM X MOVEMENT 120 | blokbits = append(blokbits, newBlok) 121 | num-- 122 | } 123 | 124 | } 125 | 126 | } 127 | 128 | // RETURNS A RANDOM COLOR 129 | func ranCol() rl.Color { 130 | return rl.NewColor(uint8(rInt(0, 256)), uint8(rInt(0, 256)), uint8(rInt(0, 256)), 255) 131 | } 132 | 133 | // RETURNS A RANDOM INTEGER FOR USE IN RANDOM COLOR ABOVE 134 | func rInt(min, max int) int { 135 | return min + rand.Intn(max-min) 136 | } 137 | func rF32(min, max float32) float32 { 138 | min2 := float64(min) 139 | max2 := float64(max) 140 | return float32(min2 + rand.Float64()*(max2-min2)) 141 | } 142 | -------------------------------------------------------------------------------- /2D_Beginner/pixel_noise/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - PIXEL NOISE (ARTIFACTS) 3 | 4 | Simulates pixel noise, or old movie-type screen artifacts, with color and size change. View more at [unklnik.com](https://unklnik.com/posts/2d-pixel-noise/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/ef451fcf-9322-4ea9-99ff-4aa2ecd63b52 7 | -------------------------------------------------------------------------------- /2D_Beginner/pixel_noise/gopher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Beginner/pixel_noise/gopher.png -------------------------------------------------------------------------------- /2D_Beginner/pixel_noise/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math/rand" 5 | 6 | rl "github.com/gen2brain/raylib-go/raylib" 7 | ) 8 | 9 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 10 | 11 | https://github.com/unklnik/raylib-go-more-examples 12 | 13 | */ 14 | 15 | var ( 16 | cnt rl.Vector2 //SCREEN CENTER 17 | noiseColor = rl.Black //INITIAL PIXEL REC COLOR 18 | backColor = rl.White //INITIAL BACKGROUND COLOR 19 | backRec rl.Rectangle //RECTANGLE FOR THE BACKGROUND COLOR 20 | noiseLevel = float32(4) //INITIAL MAX SIZE LIMIT USED TO GENERATE RANDOM PIXEL NOISE REC 21 | noiseMax = float32(10) //MAX SIZE LIMIT OF PIXEL NOISE REC 22 | noiseMin = float32(2) //MIN SIZE LIMIT OF PIXEL NOISE REC 23 | ) 24 | 25 | func main() { 26 | 27 | rl.InitWindow(0, 0, "pixel noise - raylib go - https://github.com/unklnik/raylib-go-more-examples") 28 | scrW, scrH := rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 29 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 30 | 31 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 32 | 33 | cnt = rl.NewVector2(float32(scrW/2), float32(scrH/2)) //DEFINE SCREEN CENTER 34 | 35 | camera := rl.Camera2D{} // DEFINES THE CAMERA 36 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 37 | 38 | texture := rl.LoadTexture("gopher.png") //LOAD GOPHER IMAGE 39 | 40 | backRec = rl.NewRectangle(0, 0, float32(scrW), float32(scrH)) //DEFINE BACKGROUND RECTANGLE 41 | 42 | rl.SetTargetFPS(60) // NUMBER OF FRAMES DRAWN IN A SECOND 43 | 44 | for !rl.WindowShouldClose() { 45 | 46 | if rl.IsKeyDown(rl.KeyLeft) { //DECREASE SIZE LIMIT USED TO GENERATE RANDOM PIXEL REC 47 | if noiseLevel > noiseMin { 48 | noiseLevel -= 0.05 49 | } 50 | } else if rl.IsKeyDown(rl.KeyRight) { //INCREASE SIZE LIMIT USED TO GENERATE RANDOM PIXEL REC 51 | if noiseLevel < noiseMax { 52 | noiseLevel += 0.05 53 | } 54 | } 55 | 56 | if rl.IsKeyPressed(rl.KeyUp) { //SWITCH COLORS PIXEL NOISE 57 | if noiseColor == rl.Black { 58 | noiseColor = rl.Red 59 | } else if noiseColor == rl.Red { 60 | noiseColor = rl.Green 61 | } else if noiseColor == rl.Green { 62 | noiseColor = rl.SkyBlue 63 | } else if noiseColor == rl.SkyBlue { 64 | noiseColor = rl.Magenta 65 | } else if noiseColor == rl.Magenta { 66 | noiseColor = rl.White 67 | } else if noiseColor == rl.White { 68 | noiseColor = rl.Black 69 | } 70 | } 71 | 72 | if rl.IsKeyPressed(rl.KeyDown) { //SWITCH COLORS BACKGROUND COLOR 73 | if backColor == rl.Black { 74 | backColor = rl.Red 75 | } else if backColor == rl.Red { 76 | backColor = rl.Green 77 | } else if backColor == rl.Green { 78 | backColor = rl.SkyBlue 79 | } else if backColor == rl.SkyBlue { 80 | backColor = rl.Magenta 81 | } else if backColor == rl.Magenta { 82 | backColor = rl.White 83 | } else if backColor == rl.White { 84 | backColor = rl.Black 85 | } 86 | } 87 | 88 | rl.BeginDrawing() 89 | 90 | rl.ClearBackground(rl.RayWhite) 91 | 92 | rl.BeginMode2D(camera) 93 | 94 | rl.DrawRectangleRec(backRec, backColor) //DRAW BACKGROUND RECTANGLE 95 | 96 | //DRAW GOPHER IMAGE 97 | rl.DrawTexture(texture, int32(cnt.X)-texture.Width/2, int32(cnt.Y)-texture.Height/2, rl.White) 98 | 99 | rl.EndMode2D() 100 | 101 | //DRAW PIXELS OUTSIDE OF CAMERA MODE 2D THEREFORE WILL DISPLAY THE SAME ON ZOOM CHANGE 102 | num := 100 //NUMBER OF PIXEL NOISE RECS TO DRAW PER FRAME 103 | for num > 0 { 104 | size := rF32(1, noiseLevel) // RANDOM REC SIZE RF32 FUNCTION BELOW 105 | //DEFINE REC 106 | rec := rl.NewRectangle(rF32(0, float32(scrW)), rF32(0, float32(scrH)), size, size) 107 | rl.DrawRectangleRec(rec, noiseColor) //DRAW RECTANGLE 108 | num-- 109 | } 110 | 111 | rl.DrawText("UP ARROW KEY CHANGE PIXEL NOISE COLOR", 8, 12, 20, rl.White) 112 | rl.DrawText("UP ARROW KEY CHANGE PIXEL NOISE COLOR", 9, 11, 20, rl.Black) 113 | rl.DrawText("UP ARROW KEY CHANGE PIXEL NOISE COLOR", 10, 10, 20, rl.Blue) 114 | 115 | rl.DrawText("DOWN ARROW KEY CHANGE BACKGROUND COLOR", 8, 42, 20, rl.White) 116 | rl.DrawText("DOWN ARROW KEY CHANGE BACKGROUND COLOR", 9, 41, 20, rl.Black) 117 | rl.DrawText("DOWN ARROW KEY CHANGE BACKGROUND COLOR", 10, 40, 20, rl.Blue) 118 | 119 | rl.DrawText("RIGHT LEFT ARROW KEYS INCREASE DECREASE SIZE", 8, 72, 20, rl.White) 120 | rl.DrawText("RIGHT LEFT ARROW KEYS INCREASE DECREASE SIZE", 9, 71, 20, rl.Black) 121 | rl.DrawText("RIGHT LEFT ARROW KEYS INCREASE DECREASE SIZE", 10, 70, 20, rl.Blue) 122 | 123 | rl.EndDrawing() 124 | } 125 | 126 | rl.UnloadTexture(texture) //UNLOAD FROM MEMORY 127 | 128 | rl.CloseWindow() 129 | } 130 | 131 | // RETURNS A RANDOM FLOAT32 VALUE BETWEEN MIN/MAX RANGE 132 | func rF32(min, max float32) float32 { 133 | min2 := float64(min) 134 | max2 := float64(max) 135 | return float32(min2 + rand.Float64()*(max2-min2)) 136 | } 137 | -------------------------------------------------------------------------------- /2D_Beginner/random_color_grid/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - RANDOM COLOR GRID BLOCKS 3 | 4 | Quick way to create colorful background of randomly colored blocks using a slice of structs to store the color and position information. Try changing color fade, outline, rectangle size and use textures to achieve different effects. Using the same or similar colours or textures can be used to create a simple tiled background. View more at [unklnik.com](https://unklnik.com/posts/2d-random-color-grid/) 5 | 6 | ![random_color_grid](https://github.com/unklnik/raylib-go-more-examples/assets/146096950/7fd73f56-9355-41d2-8eea-4ff94f68a130) 7 | -------------------------------------------------------------------------------- /2D_Beginner/random_color_grid/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math/rand" 5 | 6 | rl "github.com/gen2brain/raylib-go/raylib" 7 | ) 8 | 9 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 10 | 11 | https://github.com/unklnik/raylib-go-more-examples 12 | 13 | */ 14 | 15 | var ( 16 | bloks []blok //SLICE OF BLOKS SEE STRUCT BELOW 17 | size = float32(32) //GRID RECTANGLE WIDTH & HEIGHT 18 | ) 19 | 20 | type blok struct { // BLOK STRUCTS THAT CONTAIN THE COLOR & POSITION 21 | col rl.Color 22 | rec rl.Rectangle 23 | } 24 | 25 | func main() { 26 | 27 | rl.InitWindow(0, 0, "grid random colors - raylib go - https://github.com/unklnik/raylib-go-more-examples") 28 | scrW, scrH := rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 29 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 30 | 31 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 32 | 33 | x := float32(0) 34 | y := float32(0) 35 | for { 36 | newBlok := blok{} //CREATES AN EMPTY BLOK 37 | newBlok.col = ranCol() //ASSIGNS A RANDOM COLOR 38 | newBlok.rec = rl.NewRectangle(x, y, size, size) //CREATES A REC AT X,Y WITH SIZE X SIZE 39 | bloks = append(bloks, newBlok) //ADDS NEW BLOK TO SLICE 40 | 41 | x += size //MOVES X BY SIZE 42 | if x >= float32(scrW) { //IF X LARGER THAN OR EQUALS SCREEN WIDTH GO BACK TO ZERO 43 | x = 0 44 | y += size //MOVE Y DOWN ONE LINE 45 | } 46 | 47 | if y >= float32(scrH) { //IF Y LARGER THAN OR EQUALS SCREEN HEIGHT END 48 | break 49 | } 50 | } 51 | 52 | camera := rl.Camera2D{} // DEFINES THE CAMERA 53 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 54 | 55 | rl.SetTargetFPS(60) // NUMBER OF FRAMES DRAWN IN A SECOND 56 | 57 | for !rl.WindowShouldClose() { 58 | 59 | rl.BeginDrawing() 60 | 61 | rl.ClearBackground(rl.Black) 62 | 63 | rl.BeginMode2D(camera) 64 | 65 | for a := 0; a < len(bloks); a++ { //DRAWS THE LIST OF BLOCKS 66 | rl.DrawRectangleRec(bloks[a].rec, bloks[a].col) 67 | } 68 | 69 | rl.EndMode2D() 70 | 71 | rl.EndDrawing() 72 | } 73 | 74 | rl.CloseWindow() 75 | } 76 | 77 | // RETURNS A RANDOM COLOR 78 | func ranCol() rl.Color { 79 | return rl.NewColor(uint8(rInt(0, 256)), uint8(rInt(0, 256)), uint8(rInt(0, 256)), 255) 80 | } 81 | 82 | // RETURNS A RANDOM INTEGER FOR USE IN RANDOM COLOR ABOVE 83 | func rInt(min, max int) int { 84 | return min + rand.Intn(max-min) 85 | } 86 | -------------------------------------------------------------------------------- /2D_Beginner/rec_collisions/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - COLLISION RECTANGLES 3 | 4 | Demonstrates how to check for collisions of moving rectangles against other moving rectangles as well as border rectangles. This method uses *rl.CheckCollisionRecs* and creates a duplicate rectangle which is then moved to the next position of the moving rectangle. If this next rectangle collides then the direction is changed. Checking for collisions with the **next** movement position, as opposed to the moving rectangle itself, prevents problems with rectangles intersecting. When using the moving rectangle itself, when the collision is reported as having happened, the rectangles are already intersecting which can cause problems. View more at [unklnik.com](https://unklnik.com/posts/2d-rectangle-collisions/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/5773316b-27bd-4a98-b00d-f202be00dc3c 7 | -------------------------------------------------------------------------------- /2D_Beginner/rec_collisions/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math/rand" 5 | 6 | rl "github.com/gen2brain/raylib-go/raylib" 7 | ) 8 | 9 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 10 | 11 | https://github.com/unklnik/raylib-go-more-examples 12 | 13 | */ 14 | 15 | var ( 16 | velX, velY float32 //X & Y MOVEMENT SPEED 17 | maxVel = float32(10) //MAX SPEED FOR USE IN RANDOM GENERATOR 18 | borderRec rl.Rectangle //BOUNCING & BORDER RECTANGLES 19 | cntr rl.Vector2 //CENTER OF SCREEN 20 | bounceRecs, borderRecs []rl.Rectangle //SLICES OF BOUNCE & BORDER RECTANGLES 21 | bounceV2 []rl.Vector2 //X & Y MOVE SPEED OF BOUNCE RECTNAGLES 22 | spd = float32(16) //MAX SPEED 23 | ) 24 | 25 | func main() { 26 | 27 | rl.InitWindow(0, 0, "rectangle collisions - raylib go - https://github.com/unklnik/raylib-go-more-examples") 28 | scrW, scrH := rl.GetScreenWidth(), rl.GetScreenHeight() //GET SCREEN SIZES 29 | rl.SetWindowSize(scrW, scrH) //SET WINDOW SIZE 30 | rl.SetWindowState(rl.FlagBorderlessWindowedMode) 31 | //rl.ToggleFullscreen() //UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 32 | 33 | cntr = rl.NewVector2(float32(scrW/2), float32(scrH/2)) //CALCULATE CENTER 34 | 35 | borderRec = rl.NewRectangle(cntr.X-float32(scrW/4), cntr.Y-float32(scrH/4), float32(scrW/2), float32(scrH/2)) //DEFINE BORDER RECTANGLE 36 | 37 | //CREATE 4 RECTANGLES AT EACH SIDE OF BORDER RECTANGLE TO CHECK FOR COLLISIONS AGAINST 38 | borderRecs = append(borderRecs, rl.NewRectangle(borderRec.X, borderRec.Y-10, borderRec.Width, 10)) 39 | borderRecs = append(borderRecs, rl.NewRectangle(borderRec.X, borderRec.Y+borderRec.Height, borderRec.Width, 10)) 40 | borderRecs = append(borderRecs, rl.NewRectangle(borderRec.X-10, borderRec.Y, 10, borderRec.Height)) 41 | borderRecs = append(borderRecs, rl.NewRectangle(borderRec.X+borderRec.Width, borderRec.Y, 10, borderRec.Height)) 42 | 43 | //CREATE 4 BOUNCE RECTANGLES AT EACH SIDE OF THE BORDER RECTANGLE RF32 FUNCTION SEE BELOW 44 | siz := float32(64) 45 | bounceRecs = append(bounceRecs, rl.NewRectangle(borderRec.X+siz+rF32(0, borderRec.Width-siz*2), borderRec.Y, siz, siz)) 46 | bounceRecs = append(bounceRecs, rl.NewRectangle(borderRec.X+siz+rF32(0, borderRec.Width-siz*2), borderRec.Y+borderRec.Height-siz, siz, siz)) 47 | bounceRecs = append(bounceRecs, rl.NewRectangle(borderRec.X, borderRec.Y+siz+rF32(0, borderRec.Height-siz*2), siz, siz)) 48 | bounceRecs = append(bounceRecs, rl.NewRectangle(borderRec.X+borderRec.Width-siz, borderRec.Y+siz+rF32(0, borderRec.Height-siz*2), siz, siz)) 49 | 50 | //CREATE 4 VECTOR 2 TO STORE X & Y MOVEMEMENT SPEED 51 | bounceV2 = append(bounceV2, rl.NewVector2(rF32(-spd, spd), rF32(-spd, spd))) 52 | bounceV2 = append(bounceV2, rl.NewVector2(rF32(-spd, spd), rF32(-spd, spd))) 53 | bounceV2 = append(bounceV2, rl.NewVector2(rF32(-spd, spd), rF32(-spd, spd))) 54 | bounceV2 = append(bounceV2, rl.NewVector2(rF32(-spd, spd), rF32(-spd, spd))) 55 | 56 | //SEE RF32 FUNCTION END OF CODE FINDS A RANDOM FLOAT32 BETWEEN TWO VALUES 57 | velX = rF32(-maxVel, maxVel) //FINDS A RANDOM X AXIS MOVEMENT SPEED 58 | velY = rF32(-maxVel, maxVel) //FINDS A RANDOM Y AXIS MOVEMENT SPEED 59 | 60 | camera := rl.Camera2D{} //DEFINES THE CAMERA 61 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 62 | 63 | rl.SetTargetFPS(60) //NUMBER OF FRAMES DRAWN IN A SECOND 64 | 65 | for !rl.WindowShouldClose() { 66 | 67 | checkCollisionsMove() //SEE FUNCTION BELOW - CHECKS FOR BORDER COLLISIONS & MOVES 68 | 69 | rl.BeginDrawing() 70 | 71 | rl.ClearBackground(rl.Black) 72 | 73 | rl.BeginMode2D(camera) 74 | 75 | rl.DrawRectangleLinesEx(borderRec, 4, rl.Green) //DRAWS BORDER REC 76 | 77 | //DRAWS THE BOUNCE RECTANGLES IN THE SLICE 78 | for i := 0; i < len(bounceRecs); i++ { 79 | rl.DrawRectangleLinesEx(bounceRecs[i], 4, rl.Green) 80 | } 81 | 82 | rl.EndMode2D() 83 | 84 | rl.EndDrawing() 85 | } 86 | 87 | rl.CloseWindow() 88 | } 89 | 90 | // CHECKS FOR BOUNCE REC COLLISIONS & MOVES BOUNCE RECS 91 | func checkCollisionsMove() { 92 | 93 | for i := 0; i < len(bounceRecs); i++ { 94 | 95 | //CREATING DUPLICATE RECTANGLE FOR NEXT MOVE PREVENTS PROBLEMS WITH INTERSECTING RECTANGLES IF USING THE RECTANGLE ITSELF AS THEN IT WILL ONLY RETURN A COLLISION ONCE IT HAS ALREADY HAPPENED 96 | 97 | canmove := true 98 | checkRec := bounceRecs[i] //DUPLICATE THE RECTANGLE 99 | checkRec.X += bounceV2[i].X //MOVE THE DUPLICATE BY X SPEED 100 | checkRec.Y += bounceV2[i].Y //MOVE THE DUPLICATE BY X SPEED 101 | 102 | //CHECK FOR COLLISIONS WITH DUPLICATE 103 | for j := 0; j < len(borderRecs); j++ { 104 | if rl.CheckCollisionRecs(checkRec, borderRecs[j]) { 105 | canmove = false 106 | break 107 | } 108 | } 109 | 110 | //IF NO COLLISIONS WITH BORDER THEN CHECK FOR COLLISIONS WITH OTHER BOUNCE RECTANGLES 111 | if canmove { 112 | for j := 0; j < len(bounceRecs); j++ { 113 | if i != j { 114 | if rl.CheckCollisionRecs(checkRec, bounceRecs[j]) { 115 | canmove = false 116 | break 117 | } 118 | } 119 | } 120 | } 121 | 122 | if canmove { 123 | //IF CAN MOVE THEN MOVE THE RECTANGLE ITSELF 124 | bounceRecs[i].X += bounceV2[i].X 125 | bounceRecs[i].Y += bounceV2[i].Y 126 | } else { 127 | //IF CANNOT MOVE THEN MOVE IN THE OPPOSITE DIRECTION AT A NEW RANDOM SPEED 128 | if bounceV2[i].X > 0 { 129 | bounceV2[i].X = rF32(-spd, -spd/4) 130 | } else { 131 | bounceV2[i].X = rF32(spd/4, spd) 132 | } 133 | if bounceV2[i].Y > 0 { 134 | bounceV2[i].Y = rF32(-spd, -spd/4) 135 | } else { 136 | bounceV2[i].Y = rF32(spd/4, spd) 137 | } 138 | } 139 | 140 | } 141 | 142 | } 143 | 144 | // RETURNS A RANDOM FLOAT32 VALUE WITHIN A RANGE (BETWEEN MIN/MAX VALUES) 145 | func rF32(min, max float32) float32 { 146 | min2 := float64(min) 147 | max2 := float64(max) 148 | return float32(min2 + rand.Float64()*(max2-min2)) 149 | } 150 | -------------------------------------------------------------------------------- /2D_Beginner/room_tiles/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - ROOM TILES 3 | 4 | Creates a randomly sized room and draws tile textures for the walls and floor with camera zoom and random color tiles. UP arrow key to change zoom and SPACE key to create a new room. View more at [unklnik.com](https://unklnik.com/posts/2d-room-tiles/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/539dc196-7344-4196-917b-3fac8aa98d12 7 | -------------------------------------------------------------------------------- /2D_Beginner/room_tiles/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | 7 | rl "github.com/gen2brain/raylib-go/raylib" 8 | ) 9 | 10 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 11 | 12 | https://github.com/unklnik/raylib-go-more-examples 13 | 14 | */ 15 | 16 | var ( 17 | tiles rl.Texture2D //IMG TEXTURE WITH TILES 18 | size = float32(32) //TILE SIZE CHANGE FOR LARGER/SMALLER IMG DISPLAY SIZE 19 | cnt rl.Vector2 //SCREEN CENTER VECTOR2 20 | 21 | /* DEFINES RECTANGLE OF FLOOR IMAGE IN tiles.png THIS DETERMINES WHAT PART OF THE TILES IMAGE TEXTURE TO DISPLAY WHEN A RECTANGLE IS DRAWN (0,0,16,16) MEANS X=0 Y=0 WIDTH=16 pixels HEIGHT=16 pixels THEREFORE WILL SEARCH FOR RECTANGLE AT COORDINATES 0,0 (X,Y) AND DRAW A RECTANGLE AT THOSE COORDINATES TO THE SCREEN OF 16X16 SCALED UP TO SIZE */ 22 | floorTile = rl.NewRectangle(0, 0, 16, 16) 23 | 24 | wallTile = rl.NewRectangle(0, 16, 16, 16) // DEFINES RECTANGLE OF FLOOR IMAGE 25 | roomRec rl.Rectangle //SIZE OF ROOM 26 | wallColor, floorColor rl.Color //COLORS OF WALL & FLOOR TILES 27 | ) 28 | 29 | func main() { 30 | 31 | rl.InitWindow(0, 0, "room tiles - raylib go - https://github.com/unklnik/raylib-go-more-examples") 32 | scrW, scrH := rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 33 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 34 | 35 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 36 | 37 | cnt = rl.NewVector2(float32(scrW/2), float32(scrH/2)) //FIND SCREEN CENTER 38 | 39 | camera := rl.Camera2D{} // DEFINES THE CAMERA 40 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 41 | 42 | tiles = rl.LoadTexture("tiles.png") //LOAD IMAGES FROM FILE 43 | 44 | makeRoom() //MAKE INITIAL ROOM SEE FUNCTION AT END OF CODE 45 | 46 | rl.SetTargetFPS(60) // NUMBER OF FRAMES DRAWN IN A SECOND 47 | 48 | for !rl.WindowShouldClose() { 49 | 50 | if rl.IsKeyPressed(rl.KeyUp) { //CHANGE CAMERA ZOOM KEYS 51 | if camera.Zoom == 0.5 { 52 | camera.Zoom = 1 53 | } else if camera.Zoom == 1 { 54 | camera.Zoom = 1.5 55 | } else if camera.Zoom == 1.5 { 56 | camera.Zoom = 2 57 | } else if camera.Zoom == 2 { 58 | camera.Zoom = 0.5 59 | } 60 | 61 | camera.Target = cnt //SET THE CAMERA TARGET TO CENTER 62 | camera.Offset.X = float32(scrW / 2) //ADJUST FOR ZOOM 63 | camera.Offset.Y = float32(scrH / 2) //ADJUST FOR ZOOM 64 | } 65 | 66 | if rl.IsKeyPressed(rl.KeySpace) { //MAKE A NEW ROOM IF SPACE KEY IS PRESSED 67 | makeRoom() 68 | } 69 | 70 | rl.BeginDrawing() 71 | 72 | rl.ClearBackground(rl.Black) 73 | 74 | rl.BeginMode2D(camera) 75 | 76 | //DRAW FLOOR TILES 77 | x := roomRec.X + size //SET X TO ROOM RECTANGLE LEFT PLUS SIZE OF WALL 78 | y := roomRec.Y + size //SET Y TO ROOM RECTANGLE TOP PLUS SIZE OF WALL 79 | for { 80 | rl.DrawTexturePro(tiles, floorTile, rl.NewRectangle(x, y, size, size), rl.Vector2Zero(), 0, rl.Fade(floorColor, 0.2)) //DRAW FLOOR TILE 81 | 82 | x += size //MOVE 1 TILE FORWARD 83 | 84 | //IF X REACHES BORDER OF RIGHT WALL X RETURNS TO START X POSITION & Y MOVES DOWN 1 TILE 85 | if x >= roomRec.X+roomRec.Width-size { 86 | x = roomRec.X + size 87 | y += size 88 | } 89 | 90 | //IF Y REACHES BORDER OF BOTTOM WALL STOP DRAWING FLOOR TILES 91 | if y >= roomRec.Y+roomRec.Height-size { 92 | break 93 | } 94 | } 95 | 96 | x = roomRec.X //SET X TO ROOM RECTANGLE LEFT 97 | y = roomRec.Y //SET X TO ROOM RECTANGLE TOP 98 | 99 | //DRAW TOP & BOTTOM WALLS 100 | for { 101 | //DRAW TOP WALL 102 | rl.DrawTexturePro(tiles, wallTile, rl.NewRectangle(x, y, size, size), rl.Vector2Zero(), 0, wallColor) 103 | 104 | //DRAW BOTTOM WALL ADD (roomRec.Height-size) TO y 105 | rl.DrawTexturePro(tiles, wallTile, rl.NewRectangle(x, y+(roomRec.Height-size), size, size), rl.Vector2Zero(), 0, wallColor) 106 | 107 | x += size //MOVE 1 TILE FORWARD 108 | 109 | //IF X REACHES ROOM RECTANGLE RIGHT BORDER STOP DRAWING 110 | if x >= roomRec.X+roomRec.Width { 111 | break 112 | } 113 | } 114 | 115 | //DRAW LEFT & RIGHT WALLS 116 | x = roomRec.X 117 | y = roomRec.Y + size //MOVE Y 1 TILE DOWN FOR TOP WALL SIZE 118 | 119 | for { 120 | //DRAW LEFT WALL 121 | rl.DrawTexturePro(tiles, wallTile, rl.NewRectangle(x, y, size, size), rl.Vector2Zero(), 0, wallColor) 122 | 123 | //DRAW RIGHT WALL ADD (roomRec.Width-size) to X 124 | rl.DrawTexturePro(tiles, wallTile, rl.NewRectangle(x+(roomRec.Width-size), y, size, size), rl.Vector2Zero(), 0, wallColor) 125 | 126 | y += size //MOVE 1 TILE DOWN 127 | 128 | //IF Y REACHES ROOM RECTANGLE BOTTOM BORDER SUBTRACT BOTTOM WALL SIZE STOP DRAWING 129 | if y >= roomRec.Y+roomRec.Height-size { 130 | break 131 | } 132 | } 133 | 134 | rl.EndMode2D() 135 | 136 | //DRAW TEXT 137 | rl.DrawText("camera zoom "+fmt.Sprintf("%.1f", camera.Zoom)+" press UP ARROW key to change", 10, 10, 20, rl.White) 138 | rl.DrawText("press SPACE key to make a new room", 10, 40, 20, rl.White) 139 | 140 | rl.EndDrawing() 141 | } 142 | 143 | rl.UnloadTexture(tiles) 144 | 145 | rl.CloseWindow() 146 | } 147 | 148 | func makeRoom() { //MAKES ROOM 149 | 150 | wallColor = ranCol() //CHOOSES RANDOM WALL COLOR SEE FUNCTION BELOW 151 | floorColor = ranCol() //CHOOSES RANDOM FLOOR COLOR SEE FUNCTION BELOW 152 | 153 | //SIZE BASED ON RANDOM INTEGER VALUE NUMBER OF TILES MULTIPLIED BY SIZE TO GET PIXEL WIDTH 154 | width := float32(rInt(10, 21)) * size 155 | height := float32(rInt(10, 21)) * size 156 | 157 | //CREATE A CENTRED ROOM RECTANGLE 158 | roomRec = rl.NewRectangle(cnt.X-width/2, cnt.Y-height/2, width, height) 159 | 160 | } 161 | 162 | // RETURNS A RANDOM COLOR 163 | func ranCol() rl.Color { 164 | return rl.NewColor(uint8(rInt(0, 256)), uint8(rInt(0, 256)), uint8(rInt(0, 256)), 255) 165 | } 166 | 167 | // RETURNS A RANDOM INTEGER FOR USE IN RANDOM COLOR ABOVE 168 | func rInt(min, max int) int { 169 | return min + rand.Intn(max-min) 170 | } 171 | -------------------------------------------------------------------------------- /2D_Beginner/room_tiles/tiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Beginner/room_tiles/tiles.png -------------------------------------------------------------------------------- /2D_Beginner/stars_background/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - SIMPLE SPACE BACKGROUND 3 | 4 | Easy way of creating some movement in your background if you are making a space game. Uses rectangles, color fade, random movement and a direction change timer. If you want to use sprites (images) instead then change the rectangles to textures. View more at [unklnik.com](https://unklnik.com/posts/2d-moving-space-background/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/e3a181b4-6205-46ee-a18f-1ae5f18894f5 7 | -------------------------------------------------------------------------------- /2D_Beginner/stars_background/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math/rand" 5 | 6 | rl "github.com/gen2brain/raylib-go/raylib" 7 | ) 8 | 9 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 10 | 11 | https://github.com/unklnik/raylib-go-more-examples 12 | 13 | */ 14 | 15 | var ( 16 | numStars = 200 // NUMBER OF STARS TO DRAW 17 | stars []blok 18 | direc int // DIRECTION 19 | timer int32 // CHANGE DIRECTION TIMER 20 | fps = int32(60) // FRAMES PER SECOND 21 | colorsOn bool // COLORS ON/OFF 22 | scrW, scrH int 23 | maxVel = float32(10) // MAX SPEED FOR DETERMINING X Y MOVEMENT 24 | velX, velY float32 // X Y SPEED 25 | ) 26 | 27 | /* 28 | direc = direction 29 | numbers correspond to direction of stars movement 30 | numbers start at 1 and move clockwise 31 | 32 | for example 2 = UP, 7 = DOWN & LEFT, 3 = UP & RIGHT, 4 = RIGHT 33 | 34 | 1 2 3 35 | 8 4 36 | 7 6 5 37 | 38 | */ 39 | 40 | type blok struct { // BLOK STRUCTS THAT CONTAIN THE COLOR & POSITION 41 | col rl.Color 42 | rec rl.Rectangle 43 | fade float32 44 | } 45 | 46 | func main() { 47 | 48 | rl.InitWindow(0, 0, "stars background - raylib go - https://github.com/unklnik/raylib-go-more-examples") 49 | scrW, scrH = rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 50 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 51 | 52 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 53 | 54 | rl.HideCursor() // HIDES MOUSE CURSOR 55 | makeStars() // FUNCTION MAKE STARS SEE END OF CODE 56 | direc = rInt(1, 9) // CHOOSE INITIAL MOVEMENT DIRECTION 57 | velX = rF32(1, maxVel) // FIND RANDOM X SPEED 58 | velY = rF32(1, maxVel) // FIND RANDOM Y SPEED 59 | timer = rI32(2, 8) * fps // SET TIMER 60 | 61 | camera := rl.Camera2D{} // DEFINES THE CAMERA 62 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 63 | 64 | rl.SetTargetFPS(fps) // NUMBER OF FRAMES DRAWN IN A SECOND 65 | 66 | for !rl.WindowShouldClose() { 67 | 68 | upStars() // FUNCTION TO UPDATE TIMER, MOVEMENT & FADE 69 | 70 | if rl.IsKeyPressed(rl.KeySpace) { 71 | colorsOn = !colorsOn // TURN COLORS ON/OFF WITH SPACE BAR 72 | } 73 | 74 | rl.BeginDrawing() 75 | 76 | rl.ClearBackground(rl.Black) 77 | 78 | rl.BeginMode2D(camera) 79 | 80 | for i := 0; i < len(stars); i++ { // RANGE OVER SLICE OF STAR BLOKS & DRAW 81 | 82 | if colorsOn { // DRAW COLOR STARS 83 | rl.DrawRectangleRec(stars[i].rec, rl.Fade(stars[i].col, stars[i].fade)) 84 | } else { // DRAW WHITE STARS 85 | rl.DrawRectangleRec(stars[i].rec, rl.Fade(rl.White, stars[i].fade)) 86 | } 87 | 88 | } 89 | 90 | rl.EndMode2D() 91 | 92 | rl.DrawText("press space on/off colors", 8, 12, 20, ranCol()) // TEXT FLASHING COLOR EFFECT 93 | rl.DrawText("press space on/off colors", 9, 11, 20, rl.Black) // TEXT BLACK SHADOWN 94 | rl.DrawText("press space on/off colors", 10, 10, 20, rl.White) // TEXT 95 | 96 | rl.EndDrawing() 97 | } 98 | 99 | rl.CloseWindow() 100 | } 101 | func upStars() { 102 | 103 | timer-- // DECREASE TIMER 104 | if timer <= 0 { 105 | direc = rInt(1, 9) // CHOOSE NEW DIRECTION 106 | velX = rF32(2, maxVel) // CHOOSE NEW X SPEED 107 | velY = rF32(2, maxVel) // CHOOSE NEW Y SEEPD 108 | timer = rI32(2, 8) * fps // SET NEW TIMER 109 | } 110 | 111 | for i := 0; i < len(stars); i++ { // RANGE OVER SLICE OF STAR BLOKS & UPDATE 112 | 113 | stars[i].fade -= 0.01 // FADE OUT 114 | if stars[i].fade <= 0 { // IF FADE LESS THAN OR EQUALS ZERO SET NEW FADE 115 | stars[i].fade = rF32(0.5, 0.9) 116 | } 117 | 118 | switch direc { // MOVE STAR REC ACCORDING TO CHOSEN DIRECTION 119 | case 1: //UP LEFT 120 | stars[i].rec.X -= velX 121 | stars[i].rec.Y -= velY 122 | case 2: //UP 123 | stars[i].rec.Y -= velY 124 | case 3: //UP RIGHT 125 | stars[i].rec.X += velX 126 | stars[i].rec.Y -= velY 127 | case 4: // RIGHT 128 | stars[i].rec.X += velX 129 | case 5: //DOWN RIGHT 130 | stars[i].rec.X += velX 131 | stars[i].rec.Y += velY 132 | case 6: //DOWN 133 | stars[i].rec.Y += velY 134 | case 7: //DOWN LEFT 135 | stars[i].rec.X -= velX 136 | stars[i].rec.Y += velY 137 | case 8: //LEFT 138 | stars[i].rec.X -= velX 139 | } 140 | 141 | // IF STAR REC X IS OVER SCREEN BORDER LEFT MOVE TO SCREEN BORDER RIGHT 142 | if stars[i].rec.X < 0 { 143 | stars[i].rec.X = float32(scrW) 144 | } 145 | // IF STAR REC IS OVER SCREEN BORDER RIGHT MOVE TO SCREEN BORDER LEFT 146 | if stars[i].rec.X > float32(scrW) { 147 | stars[i].rec.X = 0 148 | } 149 | // IF STAR REC Y IS OVER SCREEN BORDER TOP MOVE TO SCREEN BORDER BOTTOM 150 | if stars[i].rec.Y < 0 { 151 | stars[i].rec.Y = float32(scrH) 152 | } 153 | // IF STAR REC IS OVER SCREEN BORDER BOTTOM MOVE TO SCREEN BORDER TOP 154 | if stars[i].rec.Y > float32(scrH) { 155 | stars[i].rec.Y = 0 156 | } 157 | } 158 | 159 | } 160 | func makeStars() { 161 | 162 | maxSize := float32(8) // MAXIMUM SIZE OF RECTANGLE WIDTHS 163 | 164 | for i := 0; i < numStars; i++ { // FILLS THE STARS SLICE 165 | // MAKE EMPTY BLOK STRUCT 166 | newBlok := blok{} 167 | // CHOOSE RANDOM COLOR SEE FUNCTION END OF CODE 168 | newBlok.col = ranCol() 169 | // SET RANDOM FADE/OPACITY 170 | newBlok.fade = rF32(0.5, 0.9) 171 | // CHOOSE RANDOM SIZE OF RECTANGLE SIDES 172 | width := rF32(1, maxSize) 173 | // CREATE THE RECTANGLE 174 | newBlok.rec = rl.NewRectangle(rF32(0, float32(scrW)), rF32(0, float32(scrH)), width, width) 175 | // ADD TO SLICE 176 | stars = append(stars, newBlok) 177 | } 178 | 179 | } 180 | 181 | // RETURNS A RANDOM INTEGER 32 182 | func rI32(min, max int) int32 { 183 | return int32(min + rand.Intn(max-min)) 184 | } 185 | 186 | // RETURNS A RANDOM FLOAT 32 187 | func rF32(min, max float32) float32 { 188 | min2 := float64(min) 189 | max2 := float64(max) 190 | return float32(min2 + rand.Float64()*(max2-min2)) 191 | } 192 | 193 | // RETURNS A RANDOM COLOR 194 | func ranCol() rl.Color { 195 | return rl.NewColor(uint8(rInt(0, 256)), uint8(rInt(0, 256)), uint8(rInt(0, 256)), 255) 196 | } 197 | 198 | // RETURNS A RANDOM INTEGER FOR USE IN RANDOM COLOR ABOVE 199 | func rInt(min, max int) int { 200 | return min + rand.Intn(max-min) 201 | } 202 | -------------------------------------------------------------------------------- /2D_Beginner/text_cntr_scroll/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - TEXT CENTER & SCROLL UP & SCROLL LEFT/RIGHT 3 | 4 | Demonstrates centering of text at different sizes, moving of two different texts left and right across screen as well as up. 5 | View more at [unklnik.com](https://unklnik.com/posts/2d-text-center-scroll/) 6 | 7 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/f910ef15-8263-4c70-93c2-c134dc01874a 8 | -------------------------------------------------------------------------------- /2D_Beginner/text_cntr_scroll/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math/rand" 5 | 6 | rl "github.com/gen2brain/raylib-go/raylib" 7 | ) 8 | 9 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 10 | 11 | https://github.com/unklnik/raylib-go-more-examples 12 | 13 | */ 14 | 15 | var ( 16 | velX, velY float32 // X & Y MOVEMENT SPEED 17 | maxVel = float32(10) // MAX SPEED FOR USE IN RANDOM GENERATOR 18 | bounceRec, borderRec rl.Rectangle // BOUNCING & BORDER RECTANGLES 19 | cntr rl.Vector2 // CENTER OF SCREEN 20 | timer int // COLOUR CHANGE TIMER ON COLLISION 21 | ) 22 | 23 | func main() { 24 | 25 | rl.InitWindow(0, 0, "point collisions - raylib go - https://github.com/unklnik/raylib-go-more-examples") 26 | scrW, scrH := rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 27 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 28 | 29 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 30 | 31 | cntr = rl.NewVector2(float32(scrW/2), float32(scrH/2)) // CALCULATE CENTER 32 | borderRec = rl.NewRectangle(cntr.X-float32(scrW/4), cntr.Y-float32(scrH/4), float32(scrW/2), float32(scrH/2)) // DEFINE BORDER RECTANGLE 33 | bounceRec = rl.NewRectangle(cntr.X-32, cntr.Y-32, 64, 64) // DEFINE BOUNCE RECTANGLE 34 | 35 | // SEE RF32 FUNCTION END OF CODE FINDS A RANDOM FLOAT32 BETWEEN TWO VALUES 36 | velX = rF32(-maxVel, maxVel) // FINDS A RANDOM X AXIS MOVEMENT SPEED 37 | velY = rF32(-maxVel, maxVel) // FINDS A RANDOM Y AXIS MOVEMENT SPEED 38 | 39 | camera := rl.Camera2D{} // DEFINES THE CAMERA 40 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 41 | 42 | rl.SetTargetFPS(60) // NUMBER OF FRAMES DRAWN IN A SECOND 43 | 44 | for !rl.WindowShouldClose() { 45 | 46 | checkCollisionsMove() // SEE FUNCTION BELOW - CHECKS FOR BORDER COLLISIONS & MOVES 47 | 48 | rl.BeginDrawing() 49 | 50 | rl.ClearBackground(rl.Black) 51 | 52 | rl.BeginMode2D(camera) 53 | 54 | rl.DrawRectangleLinesEx(borderRec, 4, rl.Green) // DRAWS BORDER REC 55 | 56 | if timer > 0 { 57 | rl.DrawRectangleRec(bounceRec, rl.Red) //DRAWS RED BOUNCE REC IF TIMER IS LARGER THAN ZERO 58 | timer-- // DECREASES TIMER 59 | } else { 60 | rl.DrawRectangleRec(bounceRec, rl.Green) //DRAWS GREEN BOUNCE REC IF TIMER IS ZERO 61 | } 62 | 63 | rl.EndMode2D() 64 | 65 | rl.EndDrawing() 66 | } 67 | 68 | rl.CloseWindow() 69 | } 70 | 71 | // CHECKS FOR BOUNCE REC CORNER COLLISIONS & MOVES BOUNCE REC 72 | func checkCollisionsMove() { 73 | 74 | checkRec := bounceRec // DUPLICATES THE BOUNCE REC TO USE AS A COLLISION CHECK 75 | checkRec.X += velX // MOVES DUPLICATE REC BY VELX 76 | checkRec.Y += velY // MOVES DUPLICATE REC BY VELY 77 | 78 | v1 := rl.NewVector2(checkRec.X, checkRec.Y) // CREATES A CHECK POINT TOP LEFT CORNER 79 | v2 := v1 80 | v2.X += checkRec.Width // CREATES A CHECK POINT TOP RIGHT CORNER 81 | v3 := v2 82 | v3.Y += checkRec.Height // CREATES A CHECK POINT BOTTOM RIGHT CORNER 83 | v4 := v1 84 | v4.Y += checkRec.Height // CREATES A CHECK POINT BOTTOM LEFT CORNER 85 | 86 | // CHECKS IF ANY OF THE CREATED CHECK POINTS HAVE EXITED THE BORDER REC 87 | canmove := true 88 | if !rl.CheckCollisionPointRec(v1, borderRec) || !rl.CheckCollisionPointRec(v2, borderRec) || !rl.CheckCollisionPointRec(v3, borderRec) || !rl.CheckCollisionPointRec(v4, borderRec) { 89 | canmove = false 90 | } 91 | 92 | if canmove { // NO POINTS EXITED - BOUNCE REC MOVES TO CHECK REC POSITION 93 | bounceRec = checkRec 94 | } else { // POINTS EXITED - BOUNCE REC CHANGE DIRECTION 95 | 96 | if bounceRec.X < cntr.X { // FINDS A NEW VELX BASED ON POSITION RELATIVE TO CENTER 97 | velX = rF32(maxVel/8, maxVel) 98 | } else { 99 | velX = -rF32(maxVel/8, maxVel) 100 | } 101 | if bounceRec.Y < cntr.Y { // FINDS A NEW VELY BASED ON POSITION RELATIVE TO CENTER 102 | velY = rF32(maxVel/8, maxVel) 103 | } else { 104 | velY = -rF32(maxVel/8, maxVel) 105 | } 106 | 107 | timer = 15 // SETS A COLLISION TIMER 108 | } 109 | 110 | } 111 | 112 | // RETURNS A RANDOM FLOAT32 VALUE WITHIN A RANGE (BETWEEN MIN/MAX VALUES) 113 | func rF32(min, max float32) float32 { 114 | min2 := float64(min) 115 | max2 := float64(max) 116 | return float32(min2 + rand.Float64()*(max2-min2)) 117 | } 118 | -------------------------------------------------------------------------------- /2D_Beginner/vector2_collisions/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - VECTOR2 POINT COLLISIONS 3 | 4 | Simple example to demonstrate one way of checking for collisions of a moving rectangle inside a border by creating four Vector2 points for each corner and then checking if they exit the border rectangle. View more at [unklnik.com](https://unklnik.com/posts/2d-vector2-border-collisions/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/09f3dc9f-5c5b-4e93-8e96-c66a241411d1 7 | -------------------------------------------------------------------------------- /2D_Beginner/vector2_collisions/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math/rand" 5 | 6 | rl "github.com/gen2brain/raylib-go/raylib" 7 | ) 8 | 9 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 10 | 11 | https://github.com/unklnik/raylib-go-more-examples 12 | 13 | */ 14 | 15 | var ( 16 | velX, velY float32 // X & Y MOVEMENT SPEED 17 | maxVel = float32(10) // MAX SPEED FOR USE IN RANDOM GENERATOR 18 | bounceRec, borderRec rl.Rectangle // BOUNCING & BORDER RECTANGLES 19 | cntr rl.Vector2 // CENTER OF SCREEN 20 | timer int // COLOUR CHANGE TIMER ON COLLISION 21 | ) 22 | 23 | func main() { 24 | 25 | rl.InitWindow(0, 0, "point collisions - raylib go - https://github.com/unklnik/raylib-go-more-examples") 26 | scrW, scrH := rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 27 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 28 | 29 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 30 | 31 | cntr = rl.NewVector2(float32(scrW/2), float32(scrH/2)) // CALCULATE CENTER 32 | borderRec = rl.NewRectangle(cntr.X-float32(scrW/4), cntr.Y-float32(scrH/4), float32(scrW/2), float32(scrH/2)) // DEFINE BORDER RECTANGLE 33 | bounceRec = rl.NewRectangle(cntr.X-32, cntr.Y-32, 64, 64) // DEFINE BOUNCE RECTANGLE 34 | 35 | // SEE RF32 FUNCTION END OF CODE FINDS A RANDOM FLOAT32 BETWEEN TWO VALUES 36 | velX = rF32(-maxVel, maxVel) // FINDS A RANDOM X AXIS MOVEMENT SPEED 37 | velY = rF32(-maxVel, maxVel) // FINDS A RANDOM Y AXIS MOVEMENT SPEED 38 | 39 | camera := rl.Camera2D{} // DEFINES THE CAMERA 40 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 41 | 42 | rl.SetTargetFPS(60) // NUMBER OF FRAMES DRAWN IN A SECOND 43 | 44 | for !rl.WindowShouldClose() { 45 | 46 | checkCollisionsMove() // SEE FUNCTION BELOW - CHECKS FOR BORDER COLLISIONS & MOVES 47 | 48 | rl.BeginDrawing() 49 | 50 | rl.ClearBackground(rl.Black) 51 | 52 | rl.BeginMode2D(camera) 53 | 54 | rl.DrawRectangleLinesEx(borderRec, 4, rl.Green) // DRAWS BORDER REC 55 | 56 | if timer > 0 { 57 | rl.DrawRectangleRec(bounceRec, rl.Red) //DRAWS RED BOUNCE REC IF TIMER IS LARGER THAN ZERO 58 | timer-- // DECREASES TIMER 59 | } else { 60 | rl.DrawRectangleRec(bounceRec, rl.Green) //DRAWS GREEN BOUNCE REC IF TIMER IS ZERO 61 | } 62 | 63 | rl.EndMode2D() 64 | 65 | rl.EndDrawing() 66 | } 67 | 68 | rl.CloseWindow() 69 | } 70 | 71 | // CHECKS FOR BOUNCE REC CORNER COLLISIONS & MOVES BOUNCE REC 72 | func checkCollisionsMove() { 73 | 74 | checkRec := bounceRec // DUPLICATES THE BOUNCE REC TO USE AS A COLLISION CHECK 75 | checkRec.X += velX // MOVES DUPLICATE REC BY VELX 76 | checkRec.Y += velY // MOVES DUPLICATE REC BY VELY 77 | 78 | v1 := rl.NewVector2(checkRec.X, checkRec.Y) // CREATES A CHECK POINT TOP LEFT CORNER 79 | v2 := v1 80 | v2.X += checkRec.Width // CREATES A CHECK POINT TOP RIGHT CORNER 81 | v3 := v2 82 | v3.Y += checkRec.Height // CREATES A CHECK POINT BOTTOM RIGHT CORNER 83 | v4 := v1 84 | v4.Y += checkRec.Height // CREATES A CHECK POINT BOTTOM LEFT CORNER 85 | 86 | // CHECKS IF ANY OF THE CREATED CHECK POINTS HAVE EXITED THE BORDER REC 87 | canmove := true 88 | if !rl.CheckCollisionPointRec(v1, borderRec) || !rl.CheckCollisionPointRec(v2, borderRec) || !rl.CheckCollisionPointRec(v3, borderRec) || !rl.CheckCollisionPointRec(v4, borderRec) { 89 | canmove = false 90 | } 91 | 92 | if canmove { // NO POINTS EXITED - BOUNCE REC MOVES TO CHECK REC POSITION 93 | bounceRec = checkRec 94 | } else { // POINTS EXITED - BOUNCE REC CHANGE DIRECTION 95 | 96 | if bounceRec.X < cntr.X { // FINDS A NEW VELX BASED ON POSITION RELATIVE TO CENTER 97 | velX = rF32(maxVel/8, maxVel) 98 | } else { 99 | velX = -rF32(maxVel/8, maxVel) 100 | } 101 | if bounceRec.Y < cntr.Y { // FINDS A NEW VELY BASED ON POSITION RELATIVE TO CENTER 102 | velY = rF32(maxVel/8, maxVel) 103 | } else { 104 | velY = -rF32(maxVel/8, maxVel) 105 | } 106 | 107 | timer = 15 // SETS A COLLISION TIMER 108 | } 109 | 110 | } 111 | 112 | // RETURNS A RANDOM FLOAT32 VALUE WITHIN A RANGE (BETWEEN MIN/MAX VALUES) 113 | func rF32(min, max float32) float32 { 114 | min2 := float64(min) 115 | max2 := float64(max) 116 | return float32(min2 + rand.Float64()*(max2-min2)) 117 | } 118 | -------------------------------------------------------------------------------- /2D_Intermediate/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D INTERMEDIATE EXAMPLES 3 | These examples are intended for anyone that might have messed around with games programming in Go or another language before and/or is proficient in coding and/or has used Raylib before. If you find that you are confused when going over the code then the [2D Beginner Examples](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Beginner) are much simpler and require only basic knowledge to understand. Read the comments if you are not sure what the code is doing. -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - ANIMATED LOGO 3 | 4 | Demonstrates drawing of a simple horizontal scrolling Go logo as well as an animated Raylib logo using images textures stored in a slice. SPACE key to restart the animation. View more at [unklnik.com](https://unklnik.com/posts/2d-animated-logo/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/02c5efc9-62fb-4823-b220-619a2afc1f6d 7 | -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/gologo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/gologo.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/00.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/00.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/01.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/02.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/03.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/04.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/05.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/06.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/07.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/08.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/09.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/10.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/11.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/12.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/13.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/14.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/15.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/16.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/17.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/18.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/19.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/20.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/21.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/22.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/23.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/24.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/25.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/26.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/27.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/28.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/29.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/30.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/31.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/32.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/33.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/34.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/35.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/36.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/37.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/38.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/39.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/40.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/41.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/42.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/43.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/44.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/45.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/46.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/47.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/48.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/49.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/50.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/51.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/51.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/52.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/53.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/54.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/54.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/55.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/img/raylib_logo/56.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/animated_logo/img/raylib_logo/56.png -------------------------------------------------------------------------------- /2D_Intermediate/animated_logo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | rl "github.com/gen2brain/raylib-go/raylib" 7 | ) 8 | 9 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 10 | 11 | https://github.com/unklnik/raylib-go-more-examples 12 | 13 | */ 14 | 15 | var ( 16 | raylibAnim []rl.Texture2D //SLICE OF RAYLIB LOGO IMAGE FRAMES 17 | gologo rl.Texture2D //TEXTURE OF GO LOGO IMAGE 18 | goLogoRec = rl.NewRectangle(0, 0, 400, 160) //RECTANGLE SIZE OF GO LOGO IMAGE 19 | raylibFrameNum int //FRAME NUMBER FOR ANIMATION 20 | raylibRec = rl.NewRectangle(0, 0, 288, 288) //RECTANGLE SIZE OF RAYLIB LOGO IMAGE 21 | introT1 = fps * 2 //TIMER BETWEEN ANIMATIONS 22 | introT2 = fps * 2 //TIMER BETWEEN ANIMATIONS 23 | goLogoDrawRec rl.Rectangle //DRAW RECTANGLE FOR GO LOGO 24 | fps = int32(60) //FRAMES PER SECOND 25 | cnt rl.Vector2 //SCREEN CENTER 26 | scrW, scrH int // SCREEN WIDTH & HEIGHT 27 | frames int //FRAME COUNTER 28 | ) 29 | 30 | func main() { 31 | 32 | rl.InitWindow(0, 0, "animated logo - raylib go - https://github.com/unklnik/raylib-go-more-examples") 33 | scrW, scrH = rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 34 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 35 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 36 | 37 | cnt = rl.NewVector2(float32(scrW/2), float32(scrH/2)) 38 | 39 | camera := rl.Camera2D{} // DEFINES THE CAMERA 40 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 41 | 42 | gologo = rl.LoadTexture("img/gologo.png") //LOAD GO LOGO IMG 43 | for i := 0; i < 57; i++ { //LOAD RAYLIB LOGO FRAMES INTO SLICE 44 | txt := fmt.Sprint(i) + ".png" 45 | if i < 10 { 46 | txt = "0" + txt 47 | } 48 | txt = "img/raylib_logo/" + txt 49 | raylibAnim = append(raylibAnim, rl.LoadTexture(txt)) 50 | } 51 | 52 | startAnim() 53 | 54 | rl.SetTargetFPS(fps) // NUMBER OF FRAMES DRAWN IN A SECOND 55 | 56 | for !rl.WindowShouldClose() { 57 | frames++ //FRAME COUNTER 58 | if rl.IsKeyPressed(rl.KeySpace) { //RESTART KEY 59 | startAnim() 60 | } 61 | rl.BeginDrawing() 62 | rl.ClearBackground(rl.Black) 63 | rl.BeginMode2D(camera) 64 | 65 | if introT1 > 0 { //IF INTRO TIMER 1 IS LARGER THAN ZERO THEN DRAW GO LOGO 66 | rl.DrawTexturePro(gologo, goLogoRec, goLogoDrawRec, rl.Vector2Zero(), 0, rl.White) 67 | if goLogoDrawRec.X < cnt.X-goLogoDrawRec.Width/2 { //MOVE LOGO TO CENTER 68 | goLogoDrawRec.X += 20 69 | } else { //WHEN AT CENTER THEN DECREASE TIMER 70 | introT1-- 71 | } 72 | } else if introT2 > 0 { //IF INTRO TIMER 2 IS LARGER THAN ZERO & INTRO TIMER 1 IS ZERO THEN DRAW 73 | siz := float32(320) //SIZE OF RECTANGLE 74 | rec := rl.NewRectangle(cnt.X-siz/2, cnt.Y-siz/2, siz, siz) 75 | rl.DrawTexturePro(raylibAnim[raylibFrameNum], raylibRec, rec, rl.Vector2Zero(), 0, rl.White) 76 | if raylibFrameNum < len(raylibAnim)-1 { 77 | if frames%3 == 0 { //ADVANCE DRAW IMAGE EVERY 3 FRAMES 78 | raylibFrameNum++ 79 | } 80 | } 81 | } 82 | 83 | rl.DrawText("SPACE KEY TO RESTART", 10, 10, 20, rl.White) 84 | 85 | rl.EndMode2D() 86 | 87 | rl.EndDrawing() 88 | } 89 | 90 | rl.UnloadTexture(gologo) //UNLOAD FROM MEMORY 91 | for i := 0; i < len(raylibAnim); i++ { 92 | rl.UnloadTexture(raylibAnim[i]) 93 | } 94 | rl.CloseWindow() 95 | } 96 | 97 | func startAnim() { //RESET THE ANIMATION 98 | goLogoDrawRec = rl.NewRectangle(0-goLogoRec.Width, cnt.Y-goLogoRec.Height/2, goLogoRec.Width, goLogoRec.Height) //CREATE GO LOGO RECTANGLE OUTSIDE LEFT SCREEN BORDER 99 | introT1 = fps * 2 100 | introT2 = fps * 2 101 | raylibFrameNum = 0 102 | } 103 | -------------------------------------------------------------------------------- /2D_Intermediate/candlelight/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - ARTIFICIAL CANDELIGHT 3 | 4 | Demonstrates how to create the illusion of candlelight in 2D using a gradient filled circle, note that this is not lighting, just creates the illusion of a flickering candle. View more at [unklnik.com](https://unklnik.com/posts/2d-candlelight/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/2ddce3a4-78ef-440b-8e1b-a143059de2fd 7 | -------------------------------------------------------------------------------- /2D_Intermediate/candlelight/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/candlelight/img.png -------------------------------------------------------------------------------- /2D_Intermediate/candlelight/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | 7 | rl "github.com/gen2brain/raylib-go/raylib" 8 | ) 9 | 10 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 11 | 12 | https://github.com/unklnik/raylib-go-more-examples 13 | 14 | */ 15 | 16 | var ( 17 | cnt rl.Vector2 //SCREEN CENTER 18 | candleIMG rl.Texture2D //IMAGE 19 | candleRec = rl.NewRectangle(0, 0, 16, 16) //IMAGE RECTANGLE 20 | positions []rl.Vector2 //POSITIONS OF IMAGES ON SCREEN 21 | size = float32(64) //SIZE OF IMAGES 22 | currentColor int //CURRENT COLOR 23 | num = 10 //NUMBER OF CANDLES 24 | 25 | candleColors = []rl.Color{rl.Yellow, rl.White, rl.SkyBlue, rl.DarkGray, rl.Magenta} //LIGHT COLORS 26 | ) 27 | 28 | func main() { 29 | 30 | rl.InitWindow(0, 0, "candlelight - raylib go - https://github.com/unklnik/raylib-go-more-examples") 31 | scrW, scrH := rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 32 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 33 | //rl.SetWindowState(rl.FlagBorderlessWindowedMode) // UNCOMMENT IF YOU HAVE DISPLAY ISSUES 34 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES 35 | 36 | cnt = rl.NewVector2(float32(scrW/2), float32(scrH/2)) //FIND SCREEN CENTER 37 | 38 | camera := rl.Camera2D{} // DEFINES THE CAMERA 39 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 40 | 41 | candleIMG = rl.LoadTexture("img.png") //LOAD IMAGES FROM FILE 42 | 43 | for num > 0 { 44 | positions = append(positions, rl.NewVector2(rF32(0, float32(scrW)-size), rF32(0, float32(scrH)-size))) //CREATE RANDOM VECTOR2 POSITIONS SEE FUNCTION BELOW 45 | num-- 46 | } 47 | 48 | rl.SetTargetFPS(60) // NUMBER OF FRAMES DRAWN IN A SECOND 49 | 50 | for !rl.WindowShouldClose() { 51 | 52 | if rl.IsKeyPressed(rl.KeyUp) { //CHANGE CAMERA ZOOM KEYS 53 | if camera.Zoom == 0.5 { 54 | camera.Zoom = 1 55 | } else if camera.Zoom == 1 { 56 | camera.Zoom = 1.5 57 | } else if camera.Zoom == 1.5 { 58 | camera.Zoom = 2 59 | } else if camera.Zoom == 2 { 60 | camera.Zoom = 0.5 61 | } 62 | 63 | camera.Target = cnt //SET THE CAMERA TARGET TO CENTER 64 | camera.Offset.X = float32(scrW / 2) //ADJUST FOR ZOOM 65 | camera.Offset.Y = float32(scrH / 2) //ADJUST FOR ZOOM 66 | } 67 | if rl.IsKeyPressed(rl.KeyDown) { //CHANGE CURRENT COLOR 68 | currentColor++ 69 | if currentColor == len(candleColors) { 70 | currentColor = 0 71 | } 72 | } 73 | 74 | rl.BeginDrawing() 75 | 76 | rl.ClearBackground(rl.Black) 77 | 78 | rl.BeginMode2D(camera) 79 | 80 | for i := 0; i < len(positions); i++ { //RANGE OVER SLICE AND DRAW IMAGES 81 | rl.DrawTexturePro(candleIMG, candleRec, rl.NewRectangle(positions[i].X-size/2, positions[i].Y-size/2, size, size), rl.Vector2Zero(), 0, rl.White) 82 | 83 | //DRAW A CIRCLE WITH COLOR AND BLANK GRADIENT FILL TO SIMULATE LIGHT WITH RANDOM FADE 84 | rl.DrawCircleGradient(int32(positions[i].X), int32(positions[i].Y), size*4, rl.Fade(candleColors[currentColor], rF32(0.1, 0.3)), rl.Blank) 85 | } 86 | 87 | rl.EndMode2D() 88 | 89 | //DRAW TEXT 90 | rl.DrawText("camera zoom "+fmt.Sprintf("%.1f", camera.Zoom)+" press UP ARROW key to change", 10, 10, 20, rl.White) 91 | rl.DrawText("press DOWN ARROW key to change color", 10, 30, 20, rl.White) 92 | 93 | rl.EndDrawing() 94 | } 95 | 96 | rl.UnloadTexture(candleIMG) //UNLOAD FROM MEMORY 97 | 98 | rl.CloseWindow() 99 | } 100 | 101 | // RETURNS A RANDOM FLOAT32 BETWEEN MIN/MAX 102 | func rF32(min, max float32) float32 { 103 | min2 := float64(min) 104 | max2 := float64(max) 105 | return float32(min2 + rand.Float64()*(max2-min2)) 106 | } 107 | -------------------------------------------------------------------------------- /2D_Intermediate/chain_lightning/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - CHAIN LIGHTNING 3 | 4 | Demonstrates a simple method to create an effect of chain lightning, when one rectangle (enemy) is impacted by a bullet rectangle then a chain of lines is drawn between the centers of all enemies on screen. WASD keys move player, left mouse button to shoot and up arrow key to change zoom. The [Player Bullets](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Intermediate/player_bullets) example can be used a starting point for this example. View more at [unklnik.com](https://unklnik.com/posts/2d-chain-lightning/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/e05b67b8-ccca-4fe3-83fe-e4a466e5a8ae 7 | -------------------------------------------------------------------------------- /2D_Intermediate/chain_lightning/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math" 5 | "math/rand" 6 | 7 | rl "github.com/gen2brain/raylib-go/raylib" 8 | ) 9 | 10 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 11 | 12 | https://github.com/unklnik/raylib-go-more-examples 13 | 14 | */ 15 | 16 | var ( 17 | enemies []xenemy //SLICE OF ENEMY STRUCTS 18 | bullets []xbullet //SLICE OF BULLET STRUCTS 19 | shootTarget, cursorCam, cursor rl.Vector2 //TARGET, CURSOR CAMERA VS SCREEN POSITION, CURSOR 20 | playerRec rl.Rectangle //PLAYER RECTANGLE 21 | spd = float32(10) //MAX SPEED 22 | attackT, chainT int32 //PAUSE BETWEEN BULLETS & LIGHTNING DRAW TIMER 23 | fps = int32(60) //FRAMES PER SECOND 24 | camera rl.Camera2D //CAMERA 25 | borderRec rl.Rectangle //BOUNCING & BORDER RECTANGLES 26 | cntr rl.Vector2 //CENTER OF SCREEN 27 | scrW, scrH int //SCREEN WIDTH & HEIGHT 28 | ) 29 | 30 | // STRUCT OF BULLET CONTAINING REC, DIRECTION X & Y, OFF BOOL 31 | type xbullet struct { 32 | rec rl.Rectangle 33 | dirX, dirY float32 34 | off bool 35 | } 36 | 37 | // STRUCT OF ENEMY CONTAINING REC, DIRECTION X & Y, HIT TIMER 38 | type xenemy struct { 39 | rec rl.Rectangle 40 | dirX, dirY float32 41 | hitT int32 42 | } 43 | 44 | func main() { 45 | 46 | rl.InitWindow(0, 0, "chain lightning - raylib go - https://github.com/unklnik/raylib-go-more-examples") 47 | scrW, scrH = rl.GetScreenWidth(), rl.GetScreenHeight() //GET SCREEN SIZES 48 | rl.SetWindowSize(scrW, scrH) //SET WINDOW SIZE 49 | rl.SetWindowState(rl.FlagBorderlessWindowedMode) 50 | //rl.ToggleFullscreen() //UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 51 | 52 | rl.HideCursor() //HIDE THE STANDARD MOUSE CURSOR 53 | 54 | cntr = rl.NewVector2(float32(scrW/2), float32(scrH/2)) //CALCULATE CENTER 55 | 56 | borderRec = rl.NewRectangle(cntr.X-float32(scrW/4), cntr.Y-float32(scrH/4), float32(scrW/2), float32(scrH/2)) //DEFINE BORDER RECTANGLE 57 | 58 | siz := float32(32) //PLAYER SIZE 59 | playerRec = rl.NewRectangle(cntr.X-siz/2, cntr.Y-siz/2, siz, siz) //INITIAL PLAYER RECTANGLE 60 | 61 | camera.Zoom = 1.5 //SETS CAMERA ZOOM 62 | camera.Target = cntr //SET CAMERA TARGET 63 | camera.Offset.X = float32(scrW / 2) //ADJUST CAMERA FOR ZOOM 64 | camera.Offset.Y = float32(scrH / 2) //ADJUST CAMERA FOR ZOOM 65 | 66 | makeEnemies() 67 | 68 | rl.SetTargetFPS(fps) //NUMBER OF FRAMES DRAWN IN A SECOND 69 | 70 | for !rl.WindowShouldClose() { 71 | 72 | cursor = rl.GetMousePosition() //GET MOUSE POSITION 73 | cursorCam = rl.GetScreenToWorld2D(cursor, camera) //GET MOUSE POSITION IN CAMERA SPACE WITH ZOOM 74 | 75 | upEnemies() //UPDATE ENEMY MOVEMENTS 76 | upBullets() //UPDATE BULLET MOVEMENTS & COLLISIONS 77 | input() //CAPTURE INPUT 78 | 79 | //TIMER 80 | if attackT > 0 { //PAUSE BETWEEN SHOTS TIMER 81 | attackT-- 82 | } 83 | 84 | rl.BeginDrawing() 85 | 86 | rl.ClearBackground(rl.Black) 87 | 88 | rl.BeginMode2D(camera) 89 | 90 | rl.DrawRectangleLinesEx(borderRec, 4, rl.Green) //DRAWS BORDER REC 91 | 92 | rl.DrawRectangleLinesEx(playerRec, 8, rl.Magenta) //DRAW PLAYER REC 93 | 94 | //DRAW ENEMIES 95 | for i := 0; i < len(enemies); i++ { 96 | if enemies[i].hitT > 0 { 97 | rl.DrawRectangleLinesEx(enemies[i].rec, 2, rl.Magenta) 98 | } else { 99 | rl.DrawRectangleLinesEx(enemies[i].rec, 2, rl.Blue) 100 | } 101 | } 102 | 103 | //DRAW CHAIN LIGHTING 104 | if chainT > 0 { 105 | chainT-- 106 | var cntrs []rl.Vector2 //STORE ALL THE RECTANGLE CENTERS IN A SLICE AS THEY MOVE 107 | for i := 0; i < len(enemies); i++ { 108 | cntrs = append(cntrs, rl.NewVector2(enemies[i].rec.X+enemies[i].rec.Width/2, enemies[i].rec.Y+enemies[i].rec.Height/2)) 109 | } 110 | //DRAW LINES USING THESE CENTERS 111 | for i := 0; i < len(cntrs); i++ { 112 | if i < len(cntrs)-1 { //NOT ONE LESS THAN LENGTH 113 | rl.DrawLineEx(cntrs[i], cntrs[i+1], 12, rl.Fade(rl.SkyBlue, 0.4)) 114 | } 115 | } 116 | } 117 | 118 | //DRAW BULLETS 119 | for i := 0; i < len(bullets); i++ { 120 | if !bullets[i].off { 121 | rl.DrawRectangleLinesEx(bullets[i].rec, 2, rl.Yellow) 122 | } 123 | } 124 | 125 | //DRAW CIRCLE TARGET INSTEAD OF CURSOR 126 | rl.DrawCircleLines(int32(cursorCam.X), int32(cursorCam.Y), 10, rl.Red) 127 | 128 | rl.EndMode2D() 129 | 130 | rl.DrawText("W A S D keys move", 10, 10, 20, rl.White) 131 | rl.DrawText("left mouse to shoot", 10, 40, 20, rl.White) 132 | rl.DrawText("up arrow key change zoom", 10, 70, 20, rl.White) 133 | 134 | rl.EndDrawing() 135 | } 136 | 137 | rl.CloseWindow() 138 | } 139 | func makeEnemies() { 140 | num := 4 //NUMBER OF ENEMIES TO MAKE 141 | for num > 0 { 142 | size := float32(32) //SIZE OF RECTANGLE 143 | x := borderRec.X + size/2 144 | y := borderRec.Y + size/2 145 | x += rF32(0, borderRec.Width-size*2) //RANDOM POSITION WITHIN BORDER RECTANGLE 146 | y += rF32(0, borderRec.Height-size*2) 147 | zenemy := xenemy{} 148 | zenemy.dirX = rF32(-spd, spd) //RANDOM SPEED SEE FUNCTION BELOW 149 | zenemy.dirY = rF32(-spd, spd) 150 | zenemy.rec = rl.NewRectangle(x, y, size, size) 151 | enemies = append(enemies, zenemy) 152 | num-- 153 | } 154 | } 155 | func upEnemies() { 156 | 157 | for i := 0; i < len(enemies); i++ { 158 | 159 | //UPDATE HIT TIMER 160 | if enemies[i].hitT > 0 { 161 | enemies[i].hitT-- 162 | } 163 | 164 | //NEXT MOVEMENT RECTANGLE FOR RECTANGLE POINTS EXITING BORDER 165 | checkRec := enemies[i].rec 166 | checkRec.X += enemies[i].dirX 167 | checkRec.Y += enemies[i].dirY 168 | 169 | //VECTOR 2 POINTS OF FOUR CORNERS OF PLAYER RECTANGLE 170 | v1 := rl.NewVector2(checkRec.X, checkRec.Y) 171 | v2 := v1 172 | v2.X += checkRec.Width 173 | v3 := v2 174 | v3.Y += checkRec.Height 175 | v4 := v3 176 | v4.X -= checkRec.Width 177 | 178 | //CHECK IF VECTOR 2 HAS EXITED BORDER 179 | canmove := true 180 | if !rl.CheckCollisionPointRec(v1, borderRec) || !rl.CheckCollisionPointRec(v2, borderRec) || !rl.CheckCollisionPointRec(v3, borderRec) || !rl.CheckCollisionPointRec(v4, borderRec) { 181 | canmove = false 182 | } 183 | 184 | if canmove { 185 | enemies[i].rec = checkRec //MOVE TO NEW POSITION IF NO EXITS 186 | } else { 187 | //CHANGE DIRECTION IF NEXT VECTOR 2 HAS EXITED BORDER 188 | enemies[i].dirX = rF32(-spd, spd) 189 | enemies[i].dirY = rF32(-spd, spd) 190 | } 191 | } 192 | 193 | } 194 | 195 | func input() { 196 | //INPUT KEYS FOR PLAYER MOVEMENT SEE MOVEPLAYER FUNCTION 197 | if rl.IsKeyDown(rl.KeyW) { 198 | movePlayer(1) 199 | 200 | } else if rl.IsKeyDown(rl.KeyS) { 201 | movePlayer(3) 202 | } 203 | if rl.IsKeyDown(rl.KeyD) { 204 | movePlayer(2) 205 | } else if rl.IsKeyDown(rl.KeyA) { 206 | movePlayer(4) 207 | } 208 | 209 | //CREATE BULLET IF ATTACK TIMER IS ZERO 210 | if rl.IsMouseButtonPressed(rl.MouseLeftButton) && attackT == 0 { 211 | attackT = fps / 4 212 | shootTarget = cursorCam //POSITION FOR BULLET AIMING 213 | shoot() 214 | } 215 | 216 | //CHANGE ZOOM 217 | if rl.IsKeyPressed(rl.KeyUp) { 218 | if camera.Zoom == 2 { 219 | camera.Zoom = 1 220 | } else if camera.Zoom == 1.5 { 221 | camera.Zoom = 2 222 | } else if camera.Zoom == 1 { 223 | camera.Zoom = 1.5 224 | } 225 | camera.Target = cntr 226 | camera.Offset.X = float32(scrW / 2) 227 | camera.Offset.Y = float32(scrH / 2) 228 | } 229 | } 230 | 231 | // CREATE BULLET FUNCTION 232 | func shoot() { 233 | zbullet := xbullet{} 234 | zbullet.rec = playerRec //DUPLICATE PLAYER RECTANGLE FOR BULLET 235 | 236 | //MAKE DUPLICATE RECTANGLE SMALLER 237 | zbullet.rec.X += playerRec.Width / 2 238 | zbullet.rec.Y += playerRec.Height / 2 239 | zbullet.rec.Width = zbullet.rec.Width / 2 240 | zbullet.rec.Height = zbullet.rec.Height / 2 241 | 242 | //CALCULATE X & Y SPEED TO MOVE TO SHOOT TARGET 243 | playerCntr := rl.NewVector2(playerRec.X+playerRec.Width/2, playerRec.Y+playerRec.Height/2) 244 | diffX := absdiff(playerCntr.X, shootTarget.X) //GET ABSOLUTE X DISTANCE FUNCTION BELOW 245 | diffY := absdiff(playerCntr.Y, shootTarget.Y) //GET ABSOLUTE Y DISTANCE FUNCTION BELOW 246 | 247 | if diffX > diffY { 248 | zbullet.dirX = spd //IF DIFFERENCE X IS LARGER X IS FULL SPEED 249 | zbullet.dirY = diffY / (diffX / zbullet.dirX) //CALCULATE Y SPEED 250 | } else { 251 | zbullet.dirY = spd //IF DIFFERENCE Y IS LARGER Y IS FULL SPEED 252 | zbullet.dirX = diffX / (diffY / zbullet.dirY) //CALCULATE X SPEED 253 | } 254 | 255 | //IF TARGET IS BEHIND PLAYER CHANGE X DIRECTION TO NEGATIVE 256 | if playerCntr.X > shootTarget.X { 257 | zbullet.dirX = -zbullet.dirX 258 | } 259 | 260 | //IF TARGET IS ABOVE PLAYER CHANGE Y DIRECTION TO NEGATIVE 261 | if playerCntr.Y > shootTarget.Y { 262 | zbullet.dirY = -zbullet.dirY 263 | } 264 | 265 | //ADD BULLET TO SLICE 266 | bullets = append(bullets, zbullet) 267 | } 268 | 269 | func upBullets() { 270 | 271 | clear := false //TO CLEAR BULLETS IF COLLISIONS 272 | for i := 0; i < len(bullets); i++ { 273 | 274 | if !bullets[i].off { 275 | for j := 0; j < len(enemies); j++ { 276 | //CHECK FOR COLLISIONS VERSUS ENEMY RECTANGLES 277 | if rl.CheckCollisionRecs(bullets[i].rec, enemies[j].rec) && enemies[j].hitT == 0 { 278 | enemies[j].hitT = fps * 1 //TURN ON ENEMY HIT TIMER 279 | bullets[i].off = true //TURN OFF BULLET 280 | chainT = fps * 1 //TURN ON CHAIN LIGHTNING 281 | } 282 | } 283 | } 284 | 285 | //IF NO ENEMY COLLISIONS THEN CHECK BULLET MOVEMENT 286 | if !bullets[i].off { 287 | checkRec := bullets[i].rec //DUPLICATE RECTANGLE FOR NEXT COLLISIONS 288 | checkRec.X += bullets[i].dirX //MOVE DUPLICATE TO NEXT POSITION 289 | checkRec.Y += bullets[i].dirY 290 | 291 | //VECTOR 2 POINTS OF FOUR CORNERS OF BULLET RECTANGLE 292 | v1 := rl.NewVector2(checkRec.X, checkRec.Y) 293 | v2 := v1 294 | v2.X += bullets[i].rec.Width 295 | v3 := v2 296 | v3.Y += bullets[i].rec.Height 297 | v4 := v3 298 | v4.X -= bullets[i].rec.Width 299 | 300 | //CHECK IF VECTOR 2 HAS EXITED BORDER 301 | canmove := true 302 | if !rl.CheckCollisionPointRec(v1, borderRec) || !rl.CheckCollisionPointRec(v2, borderRec) || !rl.CheckCollisionPointRec(v3, borderRec) || !rl.CheckCollisionPointRec(v4, borderRec) { 303 | canmove = false 304 | } 305 | 306 | if canmove { 307 | bullets[i].rec = checkRec //IF NO EXITS MOVE BULLET 308 | } else { 309 | bullets[i].off = true //IF EXITED TURN BULLET OFF 310 | clear = true 311 | } 312 | } 313 | } 314 | 315 | //IF CLEAR IS ON REMOVE ALL OFF BULLETS FROM SLICE 316 | if clear { 317 | for i := 0; i < len(bullets); i++ { 318 | if bullets[i].off { 319 | bullets = remBullet(bullets, i) 320 | } 321 | } 322 | } 323 | 324 | } 325 | func movePlayer(direc int) { 326 | 327 | checkRec := playerRec //DUPLICATE PLAYER RECTANGLE 328 | 329 | //MOVE DUPLICATE IN THE DIRECTION OF KEYPRESS 330 | switch direc { 331 | case 1: //UP 332 | checkRec.Y -= spd 333 | case 2: //RIGHT 334 | checkRec.X += spd 335 | case 3: //DOWN 336 | checkRec.Y += spd 337 | case 4: //LEFT 338 | checkRec.X -= spd 339 | } 340 | 341 | //VECTOR 2 POINTS OF FOUR CORNERS OF PLAYER RECTANGLE 342 | v1 := rl.NewVector2(checkRec.X, checkRec.Y) 343 | v2 := v1 344 | v2.X += playerRec.Width 345 | v3 := v2 346 | v3.Y += playerRec.Height 347 | v4 := v3 348 | v4.X -= playerRec.Width 349 | 350 | //CHECK IF VECTOR 2 HAS EXITED BORDER 351 | canmove := true 352 | if !rl.CheckCollisionPointRec(v1, borderRec) || !rl.CheckCollisionPointRec(v2, borderRec) || !rl.CheckCollisionPointRec(v3, borderRec) || !rl.CheckCollisionPointRec(v4, borderRec) { 353 | canmove = false 354 | } 355 | 356 | if canmove { //IF NO EXITS MOVE PLAYER 357 | playerRec = checkRec 358 | } 359 | 360 | } 361 | 362 | // REMOVES BULLET FROM SLICE 363 | func remBullet(slice []xbullet, s int) []xbullet { 364 | return append(slice[:s], slice[s+1:]...) 365 | } 366 | 367 | // GET ABSOLUTE DIFFERENCE 368 | func absdiff(num1, num2 float32) float32 { 369 | num := float32(0) 370 | if num1 == num2 { 371 | num = 0 372 | } else { 373 | if num1 <= 0 && num2 <= 0 { 374 | num1 = getabs(num1) 375 | num2 = getabs(num2) 376 | if num1 > num2 { 377 | num = num1 - num2 378 | } else { 379 | num = num2 - num1 380 | } 381 | } else if num1 <= 0 && num2 >= 0 { 382 | num = num2 + getabs(num1) 383 | } else if num2 <= 0 && num1 >= 0 { 384 | num = num1 + getabs(num2) 385 | } else if num2 >= 0 && num1 >= 0 { 386 | if num1 > num2 { 387 | num = num1 - num2 388 | } else { 389 | num = num2 - num1 390 | } 391 | } 392 | } 393 | return num 394 | } 395 | 396 | // GET ABSOLUTE VALUE 397 | func getabs(value float32) float32 { 398 | value2 := float64(value) 399 | value = float32(math.Abs(value2)) 400 | return value 401 | } 402 | 403 | // RETURN RANDOM FLOAT32 BETWEEN TWO VALUES 404 | func rF32(min, max float32) float32 { 405 | min2 := float64(min) 406 | max2 := float64(max) 407 | return float32(min2 + rand.Float64()*(max2-min2)) 408 | } 409 | -------------------------------------------------------------------------------- /2D_Intermediate/motion_blur_scanlines/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - FAKE MOTION BLUR 3 | 4 | Demonstrates how to create the illusion of an image moving or slightly blurred by drawing a duplicate texture above with an offset and fade. View more at [unklnik.com](https://unklnik.com/posts/2d-motion-blur/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/1a894a12-3c1d-4730-9655-6eef85138c96 7 | -------------------------------------------------------------------------------- /2D_Intermediate/motion_blur_scanlines/imgs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/motion_blur_scanlines/imgs.png -------------------------------------------------------------------------------- /2D_Intermediate/motion_blur_scanlines/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | 7 | rl "github.com/gen2brain/raylib-go/raylib" 8 | ) 9 | 10 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 11 | 12 | https://github.com/unklnik/raylib-go-more-examples 13 | 14 | */ 15 | 16 | var ( 17 | imgs rl.Texture2D //TEXTURE TO LOAD IMAGE 18 | cntr rl.Vector2 //SCREEN CENTER 19 | fps = int32(60) //FRAMES PER SECOND OF GAME 20 | blurDistance = float32(2) //OFFSET OF BLUR IMAGE 21 | blurFade = float32(0.2) //BLUR OPACITY (FADE) 22 | scanlines []rl.Vector2 //SLICE OF VECTOR2 FOR SCAN LINES 23 | scanlineson = true //SET SCANLINES ON 24 | scanlinesFade = float32(0.5) //SCANLINES FADE 25 | currentColor int //CURRENT SCANLINE COLOR 26 | 27 | scanlineColors = []rl.Color{rl.Black, rl.Green, rl.SkyBlue, rl.LightGray} //SCANLINES COLORS 28 | ) 29 | 30 | func main() { 31 | 32 | rl.InitWindow(0, 0, "fake motion blur - raylib go - https://github.com/unklnik/raylib-go-more-examples") 33 | scrW, scrH := rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 34 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 35 | //rl.SetWindowState(rl.FlagBorderlessWindowedMode) // UNCOMMENT IF YOU HAVE DISPLAY ISSUES 36 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES 37 | 38 | cntr = rl.NewVector2(float32(scrW/2), float32(scrH/2)) //CENTER OF SCREEN 39 | imgs = rl.LoadTexture("imgs.png") //LOAD IMAGESc 40 | flagIMG := rl.NewRectangle(0, 0, 16, 16) //FLAG IMAGE RECTANGLE 41 | fireballIMG := rl.NewRectangle(16, 0, 16, 16) //FIREBALL IMAGE RECTANGLE 42 | 43 | camera := rl.Camera2D{} // DEFINES THE CAMERA 44 | camera.Zoom = 2.0 //SETS CAMERA ZOOM 45 | camera.Target = cntr //OFFSET CAMERA FROM CENTER AFTER ZOOM CHANGE 46 | camera.Offset.X = float32(scrW / 2) 47 | camera.Offset.Y = float32(scrH / 2) 48 | 49 | //CREATE SCANLINE VECTOR2 50 | scanoffset := float32(3) //SPACE BETWEEN SCANLINES 51 | y := float32(-scanoffset) //START FROM ABOVE SCREEN TOP 52 | for y < float32(scrH)+scanoffset { //END BELOW SCREEN HEIGHT 53 | scanlines = append(scanlines, rl.NewVector2(0, y)) 54 | y += scanoffset 55 | } 56 | 57 | rl.SetTargetFPS(fps) // NUMBER OF FRAMES DRAWN IN A SECOND 58 | 59 | for !rl.WindowShouldClose() { 60 | 61 | if rl.IsKeyPressed(rl.KeyZ) { //CHANGE FADE 62 | scanlinesFade += 0.1 63 | if scanlinesFade > 1 { 64 | scanlinesFade = 0.2 65 | } 66 | } 67 | if rl.IsKeyPressed(rl.KeyRight) { //CHANGE BLUR 68 | blurFade -= 0.1 69 | if blurFade <= 0.1 { 70 | blurFade = 0.8 71 | } 72 | } 73 | if rl.IsKeyPressed(rl.KeyLeft) { //CHANGE COLOR 74 | currentColor++ 75 | if currentColor == len(scanlineColors)-1 { 76 | currentColor = 0 77 | } 78 | } 79 | if rl.IsKeyPressed(rl.KeyDown) { //CHANGE BLUR DISTANCE 80 | blurDistance++ 81 | if blurDistance >= 10 { 82 | blurDistance = 1 83 | } 84 | } 85 | if rl.IsKeyPressed(rl.KeyUp) { //CHANGE ZOOM 86 | if camera.Zoom == 1 { 87 | camera.Zoom = 1.5 88 | } else if camera.Zoom == 1.5 { 89 | camera.Zoom = 2 90 | } else if camera.Zoom == 2 { 91 | camera.Zoom = 1 92 | } 93 | //ADJUST CAMERA TO CENTER IMAGE AFTER CHANGE IN ZOOM 94 | camera.Target = cntr 95 | camera.Offset.X = float32(scrW / 2) 96 | camera.Offset.Y = float32(scrH / 2) 97 | } 98 | if rl.IsKeyPressed(rl.KeySpace) { //TURN SCANLINES ON/OFF 99 | scanlineson = !scanlineson 100 | } 101 | 102 | for i := 0; i < len(scanlines); i++ { //MOVE SCANLINES DOWN BY OFFEST 103 | scanlines[i].Y += scanoffset 104 | if scanlines[i].Y > float32(scrH) { //RETURN TO ABOVE SCREEN TOP IF REACH SCREEN HEIGHT 105 | scanlines[i].Y = -scanoffset 106 | } 107 | } 108 | 109 | rl.BeginDrawing() 110 | 111 | rl.ClearBackground(rl.Black) 112 | 113 | rl.BeginMode2D(camera) 114 | 115 | size := float32(128) //IMAGE SIZE 116 | fireballRec := rl.NewRectangle(cntr.X-size/2, cntr.Y-size, size, size) //FIREBALL DRAW REC 117 | flagRec := rl.NewRectangle(cntr.X-size/2, cntr.Y, size, size) //FLAG DRAW REC 118 | 119 | fireballColor := ranOrange() //RANDOM COLOR SEE FUNCTION BELOW 120 | //DRAW ORIGINAL IMAGE 121 | rl.DrawTexturePro(imgs, fireballIMG, fireballRec, rl.Vector2Zero(), 0, fireballColor) 122 | //COPY ORIGINAL IMAGE 123 | blurRec := fireballRec 124 | //MOVE Y RANDOM DISTANCE FUNCTION BELOW 125 | blurRec.Y += rF32(-blurDistance, blurDistance) 126 | //MOVE X RANDOM DISTANCE FUNCTION BELOW 127 | blurRec.X += rF32(-blurDistance, blurDistance) 128 | rl.DrawTexturePro(imgs, fireballIMG, blurRec, rl.Vector2Zero(), 0, rl.Fade(fireballColor, blurFade)) //DRAW OFFEST IMAGE WITH FADE 129 | 130 | rl.DrawTexturePro(imgs, flagIMG, flagRec, rl.Vector2Zero(), 0, rl.White) 131 | blurRec = flagRec 132 | blurRec.Y += rF32(-blurDistance, blurDistance) 133 | blurRec.X += rF32(-blurDistance, blurDistance) 134 | rl.DrawTexturePro(imgs, flagIMG, blurRec, rl.Vector2Zero(), 0, rl.Fade(rl.White, blurFade)) 135 | 136 | rl.EndMode2D() 137 | 138 | if scanlineson { //DRAW SCANLINES 139 | for i := 0; i < len(scanlines); i++ { 140 | endV2 := rl.NewVector2(scanlines[i].X+float32(scrW), scanlines[i].Y) 141 | rl.DrawLineV(scanlines[i], endV2, rl.Fade(scanlineColors[currentColor], scanlinesFade)) 142 | } 143 | } 144 | 145 | rl.DrawText("UP key change zoom / DOWN key change blur distance / RIGHT key change blur fade / LEFT key change scanlines color / Z key change scanlines fade / SPACE key turn scanlines on/off", 10, 10, 10, rl.White) 146 | 147 | rl.DrawText("blur distance "+fmt.Sprint(blurDistance)+" blur fade "+fmt.Sprint(blurFade)+" scanlines fade "+fmt.Sprint(scanlinesFade), 10, 20, 10, rl.White) 148 | 149 | rl.EndDrawing() 150 | } 151 | 152 | rl.UnloadTexture(imgs) //UNLOAD FROM MEMORY 153 | 154 | rl.CloseWindow() 155 | } 156 | 157 | // RETURNS A RANDOM ORANGE COLOR 158 | func ranOrange() rl.Color { 159 | return rl.NewColor(uint8(255), uint8(rInt(70, 170)), uint8(rInt(0, 50)), 255) 160 | } 161 | 162 | // RETURNS A RANDOM INTEGER FOR USE IN RANDOM ORANGE COLOR FUNCTION ABOVE 163 | func rInt(min, max int) int { 164 | return min + rand.Intn(max-min) 165 | } 166 | 167 | // RETURNS A RANDOM FLOAT32 VALUE BETWEEN MIN/MAX VALUES 168 | func rF32(min, max float32) float32 { 169 | min2 := float64(min) 170 | max2 := float64(max) 171 | return float32(min2 + rand.Float64()*(max2-min2)) 172 | } 173 | -------------------------------------------------------------------------------- /2D_Intermediate/move_to_point/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - MOVE TO POINT 3 | 4 | Demonstrates how to move a player (or other object) as determined by a mouse click on screen. Simply left click on the screen and the green circle will move smoothly to the point that you have clicked. Note that this does not take into account any collisions with other objects. View more at [unklnik.com](https://unklnik.com/posts/2d-move-to-point/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/0e72d3e8-9567-4ca1-9401-41b54d08c939 7 | -------------------------------------------------------------------------------- /2D_Intermediate/move_to_point/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math" 5 | 6 | rl "github.com/gen2brain/raylib-go/raylib" 7 | ) 8 | 9 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 10 | 11 | https://github.com/unklnik/raylib-go-more-examples 12 | 13 | */ 14 | 15 | var ( 16 | scrW, scrH int // SCREEN WIDTH & HEIGHT 17 | player, cnt, clickPoint rl.Vector2 //PLAYER, SCREEN CENTER, MOUSE CLICK VECTOR2 18 | nextPosition rl.Rectangle //COLLISION RECTANGLE FOR MOVE TO POINT 19 | playerSpeed = float32(8) //MAX SPEED PLAYER MOVES 20 | playerDirX, playerDirY float32 //X & Y DIRECTION SPEEDS 21 | ) 22 | 23 | func main() { 24 | 25 | rl.InitWindow(0, 0, "move to point - raylib go - https://github.com/unklnik/raylib-go-more-examples") 26 | scrW, scrH = rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 27 | rl.SetWindowState(rl.FlagBorderlessWindowedMode) //SET WINDOW STATE 28 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 29 | 30 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 31 | 32 | camera := rl.Camera2D{} // DEFINES THE CAMERA 33 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 34 | 35 | cnt = rl.NewVector2(float32(scrW/2), float32(scrH/2)) //SCREEN CENTER 36 | player, clickPoint = cnt, cnt //SET INITIAL PLAYER & CLICKPOINT POSITIONS 37 | 38 | rl.SetTargetFPS(60) // NUMBER OF FRAMES DRAWN IN A SECOND 39 | 40 | for !rl.WindowShouldClose() { 41 | 42 | //IF LEFT MOUSE CLICKED CREATE COLLISION RECTANGLE FROM CLICK POINT 43 | if rl.IsMouseButtonPressed(rl.MouseButtonLeft) { 44 | size := float32(16) 45 | clickPoint = rl.GetMousePosition() 46 | nextPosition = rl.NewRectangle(clickPoint.X-size/2, clickPoint.Y-size/2, size, size) 47 | } 48 | 49 | //IF CLICK POINT IS NOT CENTER & PLAYER IS NOT COLLIDING WITH NEXT POSITION RECTANGLE MOVE 50 | if clickPoint != cnt && !rl.CheckCollisionPointRec(player, nextPosition) { 51 | 52 | player.X += playerDirX //MOVE X DIRECTION 53 | player.Y += playerDirY //MOVE Y DIRECTION 54 | 55 | diffX := absdiff(player.X, clickPoint.X) //ABSOLUTE DISTANCE BETWEEN X POINTS 56 | diffY := absdiff(player.Y, clickPoint.Y) //ABSOLUTE DISTANCE BETWEEN Y POINTS 57 | 58 | if diffX > diffY { //IF X DISTANCE IS LARGER THAN Y DISTANCE 59 | //DIRECTION X SPEED = PLAYER MAX SPEED 60 | playerDirX = playerSpeed 61 | //DIRECTION Y SPEED = Y DISTANCE DIVIDED BY (X DISTANCE DIVIDED BY MAX SPEED) 62 | playerDirY = diffY / (diffX / playerSpeed) 63 | } else { 64 | playerDirY = playerSpeed 65 | playerDirX = diffX / (diffY / playerSpeed) 66 | } 67 | 68 | //CHANGES TO NEGATIVE IF CLICKPOINT X IS LEFT OF PLAYER 69 | if clickPoint.X < player.X { 70 | playerDirX = -playerDirX 71 | } 72 | //CHANGES TO NEGATIVE IF CLICKPOINT Y IS ABOVE PLAYER 73 | if clickPoint.Y < player.Y { 74 | playerDirY = -playerDirY 75 | } 76 | 77 | } 78 | 79 | rl.BeginDrawing() 80 | 81 | rl.ClearBackground(rl.Black) 82 | 83 | rl.BeginMode2D(camera) 84 | 85 | if clickPoint != cnt { 86 | rl.DrawRectangleLinesEx(nextPosition, 2, rl.Magenta) //DRAW COLLISION RECTANGLE 87 | } 88 | 89 | rl.DrawCircleV(player, 32, rl.Fade(rl.Green, 0.4)) //DRAW PLAYER CIRCLE 90 | 91 | rl.DrawText("LEFT MOUSE CLICK ON THE SCREEN TO MOVE TO POINT", 10, 10, 20, rl.White) 92 | 93 | rl.EndMode2D() 94 | 95 | rl.EndDrawing() 96 | } 97 | 98 | rl.CloseWindow() 99 | } 100 | 101 | // FUNCTION TO CALCULATE ABSOLUTE DIFFERENCE BETWEEN TWO VALUES FOR NEGATIVE VALUES 102 | func absdiff(num1, num2 float32) float32 { 103 | num := float32(0) 104 | if num1 == num2 { 105 | num = 0 106 | } else { 107 | if num1 <= 0 && num2 <= 0 { 108 | num1 = getabs(num1) 109 | num2 = getabs(num2) 110 | if num1 > num2 { 111 | num = num1 - num2 112 | } else { 113 | num = num2 - num1 114 | } 115 | } else if num1 <= 0 && num2 >= 0 { 116 | num = num2 + getabs(num1) 117 | } else if num2 <= 0 && num1 >= 0 { 118 | num = num1 + getabs(num2) 119 | } else if num2 >= 0 && num1 >= 0 { 120 | if num1 > num2 { 121 | num = num1 - num2 122 | } else { 123 | num = num2 - num1 124 | } 125 | } 126 | } 127 | return num 128 | } 129 | 130 | // FUNCTION TO CALCULATE ABSOLUTE VALUE FOR NEGATIVE VALUES 131 | func getabs(value float32) float32 { 132 | value2 := float64(value) 133 | value = float32(math.Abs(value2)) 134 | return value 135 | } 136 | -------------------------------------------------------------------------------- /2D_Intermediate/move_to_point_collisions/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - MOVE TO POINT WITH COLLISIONS 3 | 4 | This demonstrates how to move a player (or other object) to a point as determined by clicking on the screen. Left mouse click on the screen and the green rectangle will move to the point, recalculating X & Y directions as it moves therefore moving smoothly. If the player (green rectangle) collides with a blue block it will adjust movement accordingly, however, note that this does not find paths. This will purely stop either X or Y, or both, movement directions, dependent on the angle of movement. This example is based on the previous example [Move to Point](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Intermediate/move_to_point) which does not take collisions into account which can be used as a starting point to complete this example. View more at [unklnik.com](https://unklnik.com/posts/2d-move-to-point-collisions/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/df27630e-ee09-4781-9cec-6d4c1c766cbd 7 | -------------------------------------------------------------------------------- /2D_Intermediate/move_to_point_collisions/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math" 5 | "math/rand" 6 | 7 | rl "github.com/gen2brain/raylib-go/raylib" 8 | ) 9 | 10 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 11 | 12 | https://github.com/unklnik/raylib-go-more-examples 13 | 14 | */ 15 | 16 | var ( 17 | scrW, scrH int // SCREEN WIDTH & HEIGHT 18 | player, cnt, clickPoint rl.Vector2 //PLAYER, SCREEN CENTER, MOUSE CLICK VECTOR2 19 | nextPosition rl.Rectangle //COLLISION RECTANGLE FOR MOVE TO POINT 20 | playerSpeed = float32(8) //MAX SPEED PLAYER MOVES 21 | playerDirX, playerDirY float32 //X & Y DIRECTION SPEEDS 22 | playerSize = float32(32) //SIZE OF PLAYER RECTANGLE 23 | playerRec rl.Rectangle //PLAYER RECTANGLE 24 | bloks []rl.Rectangle //SLICE OF COLLISION BLOKS 25 | ) 26 | 27 | func main() { 28 | 29 | rl.InitWindow(0, 0, "move to point with collisions - raylib go - https://github.com/unklnik/raylib-go-more-examples") 30 | scrW, scrH = rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 31 | rl.SetWindowState(rl.FlagBorderlessWindowedMode) //SET WINDOW STATE 32 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 33 | 34 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 35 | 36 | camera := rl.Camera2D{} // DEFINES THE CAMERA 37 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 38 | 39 | cnt = rl.NewVector2(float32(scrW/2), float32(scrH/2)) //SCREEN CENTER 40 | player, clickPoint = cnt, cnt //SET INITIAL PLAYER & CLICKPOINT POSITIONS 41 | //DEFINE PLAYER RECTANGLE AT CENTRE 42 | playerRec = rl.NewRectangle(player.X-playerSize/2, player.Y-playerSize/2, playerSize, playerSize) 43 | 44 | makebloks() //MAKES A SLICE OF BLOKS FOR COLLISIONS SEE FUNCTION BELOW 45 | 46 | rl.SetTargetFPS(60) // NUMBER OF FRAMES DRAWN IN A SECOND 47 | 48 | for !rl.WindowShouldClose() { 49 | 50 | //IF LEFT MOUSE CLICKED CREATE COLLISION RECTANGLE FROM CLICK POINT 51 | if rl.IsMouseButtonPressed(rl.MouseButtonLeft) { 52 | size := float32(16) 53 | clickPoint = rl.GetMousePosition() 54 | nextPosition = rl.NewRectangle(clickPoint.X-size/2, clickPoint.Y-size/2, size, size) 55 | } 56 | 57 | //IF CLICK POINT IS NOT CENTER & PLAYER IS NOT COLLIDING WITH NEXT POSITION RECTANGLE MOVE 58 | if clickPoint != cnt && !rl.CheckCollisionPointRec(player, nextPosition) { 59 | 60 | diffX := absdiff(player.X, clickPoint.X) //ABSOLUTE DISTANCE BETWEEN X POINTS 61 | diffY := absdiff(player.Y, clickPoint.Y) //ABSOLUTE DISTANCE BETWEEN Y POINTS 62 | 63 | if diffX > diffY { //IF X DISTANCE IS LARGER THAN Y DISTANCE 64 | //DIRECTION X SPEED = PLAYER MAX SPEED 65 | playerDirX = playerSpeed 66 | //DIRECTION Y SPEED = Y DISTANCE DIVIDED BY (X DISTANCE DIVIDED BY MAX SPEED) 67 | playerDirY = diffY / (diffX / playerSpeed) 68 | } else { 69 | playerDirY = playerSpeed 70 | playerDirX = diffX / (diffY / playerSpeed) 71 | } 72 | 73 | //CHANGES TO NEGATIVE IF CLICKPOINT X IS LEFT OF PLAYER 74 | if clickPoint.X < player.X { 75 | playerDirX = -playerDirX 76 | } 77 | //CHANGES TO NEGATIVE IF CLICKPOINT Y IS ABOVE PLAYER 78 | if clickPoint.Y < player.Y { 79 | playerDirY = -playerDirY 80 | } 81 | 82 | if checkmove("x") { //CHECKS FOR X MOVEMENT AGAINST BLOK COLLISIONS SEE FUNCTION BELOW 83 | player.X += playerDirX //MOVE X DIRECTION 84 | } 85 | if checkmove("y") { //CHECKS FOR Y MOVEMENT AGAINST BLOK COLLISIONS SEE FUNCTION BELOW 86 | player.Y += playerDirY //MOVE Y DIRECTION 87 | } 88 | 89 | playerRec = rl.NewRectangle(player.X-playerSize/2, player.Y-playerSize/2, playerSize, playerSize) //DEFINE RECTANGLE IN NEW POSITION 90 | 91 | } 92 | 93 | rl.BeginDrawing() 94 | 95 | rl.ClearBackground(rl.Black) 96 | 97 | rl.BeginMode2D(camera) 98 | 99 | //DRAW THE SLICE OF COLLISION BLOKS 100 | for i := 0; i < len(bloks); i++ { 101 | rl.DrawRectangleRec(bloks[i], rl.Fade(rl.SkyBlue, 0.4)) 102 | rl.DrawRectangleLinesEx(bloks[i], 4, rl.SkyBlue) 103 | } 104 | 105 | if clickPoint != cnt { 106 | rl.DrawRectangleLinesEx(nextPosition, 2, rl.Magenta) //DRAW COLLISION RECTANGLE 107 | } 108 | 109 | //DRAW PLAYER RECTANGLE 110 | rl.DrawRectangleRec(playerRec, rl.Fade(rl.Green, 0.5)) 111 | rl.DrawRectangleLinesEx(playerRec, 4, rl.Green) 112 | 113 | rl.DrawText("LEFT MOUSE CLICK ON THE SCREEN TO MOVE TO POINT", 10, 10, 20, rl.White) 114 | 115 | rl.EndMode2D() 116 | 117 | rl.EndDrawing() 118 | } 119 | 120 | rl.CloseWindow() 121 | } 122 | 123 | // CHECKS FOR NEXT X & Y MOVEMENTS AGAINST SLICE OF BLOKS 124 | func checkmove(direc string) bool { 125 | 126 | canmove := true //RETURN VALUE 127 | checkRec := playerRec //RECTANGLE FOR CHECKING NEXT MOVE 128 | 129 | switch direc { 130 | case "x": 131 | checkRec.X += playerDirX //MOVE CHECK RECTANGLE X TO NEXT POSITION 132 | case "y": 133 | checkRec.Y += playerDirY //MOVE CHECK RECTANGLE Y TO NEXT POSITION 134 | } 135 | 136 | //CHECK NEXT POSITION OF PLAYER AGAINST SLICE OF COLLISION BLOKS 137 | for i := 0; i < len(bloks); i++ { 138 | if rl.CheckCollisionRecs(checkRec, bloks[i]) { 139 | canmove = false 140 | } 141 | } 142 | 143 | return canmove 144 | } 145 | 146 | // MAKES A SLICE OF RECTANGLES IN RANDOM POSITIONS 147 | func makebloks() { 148 | 149 | num := rInt(20, 31) 150 | for { 151 | canadd := true //FOR CHECKING COLLISIONS AGAINST OTHER BLOKS ALREADY ADDED TO SLICE 152 | countbreak := 100 //IN CASE THE FOR LOOP GETS STUCK 153 | size := rF32(32, 128) //RANDOM BLOCK SIZE SEE FUNCTION BELOW 154 | //DEFINE BLOK RECTANGLE 155 | rec := rl.NewRectangle(rF32(0, float32(scrW)-size), rF32(0, float32(scrH)-size), size, size) 156 | //CHECK FOR COLLISIONS WITH PLAYER REC 157 | if rl.CheckCollisionRecs(rec, playerRec) { 158 | canadd = false //IF COLLIDES WITH PLAYER DON'T ADD 159 | } 160 | //IF DOES NOT COLLIDE WITH PLAYER THEN CHECK FOR EXISTING BLOK COLLISIONS 161 | if canadd { 162 | //IF SLICE OF BLOKS IS LARGER THAN 1 CHECK FOR COLLISIONS OF EXISTING BLOKS IN SLICE 163 | if len(bloks) > 1 { 164 | for i := 0; i < len(bloks); i++ { 165 | if rl.CheckCollisionRecs(rec, bloks[i]) { 166 | canadd = false //IF COLLIDES WITH EXISTING BLOK DON'T ADD 167 | } 168 | } 169 | } 170 | } 171 | 172 | if canadd { 173 | bloks = append(bloks, rec) //IF NO COLLISIONS ADD TO SLICE 174 | num-- //REDUCE NUMBER OF BLOKS LEFT TO ADD 175 | } 176 | 177 | countbreak-- //REDUCE COUNTBREAK IN CASE OF ERRORS 178 | 179 | if num == 0 || countbreak == 0 { //IF ALL BLOKS ADDED OR COUNTBREAK REACHED BREAK 180 | break 181 | } 182 | 183 | } 184 | 185 | } 186 | 187 | // FUNCTION THAT RETURNS RANDOM FLOAT32 BETWEEN MIN & MAX VALUES 188 | func rF32(min, max float32) float32 { 189 | min2 := float64(min) 190 | max2 := float64(max) 191 | return float32(min2 + rand.Float64()*(max2-min2)) 192 | } 193 | 194 | // FUNCTION THAT RETURNS RANDOM INTEGER BETWEEN MIN & MAX VALUES 195 | func rInt(min, max int) int { 196 | return min + rand.Intn(max-min) 197 | } 198 | 199 | // FUNCTION TO CALCULATE ABSOLUTE DIFFERENCE BETWEEN TWO VALUES FOR NEGATIVE VALUES 200 | func absdiff(num1, num2 float32) float32 { 201 | num := float32(0) 202 | if num1 == num2 { 203 | num = 0 204 | } else { 205 | if num1 <= 0 && num2 <= 0 { 206 | num1 = getabs(num1) 207 | num2 = getabs(num2) 208 | if num1 > num2 { 209 | num = num1 - num2 210 | } else { 211 | num = num2 - num1 212 | } 213 | } else if num1 <= 0 && num2 >= 0 { 214 | num = num2 + getabs(num1) 215 | } else if num2 <= 0 && num1 >= 0 { 216 | num = num1 + getabs(num2) 217 | } else if num2 >= 0 && num1 >= 0 { 218 | if num1 > num2 { 219 | num = num1 - num2 220 | } else { 221 | num = num2 - num1 222 | } 223 | } 224 | } 225 | return num 226 | } 227 | 228 | // FUNCTION TO CALCULATE ABSOLUTE VALUE FOR NEGATIVE VALUES 229 | func getabs(value float32) float32 { 230 | value2 := float64(value) 231 | value = float32(math.Abs(value2)) 232 | return value 233 | } 234 | -------------------------------------------------------------------------------- /2D_Intermediate/moving_triangles/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - MOVING POLYGON TRIANGLES 3 | 4 | Makes use of *rl.DrawPoly* to create a line of moving triangles - change direction using the **W A S D keys**. This is the easier method, as opposed to using *rl.DrawTriangle*, as you do not have to recalculate the Vector2 points on direction change. The change direction movement is rough and could definitely be improved however it demonstrates the usage. View more at [unklnik.com](https://unklnik.com/posts/2d-moving-triangles/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/89cab52c-0e7e-4815-a26a-376bec85f388 7 | -------------------------------------------------------------------------------- /2D_Intermediate/moving_triangles/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | rl "github.com/gen2brain/raylib-go/raylib" 5 | ) 6 | 7 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 8 | 9 | https://github.com/unklnik/raylib-go-more-examples 10 | 11 | */ 12 | 13 | var ( 14 | vel = float32(8) // SPEED 15 | cntr rl.Vector2 // CENTER OF SCREEN 16 | triangles []xtri // SLICE OF TRIANGLE INFORMATION TO CREATE TRIANGLE POLYGONS (NOT POINTS) 17 | scrW, scrH int // SCREEN WIDTH & HEIGHT 18 | size = float32(32) // RADIUS OF POLYGON CIRCLE 19 | fade = float32(1.0) // COLOR FADE OF TRIANGLE POLYGON FILL 20 | direc = 3 // DIRECTION OF MOVEMENT 21 | 22 | /* DIREC STARTS AT 1 (UP) MOVES CLOCKWISE 23 | 1 UP 24 | 4 LEFT 2 RIGHT 25 | 3 DOWN 26 | */ 27 | ) 28 | 29 | type xtri struct { 30 | rad, ro float32 // RADIUS & ROTATION 31 | col rl.Color // COLOR 32 | cnt rl.Vector2 // CENTER 33 | } 34 | 35 | func main() { 36 | 37 | rl.InitWindow(0, 0, "moving triangles - raylib go - https://github.com/unklnik/raylib-go-more-examples") 38 | scrW, scrH = rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 39 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 40 | 41 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 42 | 43 | cntr = rl.NewVector2(float32(scrW/2), float32(scrH/2)) // CALCULATE CENTER 44 | 45 | camera := rl.Camera2D{} // DEFINES THE CAMERA 46 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 47 | 48 | rl.SetTargetFPS(60) // NUMBER OF FRAMES DRAWN IN A SECOND 49 | 50 | makeTriangles() // MAKE THE SLICE OF TRIANGLES 51 | 52 | for !rl.WindowShouldClose() { 53 | 54 | upTriangles() // AFTER rl.WindowShouldClose UPDATES MOVEMENT & INPUT SEE FUNCTION BELOW 55 | 56 | rl.BeginDrawing() 57 | 58 | rl.ClearBackground(rl.Black) 59 | 60 | rl.BeginMode2D(camera) 61 | 62 | rl.DrawText("W A S D keys change direction", 16, 16, 20, rl.White) 63 | 64 | for a := 0; a < len(triangles); a++ { // RANGE OVER SLICE OF TRIANGLES 0 TILL END 65 | // DRAW POLYGON TRIANGLE 66 | rl.DrawPoly(triangles[a].cnt, 3, triangles[a].rad, triangles[a].ro, rl.Fade(triangles[a].col, fade)) 67 | // DRAW POLYGON TRIANGLE OUTLINE 68 | rl.DrawPolyLinesEx(triangles[a].cnt, 3, triangles[a].rad, triangles[a].ro, 10, rl.Orange) 69 | } 70 | 71 | rl.EndMode2D() 72 | 73 | rl.EndDrawing() 74 | } 75 | 76 | rl.CloseWindow() 77 | } 78 | 79 | func upTriangles() { // UPDATES MOVEMENT & INPUT 80 | 81 | // FADE IN AND OUT 82 | if fade > 0.5 { 83 | fade -= 0.01 84 | } else { 85 | fade = 1 86 | } 87 | 88 | if rl.IsKeyPressed(rl.KeyW) { // CHANGE DIREC TO UP ON W KEY PRESS 89 | if direc != 1 { 90 | direc = 1 91 | for a := 0; a < len(triangles); a++ { 92 | triangles[a].ro = 180 // ROTATE 93 | 94 | // CHANGE POSITION OF TRIANGES 1,2,3 OF SLICE (NOT 0 - FIRST) TO FOLLOW 0 (FIRST) 95 | if a > 0 { 96 | // Y = PREVIOUS TRIANGE Y - OFFSET DISTANCE 97 | triangles[a].cnt.Y = triangles[a-1].cnt.Y + (size * 2) 98 | // X = PREVIOUS TRIANGE X 99 | triangles[a].cnt.X = triangles[a-1].cnt.X 100 | } 101 | } 102 | } 103 | } 104 | if rl.IsKeyPressed(rl.KeyD) { // CHANGE DIREC TO RIGHT ON D KEY PRESS 105 | direc = 2 106 | for a := 0; a < len(triangles); a++ { 107 | triangles[a].ro = 90 // ROTATE 108 | 109 | // CHANGE POSITION OF TRIANGES 1,2,3 OF SLICE (NOT 0 - FIRST) TO FOLLOW 0 (FIRST) 110 | if a > 0 { 111 | // Y = PREVIOUS TRIANGLE Y 112 | triangles[a].cnt.Y = triangles[a-1].cnt.Y 113 | // X = PREVIOUS TRIANGE X - OFFSET DISTANCE 114 | triangles[a].cnt.X = triangles[a-1].cnt.X - (size * 2) 115 | } 116 | } 117 | } 118 | if rl.IsKeyPressed(rl.KeyS) { // CHANGE DIREC TO DOWN ON S KEY PRESS 119 | direc = 3 120 | for a := 0; a < len(triangles); a++ { 121 | triangles[a].ro = 0 // ROTATE 122 | 123 | // CHANGE POSITION OF TRIANGES 1,2,3 OF SLICE (NOT 0 - FIRST) TO FOLLOW 0 (FIRST) 124 | if a > 0 { 125 | // Y = PREVIOUS TRIANGE Y - OFFSET DISTANCE 126 | triangles[a].cnt.Y = triangles[a-1].cnt.Y - (size * 2) 127 | // X = PREVIOUS TRIANGE X 128 | triangles[a].cnt.X = triangles[a-1].cnt.X 129 | } 130 | } 131 | } 132 | if rl.IsKeyPressed(rl.KeyA) { // CHANGE DIREC TO LEFT ON A KEY PRESS 133 | direc = 4 134 | for a := 0; a < len(triangles); a++ { 135 | triangles[a].ro = 270 // ROTATE 136 | 137 | // CHANGE POSITION OF TRIANGES 1,2,3 OF SLICE (NOT 0 - FIRST) TO FOLLOW 0 (FIRST) 138 | if a > 0 { 139 | // Y = PREVIOUS TRIANGLE Y 140 | triangles[a].cnt.Y = triangles[a-1].cnt.Y 141 | // X = PREVIOUS TRIANGE X + OFFSET DISTANCE 142 | triangles[a].cnt.X = triangles[a-1].cnt.X + (size * 2) 143 | } 144 | } 145 | } 146 | 147 | // MOVES CENTER OF POLYGON & CHECKS FOR SCREEN EXIT 148 | for a := 0; a < len(triangles); a++ { 149 | switch direc { 150 | case 1: // UP 151 | triangles[a].cnt.Y -= vel // MOVES CENTER Y UP 152 | // IF CENTER.Y IS SMALLER THAN -(SIZE/2) MOVE TO SCREEN HEIGHT + SIZE/2 153 | if triangles[a].cnt.Y < -size/2 { 154 | triangles[a].cnt.Y = float32(scrH) + size/2 155 | } 156 | case 2: // RIGHT 157 | triangles[a].cnt.X += vel // MOVES CENTER X RIGHT 158 | // IF CENTER.X IS LARGER THAN SCREEN WIDTH + SIZE/2 MOVE TO -(SIZE/2) 159 | if triangles[a].cnt.X > float32(scrW)+size/2 { 160 | triangles[a].cnt.X = -size / 2 161 | } 162 | case 3: // DOWN 163 | triangles[a].cnt.Y += vel // MOVES CENTER Y DOWN 164 | // IF CENTER.Y IS LARGER THAN SCREEN HEIGHT + SIZE/2 MOVE TO -(SIZE/2) 165 | if triangles[a].cnt.Y > float32(scrH)+size/2 { 166 | triangles[a].cnt.Y = -size / 2 167 | } 168 | case 4: // LEFT 169 | triangles[a].cnt.X -= vel // MOVES CENTER X LEFT 170 | // IF CENTER.X IS SMALLER THAN -(SIZE/2) MOVE TO SCREEN WIDTH + SIZE/2 171 | if triangles[a].cnt.X < -size/2 { 172 | triangles[a].cnt.X = float32(scrW) + size/2 173 | } 174 | } 175 | } 176 | } 177 | 178 | func makeTriangles() { 179 | 180 | ztri := xtri{} 181 | ztri.rad = size // RADIUS 182 | ztri.ro = 0 // DEFAULT ROTATION 183 | ztri.col = rl.Green // COLOR 184 | 185 | ztri.cnt = cntr // SET CENTER TO SCREEN CENTER 186 | triangles = append(triangles, ztri) // ADD TO SLICE 187 | 188 | ztri.cnt.Y += size * 2 // MOVE CENTER.Y DOWN BY SIZE X 2 189 | triangles = append(triangles, ztri) // ADD TO MOVED TRI VERSION TO SLICE 190 | 191 | ztri.cnt.Y += size * 2 // MOVE CENTER.Y DOWN BY SIZE X 2 192 | triangles = append(triangles, ztri) // ADD TO MOVED TRI VERSION TO SLICE 193 | 194 | ztri.cnt.Y += size * 2 // MOVE CENTER.Y DOWN BY SIZE X 2 195 | triangles = append(triangles, ztri) // ADD TO MOVED TRI VERSION TO SLICE 196 | } 197 | -------------------------------------------------------------------------------- /2D_Intermediate/orbiting/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - ORBITING 3 | 4 | Demonstrates three circles orbiting a center point with change in direction and change in orbit speed - press space key. 5 | View more at [unklnik.com](https://unklnik.com/posts/2d-orbiting/) 6 | 7 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/5dcba837-3940-48e8-a0de-02032f2bbaf1 8 | -------------------------------------------------------------------------------- /2D_Intermediate/orbiting/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math" 5 | "math/rand" 6 | 7 | rl "github.com/gen2brain/raylib-go/raylib" 8 | ) 9 | 10 | var ( 11 | cntr rl.Vector2 // CENTER OF SCREEN 12 | scrW, scrH int // SCREEN WIDTH & HEIGHT 13 | 14 | orbitV2one, orbitV2two, orbitV2three rl.Vector2 //CENTER VECTOR2's OF 3 ORBITING CIRCLES 15 | angle1, angle2, angle3 float32 //ANGLE FROM CENTER 16 | radius1, radius2, radius3 float32 //RADIUS OF 3 ORBITING CIRCLES 17 | angleChange1, angleChange2, angleChange3 float32 //CHANGE IN ROTATION ANGLE PER FRAME (SPEED) 18 | color1, color2, color3 rl.Color //COLOR OF 3 ORBITING CIRCLES 19 | changeDir1, changeDir2, changeDir3 bool //SWITCH TO ROTATE LEFT/RIGHT 20 | ) 21 | 22 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 23 | 24 | https://github.com/unklnik/raylib-go-more-examples 25 | 26 | */ 27 | 28 | func main() { 29 | 30 | rl.InitWindow(0, 0, "orbiting - raylib go - https://github.com/unklnik/raylib-go-more-examples") 31 | scrW, scrH = rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 32 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 33 | 34 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 35 | 36 | cntr = rl.NewVector2(float32(scrW/2), float32(scrH/2)) // CALCULATE CENTER 37 | 38 | makeV2() //MAKE INITIAL 3 ORBITING CIRCLES 39 | 40 | camera := rl.Camera2D{} // DEFINES THE CAMERA 41 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 42 | 43 | rl.SetTargetFPS(60) // NUMBER OF FRAMES DRAWN IN A SECOND 44 | 45 | for !rl.WindowShouldClose() { 46 | 47 | upV2() //UPDATE MOVEMENT 3 ORBITING CIRCLES 48 | 49 | if rl.IsKeyPressed(rl.KeySpace) { 50 | changeDir1 = flipcoin() //TRUE FALSE FLIP COIN ON KEY PRESS 51 | changeDir2 = flipcoin() 52 | changeDir3 = flipcoin() 53 | angleChange1 = rF32(0.5, 4) //RANDOM CHANGE IN ROTATION ANGLE 54 | angleChange2 = rF32(0.5, 4) 55 | angleChange3 = rF32(0.5, 4) 56 | } 57 | 58 | rl.BeginDrawing() 59 | 60 | rl.ClearBackground(rl.Black) 61 | 62 | rl.BeginMode2D(camera) 63 | 64 | rl.DrawCircleV(orbitV2one, radius1, color1) //DRAW ORIBITING CIRCLE OUTER 65 | rl.DrawCircleV(orbitV2two, radius2, color2) //DRAW ORIBITING CIRCLE MIDDLE 66 | rl.DrawCircleV(orbitV2three, radius3, color3) //DRAW ORIBITING CIRCLE INNER 67 | 68 | //CREATE CENTER CROSS LINES 69 | colorLine := ranCol() //RANDOM COLOR SEE FUNCTION BELOW 70 | //VERTICAL LINE 71 | linev1 := cntr //VECTOR2 EQUALS SCREEN CENTER 72 | linev1.Y -= 10 //MOVE VECTOR2 Y UP BY HALF LINE LENGTH 73 | linev2 := linev1 //NEW VECTOR2 EQUALS LINEV1 74 | linev2.Y += 20 //MOVE VECTOR2 Y DOWN BY LINE LENGTH 75 | //HORIZONTAL LINE 76 | linev3 := cntr //VECTOR2 EQUALS SCREEN CENTER 77 | linev3.X -= 10 //MOVE VECTOR2 X LEFT BY HALF LINE LENGTH 78 | linev4 := linev3 //NEW VECTOR2 EQUALS LINEV3 79 | linev4.X += 20 //MOVE VECTOR2 X RIGHT BY LINE LENGTH 80 | 81 | rl.DrawLineV(linev1, linev2, colorLine) //DRAW VERTICAL LINE 82 | rl.DrawLineV(linev3, linev4, colorLine) //DRAW HORIZONTAL LINE 83 | 84 | rl.DrawText("press space to change direction", 10, 10, 20, rl.White) //TEXT 85 | 86 | rl.EndMode2D() 87 | 88 | rl.EndDrawing() 89 | } 90 | 91 | rl.CloseWindow() 92 | } 93 | 94 | func upV2() { //UPDATES MOVEMENT OF ORBITING CIRCLES 95 | 96 | //COMPLICATED MATH I COPIED & CHANGED FROM SOMEWHERE ELSE 97 | angle1 = angle1 * (math.Pi / 180) 98 | newx := float32(math.Cos(float64(angle1)))*(orbitV2one.X-cntr.X) - float32(math.Sin(float64(angle1)))*(orbitV2one.Y-cntr.Y) + cntr.X 99 | newy := float32(math.Sin(float64(angle1)))*(orbitV2one.X-cntr.X) + float32(math.Cos(float64(angle1)))*(orbitV2one.Y-cntr.Y) + cntr.Y 100 | orbitV2one = rl.NewVector2(newx, newy) 101 | 102 | //CHANGE ORBIT LEFT RIGHT 103 | if changeDir1 { 104 | angle1 -= angleChange1 105 | } else { 106 | angle1 += angleChange1 107 | } 108 | 109 | angle2 = angle2 * (math.Pi / 180) 110 | newx = float32(math.Cos(float64(angle2)))*(orbitV2two.X-cntr.X) - float32(math.Sin(float64(angle2)))*(orbitV2two.Y-cntr.Y) + cntr.X 111 | newy = float32(math.Sin(float64(angle2)))*(orbitV2two.X-cntr.X) + float32(math.Cos(float64(angle2)))*(orbitV2two.Y-cntr.Y) + cntr.Y 112 | orbitV2two = rl.NewVector2(newx, newy) 113 | 114 | if changeDir2 { 115 | angle2 -= angleChange2 116 | } else { 117 | angle2 += angleChange2 118 | } 119 | 120 | angle3 = angle3 * (math.Pi / 180) 121 | newx = float32(math.Cos(float64(angle3)))*(orbitV2three.X-cntr.X) - float32(math.Sin(float64(angle3)))*(orbitV2three.Y-cntr.Y) + cntr.X 122 | newy = float32(math.Sin(float64(angle3)))*(orbitV2three.X-cntr.X) + float32(math.Cos(float64(angle3)))*(orbitV2three.Y-cntr.Y) + cntr.Y 123 | orbitV2three = rl.NewVector2(newx, newy) 124 | 125 | if changeDir3 { 126 | angle3 -= angleChange3 127 | } else { 128 | angle3 += angleChange3 129 | } 130 | 131 | } 132 | func makeV2() { 133 | width := float32(scrH / 2) //DISTANCE FROM CENTER = HALF SCREEN HEIGHT 134 | width -= width / 4 //DISTANCE FROM CENTER SUBTRACT QUARTER OF ORIGINAL LENGTH 135 | orbitV2one = rl.NewVector2(cntr.X+width, cntr.Y) //CREATE CENTER VECTOR2 OF ORBITING CIRCLE 136 | angle1 = rF32(0, 360) //RANDOM START ANGLE SEE rF32 FUNCTION BELOW 137 | radius1 = rF32(20, 40) //RANDOM START RADIUS 138 | color1 = ranCol() //RANDOM START COLOR SEE FUNCTION BELOW 139 | angleChange1 = rF32(0.5, 4) //RANDOM START ROTATION ANGLE CHANGE (SPEED) 140 | 141 | width = float32(scrH / 2) 142 | width -= width / 2 143 | orbitV2two = rl.NewVector2(cntr.X+width, cntr.Y) 144 | angle2 = rF32(0, 360) 145 | radius2 = rF32(20, 40) 146 | color2 = ranCol() 147 | angleChange2 = rF32(0.5, 4) 148 | 149 | width = float32(scrH / 2) 150 | width -= (width / 4) * 3 151 | orbitV2three = rl.NewVector2(cntr.X+width, cntr.Y) 152 | angle3 = rF32(0, 360) 153 | radius3 = rF32(20, 40) 154 | color3 = ranCol() 155 | angleChange3 = rF32(0.5, 4) 156 | 157 | } 158 | 159 | // RETURNS A RANDOM r.Color VALUE 160 | func ranCol() rl.Color { 161 | return rl.NewColor(uint8(rInt(0, 256)), uint8(rInt(0, 256)), uint8(rInt(0, 256)), 255) 162 | } 163 | 164 | // RETURNS RANDOM INTEGER VALUE 165 | func rInt(min, max int) int { 166 | return min + rand.Intn(max-min) 167 | } 168 | 169 | // RETURNS RANDOM FLOAT32 VALUE 170 | func rF32(min, max float32) float32 { 171 | min2 := float64(min) 172 | max2 := float64(max) 173 | return float32(min2 + rand.Float64()*(max2-min2)) 174 | } 175 | 176 | // RETURNS RANDOM TRUE/FALSE 177 | func flipcoin() bool { 178 | onoff := false 179 | choose := rInt(0, 100001) 180 | if choose > 50000 { 181 | onoff = true 182 | } 183 | return onoff 184 | } 185 | -------------------------------------------------------------------------------- /2D_Intermediate/player_bullets/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - PLAYER BULLETS 3 | 4 | Demonstrates how to create player bullets that will travel to a point determined by a mouse click on screen. This method works with a camera, using the screen to world position of the mouse click therefore the zoom can be changed. The player can move and the bullets will be destroyed when hitting the border rectangle. This can be used for both player bullets as well as enemy bullets, for enemy bullets the mouse click center point is substituted with the player center. WASD keys move player, left mouse button to shoot and up arrow key to change zoom. View more at [unklnik.com](https://unklnik.com/posts/2d-player-bullets/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/33cde057-e662-4c05-a5c9-4cf889df4cea 7 | -------------------------------------------------------------------------------- /2D_Intermediate/player_bullets/player_bullets.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math" 5 | 6 | rl "github.com/gen2brain/raylib-go/raylib" 7 | ) 8 | 9 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 10 | 11 | https://github.com/unklnik/raylib-go-more-examples 12 | 13 | */ 14 | 15 | var ( 16 | bullets []xbullet //SLICE OF BULLET STRUCTS 17 | shootTarget, cursorCam, cursor rl.Vector2 //TARGET, CURSOR CAMERA VS SCREEN POSITION, CURSOR 18 | playerRec rl.Rectangle //PLAYER RECTANGLE 19 | spd = float32(10) //MAX SPEED 20 | attackT int32 //PAUSE BETWEEN BULLETS 21 | fps = int32(60) //FRAMES PER SECOND 22 | camera rl.Camera2D //CAMERA 23 | borderRec rl.Rectangle //BOUNCING & BORDER RECTANGLES 24 | cntr rl.Vector2 //CENTER OF SCREEN 25 | scrW, scrH int 26 | ) 27 | 28 | // STRUCT OF BULLET CONTAINING REC, DIRECTION X & Y, OFF BOOL 29 | type xbullet struct { 30 | rec rl.Rectangle 31 | dirX, dirY float32 32 | off bool 33 | } 34 | 35 | func main() { 36 | 37 | rl.InitWindow(0, 0, "player bullets - raylib go - https://github.com/unklnik/raylib-go-more-examples") 38 | scrW, scrH = rl.GetScreenWidth(), rl.GetScreenHeight() //GET SCREEN SIZES 39 | rl.SetWindowSize(scrW, scrH) //SET WINDOW SIZE 40 | rl.SetWindowState(rl.FlagBorderlessWindowedMode) 41 | //rl.ToggleFullscreen() //UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 42 | 43 | rl.HideCursor() //HIDE THE STANDARD MOUSE CURSOR 44 | 45 | cntr = rl.NewVector2(float32(scrW/2), float32(scrH/2)) //CALCULATE CENTER 46 | 47 | borderRec = rl.NewRectangle(cntr.X-float32(scrW/4), cntr.Y-float32(scrH/4), float32(scrW/2), float32(scrH/2)) //DEFINE BORDER RECTANGLE 48 | 49 | siz := float32(32) //PLAYER SIZE 50 | playerRec = rl.NewRectangle(cntr.X-siz/2, cntr.Y-siz/2, siz, siz) //INITIAL PLAYER RECTANGLE 51 | 52 | camera.Zoom = 1.5 //SETS CAMERA ZOOM 53 | camera.Target = cntr //SET CAMERA TARGET 54 | camera.Offset.X = float32(scrW / 2) //ADJUST CAMERA FOR ZOOM 55 | camera.Offset.Y = float32(scrH / 2) //ADJUST CAMERA FOR ZOOM 56 | 57 | rl.SetTargetFPS(fps) //NUMBER OF FRAMES DRAWN IN A SECOND 58 | 59 | for !rl.WindowShouldClose() { 60 | 61 | cursor = rl.GetMousePosition() //GET MOUSE POSITION 62 | cursorCam = rl.GetScreenToWorld2D(cursor, camera) //GET MOUSE POSITION IN CAMERA SPACE WITH ZOOM 63 | 64 | upBullets() //UPDATE BULLET MOVEMENTS 65 | input() //CAPTURE INPUT 66 | 67 | //TIMER 68 | if attackT > 0 { //PAUSE BETWEEN SHOTS TIMER 69 | attackT-- 70 | } 71 | 72 | rl.BeginDrawing() 73 | 74 | rl.ClearBackground(rl.Black) 75 | 76 | rl.BeginMode2D(camera) 77 | 78 | rl.DrawRectangleLinesEx(borderRec, 4, rl.Green) //DRAWS BORDER REC 79 | 80 | rl.DrawRectangleLinesEx(playerRec, 8, rl.Magenta) //DRAW PLAYER REC 81 | 82 | //DRAW BULLETS 83 | for i := 0; i < len(bullets); i++ { 84 | rl.DrawRectangleLinesEx(bullets[i].rec, 2, rl.Yellow) 85 | } 86 | 87 | //DRAW CIRCLE TARGET INSTEAD OF CURSOR 88 | rl.DrawCircleLines(int32(cursorCam.X), int32(cursorCam.Y), 10, rl.Red) 89 | 90 | rl.EndMode2D() 91 | 92 | rl.DrawText("W A S D keys move", 10, 10, 20, rl.White) 93 | rl.DrawText("left mouse to shoot", 10, 40, 20, rl.White) 94 | rl.DrawText("up arrow key change zoom", 10, 70, 20, rl.White) 95 | 96 | rl.EndDrawing() 97 | } 98 | 99 | rl.CloseWindow() 100 | } 101 | func input() { 102 | //INPUT KEYS FOR PLAYER MOVEMENT SEE MOVEPLAYER FUNCTION 103 | if rl.IsKeyDown(rl.KeyW) { 104 | movePlayer(1) 105 | 106 | } else if rl.IsKeyDown(rl.KeyS) { 107 | movePlayer(3) 108 | } 109 | if rl.IsKeyDown(rl.KeyD) { 110 | movePlayer(2) 111 | } else if rl.IsKeyDown(rl.KeyA) { 112 | movePlayer(4) 113 | } 114 | 115 | //CREATE BULLET IF ATTACK TIMER IS ZERO 116 | if rl.IsMouseButtonPressed(rl.MouseLeftButton) && attackT == 0 { 117 | attackT = fps / 4 118 | shootTarget = cursorCam //POSITION FOR BULLET AIMING 119 | shoot() 120 | } 121 | 122 | //CHANGE ZOOM 123 | if rl.IsKeyPressed(rl.KeyUp) { 124 | if camera.Zoom == 2 { 125 | camera.Zoom = 1 126 | } else if camera.Zoom == 1.5 { 127 | camera.Zoom = 2 128 | } else if camera.Zoom == 1 { 129 | camera.Zoom = 1.5 130 | } 131 | camera.Target = cntr 132 | camera.Offset.X = float32(scrW / 2) 133 | camera.Offset.Y = float32(scrH / 2) 134 | } 135 | } 136 | 137 | // CREATE BULLET FUNCTION 138 | func shoot() { 139 | zbullet := xbullet{} 140 | zbullet.rec = playerRec //DUPLICATE PLAYER RECTANGLE FOR BULLET 141 | 142 | //MAKE DUPLICATE RECTANGLE SMALLER 143 | zbullet.rec.X += playerRec.Width / 2 144 | zbullet.rec.Y += playerRec.Height / 2 145 | zbullet.rec.Width = zbullet.rec.Width / 2 146 | zbullet.rec.Height = zbullet.rec.Height / 2 147 | 148 | //CALCULATE X & Y SPEED TO MOVE TO SHOOT TARGET 149 | playerCntr := rl.NewVector2(playerRec.X+playerRec.Width/2, playerRec.Y+playerRec.Height/2) 150 | diffX := absdiff(playerCntr.X, shootTarget.X) //GET ABSOLUTE X DISTANCE FUNCTION BELOW 151 | diffY := absdiff(playerCntr.Y, shootTarget.Y) //GET ABSOLUTE Y DISTANCE FUNCTION BELOW 152 | 153 | if diffX > diffY { 154 | zbullet.dirX = spd //IF DIFFERENCE X IS LARGER X IS FULL SPEED 155 | zbullet.dirY = diffY / (diffX / zbullet.dirX) //CALCULATE Y SPEED 156 | } else { 157 | zbullet.dirY = spd //IF DIFFERENCE Y IS LARGER Y IS FULL SPEED 158 | zbullet.dirX = diffX / (diffY / zbullet.dirY) //CALCULATE X SPEED 159 | } 160 | 161 | //IF TARGET IS BEHIND PLAYER CHANGE X DIRECTION TO NEGATIVE 162 | if playerCntr.X > shootTarget.X { 163 | zbullet.dirX = -zbullet.dirX 164 | } 165 | 166 | //IF TARGET IS ABOVE PLAYER CHANGE Y DIRECTION TO NEGATIVE 167 | if playerCntr.Y > shootTarget.Y { 168 | zbullet.dirY = -zbullet.dirY 169 | } 170 | 171 | //ADD BULLET TO SLICE 172 | bullets = append(bullets, zbullet) 173 | } 174 | 175 | func upBullets() { 176 | 177 | clear := false //TO CLEAR BULLETS IF COLLISIONS 178 | for i := 0; i < len(bullets); i++ { 179 | 180 | if !bullets[i].off { 181 | checkRec := bullets[i].rec //DUPLICATE RECTANGLE FOR NEXT COLLISIONS 182 | checkRec.X += bullets[i].dirX //MOVE DUPLICATE TO NEXT POSITION 183 | checkRec.Y += bullets[i].dirY 184 | 185 | //VECTOR 2 POINTS OF FOUR CORNERS OF BULLET RECTANGLE 186 | v1 := rl.NewVector2(checkRec.X, checkRec.Y) 187 | v2 := v1 188 | v2.X += bullets[i].rec.Width 189 | v3 := v2 190 | v3.Y += bullets[i].rec.Height 191 | v4 := v3 192 | v4.X -= bullets[i].rec.Width 193 | 194 | //CHECK IF VECTOR 2 HAS EXITED BORDER 195 | canmove := true 196 | if !rl.CheckCollisionPointRec(v1, borderRec) || !rl.CheckCollisionPointRec(v2, borderRec) || !rl.CheckCollisionPointRec(v3, borderRec) || !rl.CheckCollisionPointRec(v4, borderRec) { 197 | canmove = false 198 | } 199 | 200 | if canmove { 201 | bullets[i].rec = checkRec //IF NO EXITS MOVE BULLET 202 | } else { 203 | bullets[i].off = true //IF EXITED TURN BULLET OFF 204 | clear = true 205 | } 206 | } 207 | } 208 | 209 | //IF CLEAR IS ON REMOVE ALL OFF BULLETS FROM SLICE 210 | if clear { 211 | for i := 0; i < len(bullets); i++ { 212 | if bullets[i].off { 213 | bullets = remBullet(bullets, i) 214 | } 215 | } 216 | } 217 | 218 | } 219 | func movePlayer(direc int) { 220 | 221 | checkRec := playerRec //DUPLICATE PLAYER RECTANGLE 222 | 223 | //MOVE DUPLICATE IN THE DIRECTION OF KEYPRESS 224 | switch direc { 225 | case 1: //UP 226 | checkRec.Y -= spd 227 | case 2: //RIGHT 228 | checkRec.X += spd 229 | case 3: //DOWN 230 | checkRec.Y += spd 231 | case 4: //LEFT 232 | checkRec.X -= spd 233 | } 234 | 235 | //VECTOR 2 POINTS OF FOUR CORNERS OF PLAYER RECTANGLE 236 | v1 := rl.NewVector2(checkRec.X, checkRec.Y) 237 | v2 := v1 238 | v2.X += playerRec.Width 239 | v3 := v2 240 | v3.Y += playerRec.Height 241 | v4 := v3 242 | v4.X -= playerRec.Width 243 | 244 | //CHECK IF VECTOR 2 HAS EXITED BORDER 245 | canmove := true 246 | if !rl.CheckCollisionPointRec(v1, borderRec) || !rl.CheckCollisionPointRec(v2, borderRec) || !rl.CheckCollisionPointRec(v3, borderRec) || !rl.CheckCollisionPointRec(v4, borderRec) { 247 | canmove = false 248 | } 249 | 250 | if canmove { //IF NO EXITS MOVE PLAYER 251 | playerRec = checkRec 252 | } 253 | 254 | } 255 | 256 | // REMOVES BULLET FROM SLICE 257 | func remBullet(slice []xbullet, s int) []xbullet { 258 | return append(slice[:s], slice[s+1:]...) 259 | } 260 | 261 | // GET ABSOLUTE DIFFERENCE 262 | func absdiff(num1, num2 float32) float32 { 263 | num := float32(0) 264 | if num1 == num2 { 265 | num = 0 266 | } else { 267 | if num1 <= 0 && num2 <= 0 { 268 | num1 = getabs(num1) 269 | num2 = getabs(num2) 270 | if num1 > num2 { 271 | num = num1 - num2 272 | } else { 273 | num = num2 - num1 274 | } 275 | } else if num1 <= 0 && num2 >= 0 { 276 | num = num2 + getabs(num1) 277 | } else if num2 <= 0 && num1 >= 0 { 278 | num = num1 + getabs(num2) 279 | } else if num2 >= 0 && num1 >= 0 { 280 | if num1 > num2 { 281 | num = num1 - num2 282 | } else { 283 | num = num2 - num1 284 | } 285 | } 286 | } 287 | return num 288 | } 289 | 290 | // GET ABSOLUTE VALUE 291 | func getabs(value float32) float32 { 292 | value2 := float64(value) 293 | value = float32(math.Abs(value2)) 294 | return value 295 | } 296 | -------------------------------------------------------------------------------- /2D_Intermediate/simple_dungeon_map/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - SIMPLE DUNGEON MAP 3 | 4 | Demonstrates how to create a simple dungeon map of room rectangles for use in top-down games. Press SPACE to create a new map, every map will be different from the next map and you can change the number of rooms and map size easily to allow for creation of larger or smaller maps. This is used as the base for a more advanced tutorial with image tiling and players [Tiled Dungeon Map with Player](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Advanced/tiled_dungeon_map_with_player). View more at [unklnik.com](https://unklnik.com/posts/2d-simple-dungeon-map/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/91747abd-5c43-45f6-bf53-1900c9435d01 7 | -------------------------------------------------------------------------------- /2D_Intermediate/simple_dungeon_map/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | 7 | rl "github.com/gen2brain/raylib-go/raylib" 8 | ) 9 | 10 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 11 | 12 | https://github.com/unklnik/raylib-go-more-examples 13 | 14 | */ 15 | 16 | var ( 17 | scrW, scrH int // SCREEN WIDTH & HEIGHT 18 | cnt rl.Vector2 // SCREEN CENTER 19 | rooms []rl.Rectangle // SLICE OF ROOM RECTANGLES 20 | baseUnit = float32(32) // BASE UNIT FOR DETERMINING SIZES FOR TILING 21 | min, max = 3, 12 // MIN MAX TILE SIZE OR ROOM SIDES 22 | borderRec rl.Rectangle // BORDER RECTANGLE TO ENSURE ROOMS REMAIN ON SCREEN 23 | ) 24 | 25 | func main() { 26 | 27 | rl.InitWindow(0, 0, "simple dungeon map - raylib go - https://github.com/unklnik/raylib-go-more-examples") 28 | scrW, scrH = rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 29 | rl.SetWindowState(rl.FlagBorderlessWindowedMode) //SET WINDOW STATE 30 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 31 | 32 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 33 | 34 | camera := rl.Camera2D{} // DEFINES THE CAMERA 35 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 36 | 37 | cnt = rl.NewVector2(float32(scrW/2), float32(scrH/2)) //SCREEN CENTER 38 | 39 | borderRec = rl.NewRectangle(0, 0, float32(scrW), float32(scrH)) //DEFINE BORDER RECTANGLE 40 | // MAKE BORDER REC SLIGHLTLY SMALLER SO ROOMS DONT REACH EDGES FOR TILING 41 | borderRec.X += baseUnit 42 | borderRec.Y += baseUnit 43 | borderRec.Width -= baseUnit * 2 44 | borderRec.Height -= baseUnit * 2 45 | 46 | makerooms() //CREATE INITIAL SLICE OF ROOMS SEE FUNC BELOW 47 | 48 | rl.SetTargetFPS(60) // NUMBER OF FRAMES DRAWN IN A SECOND 49 | 50 | for !rl.WindowShouldClose() { 51 | 52 | if rl.IsKeyPressed(rl.KeySpace) { 53 | makerooms() //PRESS SPACE TO MAKE NEW SET OF ROOMS 54 | } 55 | 56 | rl.BeginDrawing() 57 | 58 | rl.ClearBackground(rl.Black) 59 | 60 | rl.BeginMode2D(camera) 61 | for i := 0; i < len(rooms); i++ { // DRAW SLICE OF ROOM RECTANGLES 62 | rl.DrawRectangleRec(rooms[i], rl.Fade(rl.Green, 0.2)) 63 | rl.DrawRectangleLinesEx(rooms[i], 1, rl.White) 64 | rl.DrawText("room "+fmt.Sprint(i), rooms[i].ToInt32().X+8, rooms[i].ToInt32().Y+8, 20, rl.White) // DRAW ROOM NUMBER TEXT 65 | } 66 | 67 | rl.DrawRectangleLinesEx(borderRec, 2, rl.Magenta) // DRAW BORDER RECTANGLE 68 | 69 | rl.EndMode2D() 70 | 71 | rl.DrawText("PRESS SPACE TO MAKE ANOTHER MAP", 10, 10, 20, rl.White) 72 | 73 | rl.EndDrawing() 74 | } 75 | 76 | rl.CloseWindow() 77 | } 78 | 79 | func makerooms() { 80 | rooms = nil // CLEAR ROOM SLICE 81 | Wnum := rInt(min, max) // NUMBER TO TILES IN ROOM WALL WIDTH 82 | Hnum := rInt(min, max) // NUMBER OF TILES IN ROOM WALL HEIGHT 83 | 84 | W := float32(Wnum) * baseUnit // CALCULATE WIDTH 85 | H := float32(Hnum) * baseUnit // CALCULATE HEIGHT 86 | rooms = append(rooms, rl.NewRectangle(cnt.X-W/2, cnt.Y-H/2, W, H)) // CREATE CENTER ROOM REC 87 | 88 | num := rInt(7, 15) // RANDOM NUMBER OF ROOMS 89 | //num = 1 90 | countbreak := 100 // COUNT TO BREAK LOOP IF ROOMS CANNOT BE FOUND 91 | chooseroom := 0 // NUMBER OF BASE ROOM THAT NEXT ROOM IS ATTACHED TO 92 | 93 | for num > 0 { 94 | 95 | Wnum = rInt(min, max) 96 | Hnum = rInt(min, max) 97 | 98 | W = float32(Wnum) * baseUnit 99 | H = float32(Hnum) * baseUnit 100 | 101 | if len(rooms) > 1 { // IF MORE THAN ONE ROOM RANDOMLY CHOOSE NEXT BASE ROOM FROM EXISTING ROOMS 102 | chooseroom = rInt(0, len(rooms)) 103 | } 104 | x := rooms[chooseroom].X // SET X VALUE FOR NEXT REC FROM BASE REC 105 | y := rooms[chooseroom].Y // SET Y VALUE FOR NEXT REC FROM BASE REC 106 | 107 | choose := rInt(1, 5) // CHOOSE SIDE OF BASE REC TO ATTACH NEXT REC TO 108 | 109 | numWprevRoom := int(rooms[chooseroom].Width / baseUnit) // DETERMINE NUMBER OF TILES IN PREVIOUS ROOM WIDTH 110 | numHprevRoom := int(rooms[chooseroom].Height / baseUnit) // DETERMINE NUMBER OF TILES IN PREVIOUS ROOM HEIGHT 111 | 112 | switch choose { 113 | case 1: //ABOVE 114 | y -= H //MOVE NEW REC ABOVE 115 | if W <= rooms[chooseroom].Width { // IF WIDTH SMALLER THAN PREV REC 116 | change := rInt(-(Wnum - 1), Wnum) // DETERMINE RANDOM X MOVEMENT LEFT/RIGHT LEAVING A ONE TILE SPACE FOR DOOR/PASSAGE 117 | x += float32(change) * baseUnit 118 | } else { // IF WIDTH LARGER THAN PREV REC 119 | change := rInt(-(Wnum - 1), numWprevRoom) // DETERMINE RANDOM X MOVEMENT LEFT/RIGHT LEAVING A ONE TILE SPACE FOR DOOR/PASSAGE 120 | x += float32(change) * baseUnit 121 | } 122 | rec := rl.NewRectangle(x, y, W, H) 123 | if checkaddroom(rec) { // CHECK IF REC COLLIDES WITH OTHER RECS OR BORDER FUNCTION BELOW 124 | rooms = append(rooms, rec) 125 | num-- 126 | } 127 | case 2: //RIGHT 128 | x += rooms[chooseroom].Width //MOVE NEW REC RIGHT 129 | if H <= rooms[chooseroom].Height { // IF HEIGHT SMALLER THAN PREV REC 130 | change := rInt(-(Hnum - 1), Hnum) // DETERMINE RANDOM Y MOVEMENT UP/DOWN LEAVING A ONE TILE SPACE FOR DOOR/PASSAGE 131 | y += float32(change) * baseUnit 132 | } else { 133 | change := rInt(-(Hnum - 1), numHprevRoom) // DETERMINE RANDOM Y MOVEMENT UP/DOWN LEAVING A ONE TILE SPACE FOR DOOR/PASSAGE 134 | y += float32(change) * baseUnit 135 | } 136 | rec := rl.NewRectangle(x, y, W, H) 137 | if checkaddroom(rec) { // CHECK IF REC COLLIDES WITH OTHER RECS OR BORDER FUNCTION BELOW 138 | rooms = append(rooms, rec) 139 | num-- 140 | } 141 | case 3: //BELOW 142 | y += rooms[chooseroom].Height 143 | if W <= rooms[chooseroom].Width { 144 | change := rInt(-(Wnum - 1), Wnum) 145 | x += float32(change) * baseUnit 146 | } else { 147 | change := rInt(-(Wnum - 1), numWprevRoom) 148 | x += float32(change) * baseUnit 149 | } 150 | rec := rl.NewRectangle(x, y, W, H) 151 | if checkaddroom(rec) { 152 | rooms = append(rooms, rec) 153 | num-- 154 | } 155 | case 4: //LEFT 156 | x -= W 157 | if H <= rooms[chooseroom].Height { 158 | change := rInt(-(Hnum - 1), Hnum) 159 | y += float32(change) * baseUnit 160 | } else { 161 | change := rInt(-(Hnum - 1), numHprevRoom) 162 | y += float32(change) * baseUnit 163 | } 164 | rec := rl.NewRectangle(x, y, W, H) 165 | if checkaddroom(rec) { 166 | rooms = append(rooms, rec) 167 | num-- 168 | } 169 | 170 | } 171 | countbreak-- 172 | if countbreak == 0 { 173 | break 174 | } 175 | 176 | } 177 | } 178 | func checkaddroom(rec rl.Rectangle) bool { 179 | canadd := true 180 | 181 | // CREATE VECTOR2 OF 4 CORNERS OF NEW ROOM RECTANGLE 182 | v1 := rl.NewVector2(rec.X, rec.Y) 183 | v2 := v1 184 | v2.X += rec.Width 185 | v3 := v2 186 | v3.Y += rec.Height 187 | v4 := v3 188 | v4.X -= rec.Width 189 | 190 | if !rl.CheckCollisionPointRec(v1, borderRec) || !rl.CheckCollisionPointRec(v2, borderRec) || !rl.CheckCollisionPointRec(v3, borderRec) || !rl.CheckCollisionPointRec(v4, borderRec) { 191 | canadd = false // IF A CORNER EXITS BORDER DON'T ADD 192 | } 193 | 194 | if canadd { 195 | for i := 0; i < len(rooms); i++ { 196 | if rl.CheckCollisionRecs(rec, rooms[i]) { 197 | canadd = false // NEW ROOM REC COLLIDES WITH EXISTING ROOM REC DON'T ADD 198 | } 199 | } 200 | } 201 | 202 | return canadd 203 | } 204 | 205 | // RETURNS RANDOM INTEGER 206 | func rInt(min, max int) int { 207 | return min + rand.Intn(max-min) 208 | } 209 | -------------------------------------------------------------------------------- /2D_Intermediate/snow/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 2D - SNOWFLAKES FALLING 3 | 4 | Draws textures (images) of snowflakes falling at random speeds with random rotations and sizes. Turn on/off random colors with SPACE key and turn on/off blur effect using TAB key. View more at [unklnik.com](https://unklnik.com/posts/2d-snow/) 5 | 6 | https://github.com/unklnik/raylib-go-more-examples/assets/146096950/4be2a97a-0978-4965-be05-0677649d1efb 7 | -------------------------------------------------------------------------------- /2D_Intermediate/snow/imgs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unklnik/raylib-go-more-examples/4fa9693a7345210e3b42f03992fd6d24bf5a3cf5/2D_Intermediate/snow/imgs.png -------------------------------------------------------------------------------- /2D_Intermediate/snow/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math/rand" 5 | 6 | rl "github.com/gen2brain/raylib-go/raylib" 7 | ) 8 | 9 | /* MORE RAYLIB GO EXAMPLES ARE AVAILABLE HERE: 10 | 11 | https://github.com/unklnik/raylib-go-more-examples 12 | 13 | */ 14 | 15 | var ( 16 | scrW, scrH int // SCREEN WIDTH & HEIGHT 17 | snow []snowflake //SLICE OF SNOWFLAKE STRUCTS 18 | colorsOn, blurOn bool //COLORS & BLUR ON/OFF 19 | 20 | imgs rl.Texture2D 21 | 22 | snowflakeIMG1 = rl.NewRectangle(0, 0, 17, 17) //DEFINE SNOWFLAKE IMAGE 1 RECTANGLE IN imgs.png 23 | snowflakeIMG2 = rl.NewRectangle(18, 1, 15, 15) //DEFINE SNOWFLAKE IMAGE 2 RECTANGLE IN imgs.png 24 | snowflakeIMG3 = rl.NewRectangle(34, 1, 15, 15) //DEFINE SNOWFLAKE IMAGE 3 RECTANGLE IN imgs.png 25 | ) 26 | 27 | // STRUCT HOLDS ALL THE INFORMATION FOR EACH SNOWFLAKE 28 | type snowflake struct { 29 | img, rec, drawrec rl.Rectangle //RECTANGLES TO DISPLAY IMAGE 30 | ro, speed, roSpeed, fade float32 //ROTATION/FALL SPEED/ROTATION SPEED/FADE 31 | origin rl.Vector2 //ORIGIN OF DRAW RECTANGLE FOR ROTATION 32 | color rl.Color //SNOWFLAKE ALT COLOR 33 | leftright bool //ROTATE LEFT OR RIGTH 34 | } 35 | 36 | func main() { 37 | 38 | rl.InitWindow(0, 0, "snow - raylib go - https://github.com/unklnik/raylib-go-more-examples") 39 | scrW, scrH = rl.GetScreenWidth(), rl.GetScreenHeight() // GET SCREEN SIZES 40 | rl.SetWindowSize(scrW, scrH) // SET WINDOW SIZE 41 | 42 | //rl.ToggleFullscreen() // UNCOMMENT IF YOU HAVE DISPLAY ISSUES WITH OVERLAPPING WINDOW BARS 43 | 44 | camera := rl.Camera2D{} // DEFINES THE CAMERA 45 | camera.Zoom = 1.0 //SETS CAMERA ZOOM 46 | 47 | imgs = rl.LoadTexture("imgs.png") //LOAD SNOWFLAKE IMAGES 48 | 49 | rl.SetTargetFPS(60) // NUMBER OF FRAMES DRAWN IN A SECOND 50 | 51 | makeSnow() //CREATE SLICE OF SNOWFLAKES SEE END OF CODE 52 | 53 | for !rl.WindowShouldClose() { 54 | 55 | if rl.IsKeyPressed(rl.KeySpace) { //COLORS ON/OFF 56 | colorsOn = !colorsOn 57 | } 58 | if rl.IsKeyPressed(rl.KeyTab) { //BLUR ON/OFF 59 | blurOn = !blurOn 60 | } 61 | 62 | rl.BeginDrawing() 63 | 64 | rl.ClearBackground(rl.Black) 65 | 66 | rl.BeginMode2D(camera) 67 | 68 | upSnow() //DRAW & UPDATE SNOW MOVEMENT & ROTATION SEE END OF CODE 69 | 70 | rl.DrawText("SPACE KEY TO CHANGE COLOR / WHITE", 10, 10, 20, rl.White) 71 | rl.DrawText("TAB KEY TO TURN BLUR ON/OFF", 10, 40, 20, rl.White) 72 | 73 | rl.EndMode2D() 74 | 75 | rl.EndDrawing() 76 | } 77 | 78 | rl.UnloadTexture(imgs) //UNLOAD FROM MEMORY 79 | 80 | rl.CloseWindow() 81 | } 82 | 83 | func makeSnow() { 84 | 85 | num := 100 //NUMBER OF SNOWFLAKES 86 | 87 | for num > 0 { //CREATES A SNOWFLAKE WITH RANDOM VALUES & ADDS (APPENDS) TO SNOW SLICE 88 | 89 | newSnow := snowflake{} //CREATE INSTANCE 90 | size := rF32(32, 128) //DEFINE RANDOM SIZE FOR USE IN RECTANGLE 91 | 92 | //CREATE RECTANGLE AT TOP LEFT OF SCREEN / SUBTRACT SIZE MOVES ABOVE SCREEN TOP 93 | newSnow.rec = rl.NewRectangle(0, -size, size, size) 94 | //MOVE REC.X RANDOM DISTANCE FROM LEFT - BETWEEN 0 & (SCREEN WIDTH - SIZE) 95 | newSnow.rec.X += rF32(0, float32(scrW)-size) 96 | //MOVE REC.Y RANDOM DISTANCE AWAY FROM SCREEN TOP - STAGGER FALLING EFFECT 97 | newSnow.rec.Y -= rF32(0, size*20) 98 | //CREATE A DRAW RECTANGLE FOR ROTATION 99 | newSnow.drawrec = newSnow.rec 100 | //ADJUST DRAW RECTANGLE OFFSET 101 | newSnow.drawrec.X += newSnow.drawrec.Width / 2 102 | newSnow.drawrec.Y += newSnow.drawrec.Height / 2 103 | //CREATE ORIGIN (CENTER) FOR ROTATION 104 | newSnow.origin = rl.NewVector2(newSnow.drawrec.Width/2, newSnow.drawrec.Height/2) 105 | 106 | newSnow.color = ranCol() //RANDOM SECOND COLOR SEE FUNCTION BELOW 107 | newSnow.fade = rF32(0.3, 0.6) //RANDOM TRANSPARENCY 108 | newSnow.speed = rF32(3, 8) //RANDOM FALL SPEED 109 | newSnow.ro = rF32(0, 360) //RANDOM INITIAL ROTATION ANGLE 110 | newSnow.roSpeed = rF32(1, 4) //RANDOM ROTATION SPEED 111 | newSnow.leftright = flipcoin() //CHOOSE LEFT RIGHT ROTATION 112 | 113 | choose := rInt(1, 4) //CHOOSE SNOWFLAKE IMAGE 114 | switch choose { 115 | case 1: 116 | newSnow.img = snowflakeIMG1 117 | case 2: 118 | newSnow.img = snowflakeIMG2 119 | case 3: 120 | newSnow.img = snowflakeIMG3 121 | } 122 | 123 | snow = append(snow, newSnow) // ADD TO SLICE 124 | 125 | num-- 126 | } 127 | 128 | } 129 | 130 | // DRAW & UPDATE SNOW 131 | func upSnow() { 132 | 133 | for i := 0; i < len(snow); i++ { //RANGE OVER SNOWFLAKE SLICE UPDATING & DRAWING EACH SNOWFLAKE 134 | 135 | if colorsOn { //DRAW COLOR SNOWFLAKES 136 | rl.DrawTexturePro(imgs, snow[i].img, snow[i].drawrec, snow[i].origin, snow[i].ro, rl.Fade(snow[i].color, snow[i].fade)) 137 | 138 | if blurOn { //ADDITIONAL IMAGE FOR FAKE BLUR EFFECT 139 | blurRec := snow[i].drawrec //DUPLICATE DRAW RECTANGLE 140 | blurRec.X += rF32(-5, 5) //MOVE DUPLICATE REC X RANDOM AMOUNT 141 | blurRec.Y += rF32(-5, 5) //MOVE DUPLICATE REC Y RANDOM AMOUNT 142 | 143 | //DRAW ON TOP OF ORIGINAL IMAGE WITH LOWER FADE VALUES & SAME COLOR 144 | rl.DrawTexturePro(imgs, snow[i].img, blurRec, snow[i].origin, snow[i].ro, rl.Fade(snow[i].color, rF32(0.1, 0.3))) 145 | } 146 | } else { //DRAW WHITE SNOWFLAKES 147 | rl.DrawTexturePro(imgs, snow[i].img, snow[i].drawrec, snow[i].origin, snow[i].ro, rl.Fade(rl.White, snow[i].fade)) 148 | 149 | if blurOn { 150 | blurRec := snow[i].drawrec 151 | blurRec.X += rF32(-5, 5) 152 | blurRec.Y += rF32(-5, 5) 153 | rl.DrawTexturePro(imgs, snow[i].img, blurRec, snow[i].origin, snow[i].ro, rl.Fade(rl.White, rF32(0.1, 0.3))) 154 | } 155 | } 156 | 157 | if snow[i].leftright { 158 | snow[i].ro += snow[i].roSpeed //RIGHT ROTATATION 159 | } else { 160 | snow[i].ro -= snow[i].roSpeed //LEFT ROTATATION 161 | } 162 | 163 | snow[i].drawrec.Y += snow[i].speed //MOVE DOWN 164 | 165 | //IF SNOWFLAKE EXITS SCREEN MOVE BACK TO A RANDOM HEIGHT ABOVE TOP OF SCREEN 166 | if snow[i].drawrec.Y > float32(scrH) { 167 | snow[i].drawrec.Y = rF32(-snow[i].drawrec.Height*20, -snow[i].drawrec.Height) 168 | } 169 | 170 | } 171 | 172 | } 173 | 174 | // SIMULATES FLIPCOIN HEAD/TAILS / ON/OFF / LEFT/RIGHT 175 | func flipcoin() bool { 176 | onoff := false 177 | choose := rInt(0, 100001) 178 | if choose > 50000 { 179 | onoff = true 180 | } 181 | return onoff 182 | } 183 | 184 | // RETURNS A RANDOM COLOR 185 | func ranCol() rl.Color { 186 | return rl.NewColor(uint8(rInt(0, 256)), uint8(rInt(0, 256)), uint8(rInt(0, 256)), 255) 187 | } 188 | 189 | // RETURNS A RANDOM INTEGER BETWEEN MIN/MAX VALUES FOR USE IN ranCol() 190 | func rInt(min, max int) int { 191 | return min + rand.Intn(max-min) 192 | } 193 | 194 | // RETURNS A RANDOM FLOAT32 BETWEEN MIN/MAX VALUES 195 | func rF32(min, max float32) float32 { 196 | min2 := float64(min) 197 | max2 := float64(max) 198 | return float32(min2 + rand.Float64()*(max2-min2)) 199 | } 200 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 unklnik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Additional Examples for Raylib Go 2 | 3 | A compilation of examples on how to use the Go bindings for Raylib (https://github.com/gen2brain/raylib-go). 4 | 5 | This is intended as a resource to help beginners learn some basic Raylib and Go game development skills. If you want to use any of the code anywhere else, feel free to do so. As there are fairly few resources related to making games with Go/Golang this is intended to help people who may be interested in learning Go for making games or for people that already know how to code in Go and want to make games for fun or want to implement more advanced graphics in applications. Note that Raylib can also be used to create UI (user interfaces), data visualizations and other things and is not strictly limited to making games, Raylib serves to make working with OpenGL with Go much easier. There is no GUI (Graphical User Interface) for Raylib and this means that you do need to be able to understand and code in Go to make games using Raylib. 6 | 7 | If you need help and don't know already the [Raylib Cheatsheet](https://www.raylib.com/cheatsheet/cheatsheet.html) is useful and a good resource for finding information on Raylib functions and (generally) the same function is available in Go, just add **rl.** in the beginning (prefix). 8 | 9 | *I am a self-taught Go programmer and do it as a hobby, the code here is my own interpretation of how to do something, probably not the only way or the best way. If you have any suggestions or spot any errors then please let me know.* 10 | 11 | **2D BEGINNER** 12 | - [Random Color Grid](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Beginner/random_color_grid) - Random color blocks background 13 | - [Moving Space Background](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Beginner/stars_background) - Shooting stars/space background 14 | - [Text Center & Scroll](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Beginner/text_cntr_scroll) - Text resize, center & scroll left/right/up 15 | - [Vector2 Collisions](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Beginner/vector2_collisions) - Collisions of rectangle versus border rectangle using Vector2 points 16 | - [Room Tiles](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Beginner/room_tiles) - Creates randomly sized room and draws tile textures for the walls and floor 17 | - [Pixel Noise](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Beginner/pixel_noise) - Simulates pixel noise / screen artifacts with color & size change 18 | - [Animated Character](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Beginner/animated_character) - Simple animated sprite character with speed, color & zoom change 19 | - [Exploding Blocks](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Beginner/exploding_blocks) - Create the effect of blocks exploding using slices of structs 20 | - [Rectangle Collisions](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Beginner/rec_collisions) - Checks for collisions between moving rectangles & borders 21 | 22 | **2D INTERMEDIATE** 23 | - [Moving Triangles](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Intermediate/moving_triangles) - Illustrates moving polygon triangles with direction change 24 | - [Orbiting](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Intermediate/orbiting) - Three circles orbiting center point with direction change 25 | - [Snow](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Intermediate/snow) - Draws falling snowflakes using textures with color change & blur effect 26 | - [Candlelight](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Intermediate/candlelight) - Create the illusion of candelight 27 | - [Motion Blur](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Intermediate/motion_blur_scanlines) - Create the illusion of motion blur 28 | - [Move to Point](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Intermediate/move_to_point) - Demonstrates moving to point determined by a mouse click on screen 29 | - [Move to Point Collisions](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Intermediate/move_to_point_collisions) - Demonstrates moving to point determined by a mouse click with collisions 30 | - [Player Bullets](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Intermediate/player_bullets) - Demonstrates bullets determined by mouse click on screen with camera & player movement 31 | - [Chain Lightning](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Intermediate/chain_lightning) - Demonstrates simple chain lightning effect, drawing lines between enemy centers on hit 32 | - [Animated Logo](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Intermediate/animated_logo) - Demonstrates side scrolling Go logo & animated Raylib logo 33 | - [Simple Dungeon Map](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Intermediate/simple_dungeon_map) - Demonstrates creation of a simple top-down dungeon map 34 | 35 | **2D ADVANCED** 36 | - [Tile Editor](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Advanced/tile_editor) - Tile sheet loading & grid drawing 37 | - [Moving Spike Block](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Advanced/moving_spike_block) - Creates a moving block with spikes inside a room with player collisions 38 | - [Menus & Windows](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Advanced/menus_windows) - Demonstrates simple top/bottom, left/right, pop-up and center menu/windows 39 | - [Tiled Dungeon Map with Player](https://github.com/unklnik/raylib-go-more-examples/tree/main/2D_Advanced/tiled_dungeon_map_with_player) - Creates random dungeon with image tiles & moving player 40 | 41 |
42 | --------------------------------------------------------------------------------