Draw software cursor

This commit is contained in:
Trevor Slocum 2022-06-12 16:00:34 -07:00
parent 17ccff124a
commit 9a8c3287e9
12 changed files with 170 additions and 48 deletions

View File

@ -19,12 +19,17 @@ const sampleRate = 44100
//go:embed image
var FS embed.FS
var ImgWhiteSquare = ebiten.NewImage(4, 4)
var ImgBlackSquare = ebiten.NewImage(3, 3)
var ColorWater = color.RGBA{96, 160, 168, 255}
var (
ImgWater = newWaterImage()
ImgFish = LoadImage("image/cozy-fishing/global.png")
ImgWhiteSquare = newFilledImage(4, 4, color.White)
ImgBlackSquare = newFilledImage(4, 4, color.Black)
ImgWater = newFilledImage(16, 16, ColorWater)
ImgCrosshair = LoadImage("image/crosshair.png")
ImgFishTileset = LoadImage("image/cozy-fishing/global.png")
)
func init() {
@ -32,9 +37,9 @@ func init() {
ImgBlackSquare.Fill(color.Black)
}
func newWaterImage() *ebiten.Image {
img := ebiten.NewImage(16, 16)
img.Fill(color.RGBA{96, 160, 168, 255})
func newFilledImage(w int, h int, c color.Color) *ebiten.Image {
img := ebiten.NewImage(w, h)
img.Fill(c)
return img
}
@ -130,7 +135,7 @@ func FishTileAt(i int) *ebiten.Image {
r := image.Rect(x*tileSize, y*tileSize, (x+1)*tileSize, (y+1)*tileSize)
return ImgFish.SubImage(r).(*ebiten.Image)
return ImgFishTileset.SubImage(r).(*ebiten.Image)
}
func FishTileXY(x, y int) *ebiten.Image {
@ -139,7 +144,7 @@ func FishTileXY(x, y int) *ebiten.Image {
r := image.Rect(x*tileSize, y*tileSize, (x+1)*tileSize, (y+1)*tileSize)
return ImgFish.SubImage(r).(*ebiten.Image)
return ImgFishTileset.SubImage(r).(*ebiten.Image)
}
func FishImage(i int) *ebiten.Image {
@ -152,5 +157,5 @@ func FishImage(i int) *ebiten.Image {
r := image.Rect(x*tileSize, y*tileSize, (x+1)*tileSize, (y+1)*tileSize)
return ImgFish.SubImage(r).(*ebiten.Image)
return ImgFishTileset.SubImage(r).(*ebiten.Image)
}

BIN
asset/image/crosshair.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 B

View File

@ -5,7 +5,6 @@ import (
"math/rand"
"os"
"sync"
"time"
"code.rocketnine.space/tslocum/fishfightback/component"
"code.rocketnine.space/tslocum/fishfightback/entity"
@ -72,12 +71,7 @@ func (g *game) tileToGameCoords(x, y int) (float64, float64) {
}
func (g *game) updateCursor() {
if g.activeGamepad != -1 || g.gameWon {
ebiten.SetCursorMode(ebiten.CursorModeHidden)
return
}
ebiten.SetCursorMode(ebiten.CursorModeVisible)
ebiten.SetCursorShape(ebiten.CursorShapeCrosshair)
ebiten.SetCursorMode(ebiten.CursorModeHidden)
}
// Layout is called when the game's layout changes.
@ -96,7 +90,6 @@ func (g *game) Update() error {
if !g.addedSystems {
g.addSystems()
g.addedSystems = true
}
@ -105,25 +98,14 @@ func (g *game) Update() error {
world.SetFish(level.FishParrot)
}
const playerStartOffset = 128
const camStartOffset = 480
/* w := float64(world.World.Map.Width * world.World.Map.TileWidth)
h := float64(world.World.Map.Height * world.World.Map.TileHeight)*/
world.World.Player.With(func(position *component.Position) {
//position.X, position.Y = w/2, h-playerStartOffset
position.X, position.Y = 200, 3500
position.X, position.Y = float64(rand.Intn(world.ScreenWidth/2)), world.ScreenHeight-system.TileWidth-float64(rand.Intn(100))
})
world.World.CamX, world.World.CamY = 1, 3700-camStartOffset
world.World.CamX, world.World.CamY = 0, 0
g.nextSectionX = 0
// TODO Seed is configurable
rand.Seed(time.Now().UnixNano())
world.World.ResetGame = false
world.World.GameOver = false
}
@ -174,8 +156,10 @@ func (g *game) addSystems() {
gohan.AddSystem(system.NewRenderSystem(layer))
}
gohan.AddSystem(system.NewRenderHUDSystem())
gohan.AddSystem(system.NewRenderMessageSystem())
gohan.AddSystem(system.NewRenderDebugTextSystem(world.World.Player))
gohan.AddSystem(system.NewRenderCursorSystem())
gohan.AddSystem(system.NewProfileSystem(world.World.Player))
}

1
go.mod
View File

@ -5,6 +5,7 @@ go 1.17
require (
code.rocketnine.space/tslocum/gohan v0.0.0-20220611080547-c66dd322f959
github.com/hajimehoshi/ebiten/v2 v2.3.4
golang.org/x/text v0.3.7
)
require (

1
go.sum
View File

@ -76,6 +76,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=

View File

@ -25,7 +25,7 @@ func (s *CameraSystem) Update(e gohan.Entity) error {
return nil
}
world.World.CamMoving = world.World.CamX > 0
world.World.CamMoving = world.World.CamX >= 0
if world.World.CamMoving {
world.World.CamX += world.RailSpeed
} else {

View File

@ -8,7 +8,6 @@ import (
"github.com/hajimehoshi/ebiten/v2"
)
// pause time, screen X, screen Y
type CreepSystem struct {
Creep *component.Creep
Position *component.Position
@ -39,7 +38,7 @@ func (s *CreepSystem) Update(e gohan.Entity) error {
// Skip inactive creeps.
sx, sy := world.LevelCoordinatesToScreen(position.X, position.Y)
inactive := sx < 0 || sy < 0 || sx > float64(world.ScreenWidth) || sy > float64(world.ScreenHeight)
inactive := sx < 0 || sy < 0 || sx > float64(world.ScreenWidth)+TileWidth/2 || sy > float64(world.ScreenHeight)
if creep.Active != !inactive {
creep.Active = !inactive
}

View File

@ -149,7 +149,7 @@ func (s *MovementSystem) Update(e gohan.Entity) error {
if playerBullet != nil {
var currentSection = world.World.SectionA
if position.X >= world.World.SectionA.X+world.SectionWidth {
if world.World.SectionB.X != 0 && position.X >= world.World.SectionB.X && position.X < world.World.SectionB.X+world.SectionWidth {
currentSection = world.World.SectionB
}
@ -164,19 +164,20 @@ func (s *MovementSystem) Update(e gohan.Entity) error {
// Hit creep.
creepEntity := currentSection.Creeps[ty][tx]
if creepEntity != 0 {
var hitCreep bool
creepEntity.With(func(creep *component.Creep) {
if creep == nil {
if creep == nil || !creep.Active {
return
}
if creep.Active {
creep.Health--
creep.DamageTicks = 6
}
creep.Health--
creep.DamageTicks = 6
hitCreep = true
})
if hitCreep {
e.Remove()
currentSection.Creeps[ty][tx] = 0
}
e.Remove()
currentSection.Creeps[ty][tx] = 0
}
}

35
system/rendercursor.go Normal file
View File

@ -0,0 +1,35 @@
package system
import (
"code.rocketnine.space/tslocum/fishfightback/asset"
"code.rocketnine.space/tslocum/fishfightback/component"
"code.rocketnine.space/tslocum/gohan"
"github.com/hajimehoshi/ebiten/v2"
)
type RenderCursorSystem struct {
Position *component.Position
Velocity *component.Velocity
Weapon *component.Weapon
cx, cy int
}
func NewRenderCursorSystem() *RenderCursorSystem {
s := &RenderCursorSystem{}
return s
}
func (s *RenderCursorSystem) Update(_ gohan.Entity) error {
s.cx, s.cy = ebiten.CursorPosition()
return nil
}
func (s *RenderCursorSystem) Draw(_ gohan.Entity, screen *ebiten.Image) error {
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(float64(s.cx-2), float64(s.cy-2))
screen.DrawImage(asset.ImgCrosshair, op)
return nil
}

81
system/renderhud.go Normal file
View File

@ -0,0 +1,81 @@
package system
import (
"code.rocketnine.space/tslocum/fishfightback/component"
"code.rocketnine.space/tslocum/fishfightback/world"
"code.rocketnine.space/tslocum/gohan"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
)
type RenderHUDSystem struct {
Position *component.Position
Velocity *component.Velocity
Weapon *component.Weapon
op *ebiten.DrawImageOptions
msgImg *ebiten.Image
tmpImg *ebiten.Image
lastScore int
}
func NewRenderHUDSystem() *RenderHUDSystem {
s := &RenderHUDSystem{
op: &ebiten.DrawImageOptions{},
msgImg: ebiten.NewImage(1, 1),
tmpImg: ebiten.NewImage(200, 200),
lastScore: -1,
}
return s
}
func (s *RenderHUDSystem) Update(_ gohan.Entity) error {
return gohan.ErrUnregister
}
func (s *RenderHUDSystem) Draw(_ gohan.Entity, screen *ebiten.Image) error {
if !world.World.GameStarted {
return nil
}
if world.World.Score != s.lastScore {
s.drawScore()
}
// Draw score.
s.op.GeoM.Reset()
s.op.GeoM.Translate(1, world.ScreenHeight-15)
screen.DrawImage(s.msgImg, s.op)
return nil
}
func (s *RenderHUDSystem) drawScore() {
message := world.NumberPrinter.Sprintf("%d", world.World.Score)
split := []string{message}
width := 0
for _, line := range split {
lineSize := len(line) * 12
if lineSize > width {
width = lineSize
}
}
height := len(split) * 32
const padding = 8
width, height = width+padding*2, height+padding*2
s.msgImg = ebiten.NewImage(width, height)
//s.msgImg.Fill(color.RGBA{17, 17, 17, 100})
s.tmpImg.Clear()
s.tmpImg = ebiten.NewImage(width*2, height*2)
s.op.GeoM.Reset()
s.op.GeoM.Scale(1, 1)
//s.op.GeoM.Translate(float64(padding), float64(padding))
ebitenutil.DebugPrint(s.tmpImg, message)
s.msgImg.DrawImage(s.tmpImg, s.op)
s.op.ColorM.Reset()
}

View File

@ -14,8 +14,6 @@ import (
"github.com/hajimehoshi/ebiten/v2"
)
// TODO tweak
const SectionWidth = ScreenWidth * 2
type Section struct {
@ -61,8 +59,6 @@ func (s *Section) SetPosition(x float64, y float64) {
}
func (s *Section) tileAvailable(tx, ty int, creep bool) bool {
// TODO use shore map and return false
if ty < 0 {
return true // TODO
} else if ty > s.ShoreDepth || (!creep && ty == s.ShoreDepth-1) {

View File

@ -2,7 +2,13 @@ package world
import (
"fmt"
"log"
"math"
"math/rand"
"time"
"golang.org/x/text/language"
"golang.org/x/text/message"
"code.rocketnine.space/tslocum/fishfightback/asset"
@ -17,7 +23,9 @@ const (
ScreenHeight = 225
)
const RailSpeed = 0.2
var RailSpeed = 0.4
var NumberPrinter = message.NewPrinter(language.English)
var World = &GameWorld{
CamScale: 1,
@ -80,6 +88,15 @@ func Reset() {
World.SectionA.ShoreDepth = 0
World.SectionB.ShoreDepth = 0
RailSpeed = 0.4
// TODO Seed is configurable
seed := time.Now().UnixNano()
rand.Seed(seed)
log.Printf("Starting game with seed %d", seed)
}
func LevelCoordinatesToScreen(x, y float64) (float64, float64) {
@ -103,6 +120,8 @@ func (w *GameWorld) SetGameOver() {
} else {
SetMessage("GAME OVER", math.MaxInt)
}
log.Printf("Game over - score %d", w.Score)
}
func StartGame() {