Add bats
After Width: | Height: | Size: 361 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 812 B |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 653 B |
|
@ -0,0 +1,52 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"image"
|
||||
_ "image/png"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
)
|
||||
|
||||
// BatSpriteSheet represents a collection of sprite images.
|
||||
type BatSpriteSheet struct {
|
||||
Frame1 *ebiten.Image
|
||||
Frame2 *ebiten.Image
|
||||
Frame3 *ebiten.Image
|
||||
Frame4 *ebiten.Image
|
||||
Frame5 *ebiten.Image
|
||||
Frame6 *ebiten.Image
|
||||
Frame7 *ebiten.Image
|
||||
}
|
||||
|
||||
// LoadBatSpriteSheet loads the embedded BatSpriteSheet.
|
||||
func LoadBatSpriteSheet() (*BatSpriteSheet, error) {
|
||||
tileSize := 32
|
||||
|
||||
f, err := assetsFS.Open("assets/creeps/bat/fly.png")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
img, _, err := image.Decode(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sheet := ebiten.NewImageFromImage(img)
|
||||
|
||||
// spriteAt returns a sprite at the provided coordinates.
|
||||
spriteAt := func(x, y int) *ebiten.Image {
|
||||
return sheet.SubImage(image.Rect(x*tileSize, (y+1)*tileSize, (x+1)*tileSize, y*tileSize)).(*ebiten.Image)
|
||||
}
|
||||
|
||||
// Populate CharacterSpriteSheet.
|
||||
s := &BatSpriteSheet{}
|
||||
s.Frame1 = spriteAt(0, 0)
|
||||
s.Frame2 = spriteAt(1, 0)
|
||||
s.Frame3 = spriteAt(2, 0)
|
||||
s.Frame4 = spriteAt(3, 0)
|
||||
s.Frame5 = spriteAt(4, 0)
|
||||
s.Frame6 = spriteAt(5, 0)
|
||||
s.Frame7 = spriteAt(6, 0)
|
||||
|
||||
return s, nil
|
||||
}
|
40
creep.go
|
@ -4,13 +4,27 @@ import (
|
|||
"math"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
TypeVampire = iota
|
||||
TypeBat
|
||||
TypeGhost
|
||||
)
|
||||
|
||||
type gameCreep struct {
|
||||
x, y float64
|
||||
sprite *ebiten.Image
|
||||
x, y float64
|
||||
|
||||
sprites []*ebiten.Image
|
||||
|
||||
frame int
|
||||
frames int
|
||||
lastFrame time.Time
|
||||
|
||||
creepType int
|
||||
|
||||
moveX, moveY float64
|
||||
|
||||
|
@ -27,6 +41,14 @@ type gameCreep struct {
|
|||
sync.Mutex
|
||||
}
|
||||
|
||||
func (c *gameCreep) queueNextAction() {
|
||||
if c.creepType == TypeBat {
|
||||
c.nextAction = 288 + rand.Intn(288)
|
||||
return
|
||||
}
|
||||
c.nextAction = 144 + rand.Intn(720)
|
||||
}
|
||||
|
||||
func (c *gameCreep) doNextAction() {
|
||||
randMovementA := (rand.Float64() - 0.5) / 7
|
||||
randMovementB := (rand.Float64() - 0.5) / 7
|
||||
|
@ -60,19 +82,7 @@ func (c *gameCreep) doNextAction() {
|
|||
c.moveY *= 1
|
||||
}
|
||||
|
||||
c.nextAction = 144 + rand.Intn(720)
|
||||
}
|
||||
|
||||
func NewCreep(sprite *ebiten.Image, level *Level, player *gamePlayer) *gameCreep {
|
||||
return &gameCreep{
|
||||
x: float64(1 + rand.Intn(108)),
|
||||
y: float64(1 + rand.Intn(108)),
|
||||
sprite: sprite,
|
||||
level: level,
|
||||
player: player,
|
||||
health: 1,
|
||||
killScore: 50,
|
||||
}
|
||||
c.queueNextAction()
|
||||
}
|
||||
|
||||
func (c *gameCreep) Update() {
|
||||
|
|
49
game.go
|
@ -77,6 +77,8 @@ type game struct {
|
|||
|
||||
projectiles []*projectile
|
||||
|
||||
batSS *BatSpriteSheet
|
||||
|
||||
ojasSS *CharacterSpriteSheet
|
||||
|
||||
heartImg *ebiten.Image
|
||||
|
@ -146,6 +148,11 @@ func (g *game) loadAssets() error {
|
|||
return fmt.Errorf("failed to load embedded spritesheet: %s", err)
|
||||
}
|
||||
|
||||
g.batSS, err = LoadBatSpriteSheet()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load embedded spritesheet: %s", err)
|
||||
}
|
||||
|
||||
f, err := assetsFS.Open("assets/weapons/bullet.png")
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -224,6 +231,33 @@ func (g *game) loadAssets() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (g *game) newCreep(creepType int) *gameCreep {
|
||||
sprites := []*ebiten.Image{g.vampireImage}
|
||||
if creepType == TypeBat {
|
||||
sprites = []*ebiten.Image{
|
||||
g.batSS.Frame1,
|
||||
g.batSS.Frame2,
|
||||
g.batSS.Frame3,
|
||||
g.batSS.Frame4,
|
||||
g.batSS.Frame5,
|
||||
g.batSS.Frame6,
|
||||
g.batSS.Frame7,
|
||||
}
|
||||
}
|
||||
|
||||
return &gameCreep{
|
||||
creepType: creepType,
|
||||
x: float64(1 + rand.Intn(108)),
|
||||
y: float64(1 + rand.Intn(108)),
|
||||
sprites: sprites,
|
||||
frames: len(sprites),
|
||||
level: g.currentLevel,
|
||||
player: g.player,
|
||||
health: 1,
|
||||
killScore: 50,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *game) reset() error {
|
||||
var err error
|
||||
g.currentLevel, err = NewLevel()
|
||||
|
@ -245,7 +279,11 @@ func (g *game) reset() error {
|
|||
g.creeps = make([]*gameCreep, 1000)
|
||||
addedCreeps := make(map[string]bool)
|
||||
for i := 0; i < 1000; i++ {
|
||||
c := NewCreep(g.vampireImage, g.currentLevel, g.player)
|
||||
creepType := TypeVampire
|
||||
if rand.Intn(7) == 0 {
|
||||
creepType = TypeBat
|
||||
}
|
||||
c := g.newCreep(creepType)
|
||||
|
||||
safeSpace := 7.0
|
||||
dx, dy := deltaXY(g.player.x, g.player.y, c.x, c.y)
|
||||
|
@ -735,7 +773,14 @@ func (g *game) renderLevel(screen *ebiten.Image) int {
|
|||
continue
|
||||
}
|
||||
|
||||
drawn += g.renderSprite(c.x, c.y, 0, 0, 0, c.sprite, screen)
|
||||
drawn += g.renderSprite(c.x, c.y, 0, 0, 0, c.sprites[c.frame], screen)
|
||||
if c.frames > 1 && time.Since(c.lastFrame) >= 75*time.Millisecond {
|
||||
c.frame++
|
||||
if c.frame == c.frames {
|
||||
c.frame = 0
|
||||
}
|
||||
c.lastFrame = time.Now()
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range g.projectiles {
|
||||
|
|
|
@ -6,12 +6,12 @@ builds:
|
|||
# ldflags:
|
||||
# - -s -w -X code.rocketnine.space/tslocum/carotidartillery/main.Version={{.Version}}
|
||||
goos:
|
||||
- js
|
||||
- linux
|
||||
- windows
|
||||
# - darwin
|
||||
# - freebsd
|
||||
goarch:
|
||||
- amd64
|
||||
- wasm
|
||||
archives:
|
||||
-
|
||||
id: carotidartillery
|
||||
|
@ -20,11 +20,12 @@ archives:
|
|||
replacements:
|
||||
386: i386
|
||||
format_overrides:
|
||||
- goos: js
|
||||
format: zip
|
||||
- goos: windows
|
||||
format: zip
|
||||
files:
|
||||
- ./*.md
|
||||
# - CHANGELOG
|
||||
- LICENSE
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
|
|