package game import ( "context" "fmt" "math/rand" "sync" "git.wisellama.rocks/Project-Ely/project-ely/internal/channels" "git.wisellama.rocks/Project-Ely/project-ely/internal/game/entity/animation" "git.wisellama.rocks/Project-Ely/project-ely/internal/game/entity/command" "git.wisellama.rocks/Project-Ely/project-ely/internal/game/entity/types" "git.wisellama.rocks/Project-Ely/project-ely/internal/game/player" "git.wisellama.rocks/Project-Ely/project-ely/internal/game/sprite" "git.wisellama.rocks/Wisellama/gosimpleconf" rl "github.com/gen2brain/raylib-go/raylib" ) type EntityCmdHandler interface { Run() CloseRequests() CommandRequest() chan command.Command DrawRequest() chan struct{} DrawResponse() chan struct{} UpdateRequest() chan struct{} UpdateResponse() chan struct{} } // Run is the main function to start the game. func Run(ctx context.Context, configMap gosimpleconf.ConfigMap) error { ctx, cancel := context.WithCancel(ctx) defer cancel() framerate64 := gosimpleconf.Int64(configMap["game.framerate"]) framerate := int32(framerate64) // Initialize the RayLib window channels.RL.Do(func() { rl.InitWindow(800, 600, configMap["game.title"]) rl.SetTargetFPS(framerate) }) defer func() { channels.RL.Do(func() { rl.CloseWindow() }) }() // Initialize our sprites and animations sprite.InitSpriteCache() animation.DefineAnimations() entityList := make([]EntityCmdHandler, 0) wg := sync.WaitGroup{} playerPenguinEntity := types.NewPenguin() playerPenguinEntity.SetSpeed(2) playerPenguinEntity.SetPosition(rl.Vector2{X: 100, Y: -100}) playerPenguinCmd := command.NewCommandHandler(ctx, &playerPenguinEntity) playerPenguin := player.NewPlayer(ctx) playerPenguin.SetEntityChan(playerPenguinCmd.CommandRequest()) entityList = append(entityList, playerPenguinCmd) wg.Add(1) go func() { defer wg.Done() playerPenguinCmd.Run() }() for i := 0; i < 10; i++ { entity := types.NewPenguin() entityCmd := command.NewCommandHandler(ctx, &entity) randomPos := rl.Vector2{X: rand.Float32() * 500, Y: rand.Float32() * -500} entity.SetPosition(randomPos) entity.SetAnimation(rand.Intn(animation.PENGUIN_NUM_ANIMS)) entityList = append(entityList, entityCmd) wg.Add(1) go func() { defer wg.Done() entityCmd.Run() }() } // And now starting the main loop running := true for running { channels.RL.Do(func() { if rl.WindowShouldClose() { cancel() } }) // Allow us to exit early if the context is done select { case <-ctx.Done(): running = false default: // Keep running } if !running { break } // Update players playerPenguin.Update() // Start drawing channels.RL.Do(func() { rl.BeginDrawing() }) // Tell everything to Update and Draw for _, e := range entityList { e.UpdateRequest() <- struct{}{} e.DrawRequest() <- struct{}{} } // Wait for each entity to finish their Draw and Update commands before proceeding for _, e := range entityList { <-e.UpdateResponse() <-e.DrawResponse() } // Finish drawing channels.RL.Do(func() { rl.ClearBackground(rl.Black) rl.DrawText("Some Text!", 190, 200, 20, rl.Blue) rl.DrawText(fmt.Sprintf("%v FPS", rl.GetFPS()), 190, 250, 20, rl.Blue) rl.EndDrawing() }) } for _, e := range entityList { e.CloseRequests() } sprite.CleanupSpriteCache() wg.Wait() return nil }