project-ely/internal/game.go

147 lines
3.5 KiB
Go

package internal
import (
"context"
"fmt"
"log"
"math/rand"
"git.wisellama.rocks/Project-Ely/project-ely/internal/animation"
"git.wisellama.rocks/Project-Ely/project-ely/internal/channels"
"git.wisellama.rocks/Project-Ely/project-ely/internal/entity"
"git.wisellama.rocks/Project-Ely/project-ely/internal/player"
"git.wisellama.rocks/Project-Ely/project-ely/internal/sprite"
"git.wisellama.rocks/Project-Ely/project-ely/internal/version"
"git.wisellama.rocks/Wisellama/gosimpleconf"
rl "github.com/gen2brain/raylib-go/raylib"
)
// Drawable can be rendered with OpenGL. See the 'entity' and 'animation' packages.
type Drawable interface {
Draw() error
}
// Object can have physical interactions. See the 'entity' and 'physics' packages.
type Object interface {
Update() error
}
// Run is the main function to start the game.
func Run(ctx context.Context, configMap gosimpleconf.ConfigMap) error {
var err error
ctx, cancel := context.WithCancel(ctx)
defer cancel()
framerate64 := gosimpleconf.Int64(configMap["game.framerate"])
framerate := int32(framerate64)
windowTitle := fmt.Sprintf("%s - %s (%s)",
configMap["game.title"],
version.Version,
version.CommitHash,
)
// Initialize the RayLib window
channels.RL.Do(func() {
monitor := rl.GetCurrentMonitor()
windowWidth := int32(rl.GetMonitorWidth(monitor))
windowHeight := int32(rl.GetMonitorHeight(monitor))
rl.InitWindow(windowWidth, windowHeight, windowTitle)
rl.ToggleFullscreen()
rl.SetTargetFPS(framerate)
})
defer func() {
channels.RL.Do(func() {
rl.CloseWindow()
})
}()
// Initialize our sprites and animations
sprite.InitSpriteCache()
animation.DefineAnimations()
drawables := make([]Drawable, 0)
objects := make([]Object, 0)
center := rl.Vector2{X: float32(rl.GetScreenWidth()) / 2, Y: float32(rl.GetScreenHeight()) / 2 * -1}
player1 := player.NewPlayer(ctx)
player1Penguin := entity.NewPenguin()
player1Penguin.SetColor(rl.Gold)
player1Penguin.GetObject().SetPosition(center)
player1.SetControlledObject(player1Penguin.GetObject())
drawables = append(drawables, player1Penguin)
objects = append(objects, player1Penguin)
for i := 0; i < 10; i++ {
p := entity.NewPenguin()
p.GetObject().SetPosition(rl.Vector2{
X: rand.Float32() * float32(rl.GetScreenWidth()),
Y: rand.Float32() * float32(rl.GetScreenHeight()*-1),
})
p.GetAnimationTracker().SetAnimation(animation.RandomPenguinAnimation())
p.ToggleStaticAnimation()
drawables = append(drawables, p)
objects = append(objects, p)
}
// 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
}
player1.Update()
// Update physics
// TODO probably move out to something else to handle collisions.
for _, o := range objects {
err = o.Update()
if err != nil {
log.Printf("error updating physics: %v", err)
}
}
channels.RL.Do(func() {
rl.BeginDrawing()
})
// Draw stuff
for _, d := range drawables {
err = d.Draw()
if err != nil {
log.Printf("error drawing: %v", err)
}
}
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)
})
channels.RL.Do(func() {
rl.EndDrawing()
})
}
sprite.CleanupSpriteCache()
return nil
}