Add sprite cache
parent
56ba80c935
commit
f10ffa739d
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
@ -0,0 +1,15 @@
|
|||
package game
|
||||
|
||||
import "github.com/veandco/go-sdl2/sdl"
|
||||
|
||||
// camera represents a view of the world. It's a projection through the window looking at the world.
|
||||
// Since this is only a 2D game with SDL, the projection is relatively simple: window + camera = world.
|
||||
// https://gamedev.stackexchange.com/a/123844
|
||||
type camera struct {
|
||||
pos *sdl.Point
|
||||
}
|
||||
|
||||
func NewCamera() *camera {
|
||||
c := camera{}
|
||||
return &c
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package entity
|
||||
|
||||
import (
|
||||
"gitea.wisellama.rocks/Project-Ely/project-ely/internal/game/sprite"
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
)
|
||||
|
||||
type Sprite interface {
|
||||
Draw(section *sdl.Rect, placement *sdl.Rect) error
|
||||
}
|
||||
|
||||
type penguin struct {
|
||||
renderer *sdl.Renderer
|
||||
position *sdl.Point
|
||||
sprite Sprite
|
||||
}
|
||||
|
||||
func NewPenguin(renderer *sdl.Renderer) *penguin {
|
||||
sprite := sprite.GetSprite("assets/images/penguin.png")
|
||||
|
||||
pos := sdl.Point{X: 0, Y: 0}
|
||||
|
||||
p := penguin{
|
||||
renderer: renderer,
|
||||
sprite: sprite,
|
||||
position: &pos,
|
||||
}
|
||||
|
||||
return &p
|
||||
}
|
||||
|
||||
func (p *penguin) Draw() error {
|
||||
// This is where on the screen to plop that sprite sheet chunk
|
||||
placement := &sdl.Rect{X: p.position.X, Y: p.position.Y, W: 200, H: 200}
|
||||
|
||||
// Select the section of the spritesheet to draw
|
||||
// TODO this will depend on animation cycle
|
||||
section := &sdl.Rect{X: 0, Y: 0, W: 100, H: 100}
|
||||
|
||||
err := p.sprite.Draw(section, placement)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *penguin) SdlDrawNoTexture() error {
|
||||
sdl.Do(func() {
|
||||
p.renderer.SetDrawColor(0, 0, 255, 255)
|
||||
rect := &sdl.Rect{X: p.position.X, Y: p.position.Y, W: 200, H: 200}
|
||||
p.renderer.DrawRect(rect)
|
||||
p.renderer.FillRect(rect)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *penguin) MoveTo(point *sdl.Point) {
|
||||
p.position = point
|
||||
}
|
||||
|
||||
func (p *penguin) MoveRight() {
|
||||
p.position.X += 1
|
||||
}
|
||||
|
||||
func (p *penguin) MoveLeft() {
|
||||
p.position.X -= 1
|
||||
}
|
||||
|
||||
func (p *penguin) MoveUp() {
|
||||
// (0,0) is the top left, so negative y moves up
|
||||
p.position.Y -= 1
|
||||
}
|
||||
|
||||
func (p *penguin) MoveDown() {
|
||||
// positive y moves down
|
||||
p.position.Y += 1
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package game
|
||||
|
||||
// player represents a collection of stuff controlled by the user's input.
|
||||
// It contains the camera used to view the world,
|
||||
// the viewport for the part of the screen to draw to (splitscreen support),
|
||||
// as well as the entity the player is currently controlling.
|
||||
type player struct {
|
||||
}
|
||||
|
||||
func NewPlayer() *player {
|
||||
p := player{}
|
||||
return &p
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package sprite
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/veandco/go-sdl2/img"
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
)
|
||||
|
||||
type sprite struct {
|
||||
filename string
|
||||
renderer *sdl.Renderer
|
||||
image *sdl.Surface // the original png file
|
||||
spriteSheet *sdl.Texture // the SDL texture created from the image
|
||||
}
|
||||
|
||||
func NewSprite(renderer *sdl.Renderer, filename string) (*sprite, error) {
|
||||
var err error
|
||||
|
||||
// Load the image file
|
||||
var image *sdl.Surface
|
||||
sdl.Do(func() {
|
||||
image, err = img.Load(filename)
|
||||
})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to load image: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create the sprite sheet texture from the image
|
||||
var spriteSheet *sdl.Texture
|
||||
sdl.Do(func() {
|
||||
spriteSheet, err = renderer.CreateTextureFromSurface(image)
|
||||
})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to create texture: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := sprite{
|
||||
filename: filename,
|
||||
renderer: renderer,
|
||||
image: image,
|
||||
spriteSheet: spriteSheet,
|
||||
}
|
||||
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
func (s *sprite) Cleanup() {
|
||||
// Clean up image
|
||||
defer func() {
|
||||
if s.image != nil {
|
||||
sdl.Do(func() {
|
||||
s.image.Free()
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
||||
// Clean up spritesheet
|
||||
defer func() {
|
||||
if s.spriteSheet != nil {
|
||||
sdl.Do(func() {
|
||||
err := s.spriteSheet.Destroy()
|
||||
if err != nil {
|
||||
log.Printf("error destroying spritesheet %v: %v\n", s.filename, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *sprite) Draw(section *sdl.Rect, placement *sdl.Rect) error {
|
||||
var err error
|
||||
sdl.Do(func() {
|
||||
err = s.renderer.Copy(s.spriteSheet, section, placement)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package sprite
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
)
|
||||
|
||||
var spriteFileList []string = []string{
|
||||
"assets/images/penguin.png",
|
||||
}
|
||||
|
||||
type Sprite interface {
|
||||
Draw(section *sdl.Rect, placement *sdl.Rect) error
|
||||
Cleanup()
|
||||
}
|
||||
|
||||
var SpriteCache map[string]Sprite
|
||||
var DefaultSprite Sprite
|
||||
|
||||
func InitSpriteCache(renderer *sdl.Renderer) error {
|
||||
var err error
|
||||
|
||||
DefaultSprite, err = createDefaultSprite(renderer)
|
||||
if err != nil {
|
||||
log.Printf("failed to create DefaultSprite: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
SpriteCache = make(map[string]Sprite)
|
||||
|
||||
for _, filename := range spriteFileList {
|
||||
s, err := NewSprite(renderer, filename)
|
||||
if err != nil {
|
||||
log.Printf("error creating sprite %v, using DefaultSprite: %v", filename, err)
|
||||
SpriteCache[filename] = DefaultSprite
|
||||
} else {
|
||||
SpriteCache[filename] = s
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetSprite(filename string) Sprite {
|
||||
s, exists := SpriteCache[filename]
|
||||
if !exists {
|
||||
log.Printf("no sprite found for %v, using DefaultSprite", filename)
|
||||
return DefaultSprite
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func CleanupSpriteCache() {
|
||||
for _, v := range SpriteCache {
|
||||
defer v.Cleanup()
|
||||
}
|
||||
}
|
||||
|
||||
func createDefaultSprite(renderer *sdl.Renderer) (*sprite, error) {
|
||||
var err error
|
||||
|
||||
surface, err := sdl.CreateRGBSurface(0, 100, 100, 32, 0, 0, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
texture, err := renderer.CreateTextureFromSurface(surface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := sprite{
|
||||
renderer: renderer,
|
||||
spriteSheet: texture,
|
||||
}
|
||||
|
||||
return &s, nil
|
||||
}
|
|
@ -39,7 +39,7 @@ func NewWindow(title string) (*window, error) {
|
|||
return gw, nil
|
||||
}
|
||||
|
||||
func (g *window) Destroy() {
|
||||
func (g *window) Cleanup() {
|
||||
if g.SdlWindow != nil {
|
||||
sdl.Do(func() {
|
||||
err := g.SdlWindow.Destroy()
|
||||
|
|
87
main.go
87
main.go
|
@ -7,8 +7,9 @@ import (
|
|||
|
||||
"gitea.wisellama.rocks/Project-Ely/project-ely/internal/config"
|
||||
"gitea.wisellama.rocks/Project-Ely/project-ely/internal/game"
|
||||
"gitea.wisellama.rocks/Project-Ely/project-ely/internal/game/entity"
|
||||
"gitea.wisellama.rocks/Project-Ely/project-ely/internal/game/sprite"
|
||||
"gitea.wisellama.rocks/Wisellama/gosimpleconf"
|
||||
"github.com/veandco/go-sdl2/img"
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
)
|
||||
|
||||
|
@ -59,7 +60,7 @@ func run(configMap gosimpleconf.ConfigMap) error {
|
|||
err = fmt.Errorf("failed creating GameWindow: %w", err)
|
||||
return err
|
||||
}
|
||||
defer gameWindow.Destroy()
|
||||
defer gameWindow.Cleanup()
|
||||
|
||||
var renderer *sdl.Renderer
|
||||
sdl.Do(func() {
|
||||
|
@ -78,43 +79,16 @@ func run(configMap gosimpleconf.ConfigMap) error {
|
|||
})
|
||||
}()
|
||||
|
||||
var penguinImage *sdl.Surface
|
||||
sdl.Do(func() {
|
||||
penguinImage, err = img.Load("assets/images/penguin-right.png")
|
||||
})
|
||||
err = sprite.InitSpriteCache(renderer)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to load image: %w", err)
|
||||
err = fmt.Errorf("failed in InitSpriteCache: %w", err)
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
sdl.Do(func() {
|
||||
penguinImage.Free()
|
||||
})
|
||||
}()
|
||||
defer sprite.CleanupSpriteCache()
|
||||
|
||||
var penguinTexture *sdl.Texture
|
||||
sdl.Do(func() {
|
||||
penguinTexture, err = renderer.CreateTextureFromSurface(penguinImage)
|
||||
})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to create texture: %w", err)
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
sdl.Do(func() {
|
||||
err = penguinTexture.Destroy()
|
||||
if err != nil {
|
||||
log.Printf("error destroying renderer: %v\n", err)
|
||||
}
|
||||
|
||||
})
|
||||
}()
|
||||
|
||||
penguinRect := &sdl.Rect{X: 0, Y: 0, W: 100, H: 100}
|
||||
|
||||
var rect *sdl.Rect
|
||||
var x int32 = 0
|
||||
var y int32 = 0
|
||||
penguin := entity.NewPenguin(renderer)
|
||||
p2 := entity.NewPenguin(renderer)
|
||||
p2.MoveTo(&sdl.Point{X: 100, Y: 100})
|
||||
|
||||
keystates := make(map[sdl.Keycode]bool)
|
||||
|
||||
|
@ -148,31 +122,16 @@ func run(configMap gosimpleconf.ConfigMap) error {
|
|||
}
|
||||
|
||||
if keystates[sdl.K_a] {
|
||||
x -= 1
|
||||
if x < 0 {
|
||||
x = 0
|
||||
}
|
||||
penguin.MoveLeft()
|
||||
}
|
||||
if keystates[sdl.K_d] {
|
||||
x += 1
|
||||
w, _ := gameWindow.SdlWindow.GetSize()
|
||||
if x+rect.W > w {
|
||||
x = w - rect.W
|
||||
}
|
||||
penguin.MoveRight()
|
||||
}
|
||||
// Y is inverted, positive Y moves downward
|
||||
if keystates[sdl.K_w] {
|
||||
y -= 1
|
||||
if y < 0 {
|
||||
y = 0
|
||||
}
|
||||
penguin.MoveUp()
|
||||
}
|
||||
if keystates[sdl.K_s] {
|
||||
y += 1
|
||||
_, h := gameWindow.SdlWindow.GetSize()
|
||||
if y+rect.H > h {
|
||||
y = h - rect.H
|
||||
}
|
||||
penguin.MoveDown()
|
||||
}
|
||||
|
||||
// Background
|
||||
|
@ -188,17 +147,15 @@ func run(configMap gosimpleconf.ConfigMap) error {
|
|||
}
|
||||
})
|
||||
|
||||
// Square
|
||||
sdl.Do(func() {
|
||||
//renderer.SetDrawColor(0, 0, 255, 255)
|
||||
rect = &sdl.Rect{X: x, Y: y, W: 200, H: 200}
|
||||
err = renderer.Copy(penguinTexture, penguinRect, rect)
|
||||
if err != nil {
|
||||
log.Printf("error in renderer.Copy: %v\n", err)
|
||||
}
|
||||
//renderer.DrawRect(rect)
|
||||
//renderer.FillRect(rect)
|
||||
})
|
||||
// Everything else
|
||||
err = penguin.Draw()
|
||||
if err != nil {
|
||||
log.Printf("error drawing: %v\n", err)
|
||||
}
|
||||
err = p2.Draw()
|
||||
if err != nil {
|
||||
log.Printf("error drawing: %v\n", err)
|
||||
}
|
||||
|
||||
// Draw
|
||||
sdl.Do(func() {
|
||||
|
|
Loading…
Reference in New Issue