Add garlic
This commit is contained in:
parent
d54ebb995c
commit
214dc0ce57
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
41
creep.go
41
creep.go
|
@ -47,6 +47,28 @@ func (c *gameCreep) queueNextAction() {
|
|||
c.nextAction = 144 + rand.Intn(720)
|
||||
}
|
||||
|
||||
func (c *gameCreep) runAway() {
|
||||
c.queueNextAction()
|
||||
|
||||
randMovementA := (rand.Float64() - 0.5) / 7
|
||||
randMovementB := (rand.Float64() - 0.5) / 7
|
||||
|
||||
c.moveX = c.x - c.player.x
|
||||
if c.moveX < 0 {
|
||||
c.moveX = math.Abs(randMovementA) * -1
|
||||
} else {
|
||||
c.moveX = math.Abs(randMovementA)
|
||||
}
|
||||
c.moveY = c.y - c.player.y
|
||||
if c.moveY < 0 {
|
||||
c.moveY = math.Abs(randMovementB) * -1
|
||||
} else {
|
||||
c.moveY = math.Abs(randMovementB)
|
||||
}
|
||||
|
||||
c.nextAction *= 2
|
||||
}
|
||||
|
||||
func (c *gameCreep) doNextAction() {
|
||||
c.queueNextAction()
|
||||
|
||||
|
@ -107,6 +129,25 @@ func (c *gameCreep) Update() {
|
|||
c.x, c.y = clampX, clampY
|
||||
if clampX != x || clampY != y {
|
||||
c.nextAction = 0
|
||||
return
|
||||
}
|
||||
|
||||
if !c.player.repelUntil.IsZero() && c.player.repelUntil.Sub(time.Now()) > 0 {
|
||||
dx, dy := deltaXY(c.x, c.y, c.player.x, c.player.y)
|
||||
if dx <= 3 && dy <= 3 {
|
||||
c.runAway()
|
||||
}
|
||||
}
|
||||
|
||||
for _, item := range c.level.items {
|
||||
if item.health == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
dx, dy := deltaXY(c.x, c.y, item.x, item.y)
|
||||
if dx <= 2 && dy <= 2 {
|
||||
c.runAway()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
218
game.go
218
game.go
|
@ -35,6 +35,8 @@ const (
|
|||
batDieVolume = 1.5
|
||||
playerHurtVolume = 0.4
|
||||
playerDieVolume = 1.6
|
||||
|
||||
garlicActiveTime = 7 * time.Second
|
||||
)
|
||||
|
||||
var startButtons = []ebiten.StandardGamepadButton{
|
||||
|
@ -66,8 +68,8 @@ type projectile struct {
|
|||
|
||||
// game is an isometric demo game.
|
||||
type game struct {
|
||||
w, h int
|
||||
currentLevel *Level
|
||||
w, h int
|
||||
level *Level
|
||||
|
||||
player *gamePlayer
|
||||
|
||||
|
@ -82,8 +84,6 @@ type game struct {
|
|||
|
||||
spinnerIndex int
|
||||
|
||||
creeps []*gameCreep
|
||||
|
||||
projectiles []*projectile
|
||||
|
||||
batSS *BatSpriteSheet
|
||||
|
@ -92,6 +92,7 @@ type game struct {
|
|||
|
||||
heartImg *ebiten.Image
|
||||
vampireImage *ebiten.Image
|
||||
garlicImage *ebiten.Image
|
||||
|
||||
overlayImg *ebiten.Image
|
||||
op *ebiten.DrawImageOptions
|
||||
|
@ -108,6 +109,8 @@ type game struct {
|
|||
|
||||
initialButtonReleased bool
|
||||
|
||||
tick int
|
||||
|
||||
godMode bool
|
||||
debugMode bool
|
||||
cpuProfile *os.File
|
||||
|
@ -194,37 +197,37 @@ func (g *game) loadAssets() error {
|
|||
g.soundBuffer[SoundPlayerDie] = make([]*audio.Player, 4)
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
stream, err := loadMP3(g.audioContext, "assets/audio/gunshot.mp3")
|
||||
stream, err := loadWav(g.audioContext, "assets/audio/gunshot.wav")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.soundBuffer[SoundGunshot][i] = stream
|
||||
|
||||
stream, err = loadMP3(g.audioContext, "assets/audio/vampiredie1.mp3")
|
||||
stream, err = loadWav(g.audioContext, "assets/audio/vampiredie1.wav")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.soundBuffer[SoundVampireDie1][i] = stream
|
||||
|
||||
stream, err = loadMP3(g.audioContext, "assets/audio/vampiredie2.mp3")
|
||||
stream, err = loadWav(g.audioContext, "assets/audio/vampiredie2.wav")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.soundBuffer[SoundVampireDie2][i] = stream
|
||||
|
||||
stream, err = loadMP3(g.audioContext, "assets/audio/bat.mp3")
|
||||
stream, err = loadWav(g.audioContext, "assets/audio/bat.wav")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.soundBuffer[SoundBat][i] = stream
|
||||
|
||||
stream, err = loadMP3(g.audioContext, "assets/audio/playerhurt.mp3")
|
||||
stream, err = loadWav(g.audioContext, "assets/audio/playerhurt.wav")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.soundBuffer[SoundPlayerHurt][i] = stream
|
||||
|
||||
stream, err = loadMP3(g.audioContext, "assets/audio/playerdie.mp3")
|
||||
stream, err = loadWav(g.audioContext, "assets/audio/playerdie.wav")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -242,6 +245,17 @@ func (g *game) loadAssets() error {
|
|||
|
||||
g.vampireImage = ebiten.NewImageFromImage(img)
|
||||
|
||||
f, err = assetsFS.Open("assets/items/garlic.png")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
img, _, err = image.Decode(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
g.garlicImage = ebiten.NewImageFromImage(img)
|
||||
|
||||
f, err = assetsFS.Open("assets/ui/heart.png")
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -255,6 +269,20 @@ func (g *game) loadAssets() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (g *game) newItem(itemType int) *gameItem {
|
||||
sprite := g.garlicImage
|
||||
x, y := g.level.newSpawnLocation()
|
||||
return &gameItem{
|
||||
itemType: itemType,
|
||||
x: x,
|
||||
y: y,
|
||||
sprite: sprite,
|
||||
level: g.level,
|
||||
player: g.player,
|
||||
health: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *game) newCreep(creepType int) *gameCreep {
|
||||
sprites := []*ebiten.Image{g.vampireImage}
|
||||
if creepType == TypeBat {
|
||||
|
@ -269,24 +297,34 @@ func (g *game) newCreep(creepType int) *gameCreep {
|
|||
}
|
||||
}
|
||||
|
||||
startingFrame := 0
|
||||
if len(sprites) > 1 {
|
||||
startingFrame = rand.Intn(len(sprites))
|
||||
}
|
||||
|
||||
x, y := g.level.newSpawnLocation()
|
||||
return &gameCreep{
|
||||
creepType: creepType,
|
||||
x: float64(1 + rand.Intn(108)),
|
||||
y: float64(1 + rand.Intn(108)),
|
||||
x: x,
|
||||
y: y,
|
||||
sprites: sprites,
|
||||
frames: len(sprites),
|
||||
level: g.currentLevel,
|
||||
frame: startingFrame,
|
||||
level: g.level,
|
||||
player: g.player,
|
||||
health: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *game) reset() error {
|
||||
g.tick = 0
|
||||
|
||||
var err error
|
||||
g.currentLevel, err = NewLevel()
|
||||
g.level, err = NewLevel()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create new level: %s", err)
|
||||
}
|
||||
g.level.player = g.player
|
||||
|
||||
// Reset player score.
|
||||
g.player.score = 0
|
||||
|
@ -301,33 +339,39 @@ func (g *game) reset() error {
|
|||
// Remove projectiles.
|
||||
g.projectiles = nil
|
||||
|
||||
// Spawn creeps.
|
||||
g.creeps = make([]*gameCreep, 1000)
|
||||
addedCreeps := make(map[string]bool)
|
||||
for i := 0; i < 1000; i++ {
|
||||
creepType := TypeVampire
|
||||
if rand.Intn(7) == 0 {
|
||||
creepType = TypeBat
|
||||
}
|
||||
c := g.newCreep(creepType)
|
||||
// Spawn items.
|
||||
g.level.items = nil
|
||||
added := make(map[string]bool)
|
||||
for i := 0; i < 16; i++ {
|
||||
itemType := itemTypeGarlic
|
||||
c := g.newItem(itemType)
|
||||
|
||||
safeSpace := 7.0
|
||||
dx, dy := deltaXY(g.player.x, g.player.y, c.x, c.y)
|
||||
if dx <= safeSpace || dy <= safeSpace {
|
||||
// Too close to the spawn point.
|
||||
addedItem := fmt.Sprintf("%0.0f-%0.0f", c.x, c.y)
|
||||
if added[addedItem] {
|
||||
// Already added a gameItem here.
|
||||
i--
|
||||
continue
|
||||
}
|
||||
|
||||
g.level.items = append(g.level.items, c)
|
||||
added[addedItem] = true
|
||||
}
|
||||
|
||||
// Spawn creeps.
|
||||
g.level.creeps = make([]*gameCreep, 1000)
|
||||
for i := 0; i < 1000; i++ {
|
||||
creepType := TypeVampire
|
||||
c := g.newCreep(creepType)
|
||||
|
||||
addedCreep := fmt.Sprintf("%0.0f-%0.0f", c.x, c.y)
|
||||
if addedCreeps[addedCreep] {
|
||||
if added[addedCreep] {
|
||||
// Already added a gameCreep here.
|
||||
i--
|
||||
continue
|
||||
}
|
||||
|
||||
g.creeps[i] = c
|
||||
addedCreeps[addedCreep] = true
|
||||
g.level.creeps[i] = c
|
||||
added[addedCreep] = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -409,7 +453,7 @@ func (g *game) Update() error {
|
|||
}
|
||||
|
||||
biteThreshold := 0.75
|
||||
for _, c := range g.creeps {
|
||||
for _, c := range g.level.creeps {
|
||||
if c.health == 0 {
|
||||
continue
|
||||
}
|
||||
|
@ -419,7 +463,9 @@ func (g *game) Update() error {
|
|||
cx, cy := c.Position()
|
||||
dx, dy := deltaXY(g.player.x, g.player.y, cx, cy)
|
||||
if dx <= biteThreshold && dy <= biteThreshold {
|
||||
g.player.health--
|
||||
if !g.godMode {
|
||||
g.player.health--
|
||||
}
|
||||
|
||||
err := g.hurtCreep(c, -1)
|
||||
if err != nil {
|
||||
|
@ -435,7 +481,7 @@ func (g *game) Update() error {
|
|||
|
||||
g.addBloodSplatter(g.player.x, g.player.y)
|
||||
|
||||
if g.player.health == 0 && !g.godMode {
|
||||
if g.player.health == 0 {
|
||||
ebiten.SetCursorShape(ebiten.CursorShapeDefault)
|
||||
|
||||
g.gameOverTime = time.Now()
|
||||
|
@ -515,7 +561,20 @@ func (g *game) Update() error {
|
|||
}
|
||||
|
||||
// Clamp camera position.
|
||||
g.player.x, g.player.y = g.currentLevel.Clamp(g.player.x, g.player.y)
|
||||
g.player.x, g.player.y = g.level.Clamp(g.player.x, g.player.y)
|
||||
|
||||
for _, item := range g.level.items {
|
||||
if item.health == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
dx, dy := deltaXY(g.player.x, g.player.y, item.x, item.y)
|
||||
if dx <= 1 && dy <= 1 {
|
||||
item.health = 0
|
||||
g.player.repelUntil = time.Now().Add(garlicActiveTime)
|
||||
g.player.score += item.useScore()
|
||||
}
|
||||
}
|
||||
|
||||
fire := ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft)
|
||||
|
||||
|
@ -547,7 +606,7 @@ func (g *game) Update() error {
|
|||
p.x += math.Cos(p.angle) * p.speed
|
||||
p.y += math.Sin(p.angle) * p.speed
|
||||
|
||||
for _, c := range g.creeps {
|
||||
for _, c := range g.level.creeps {
|
||||
if c.health == 0 {
|
||||
continue
|
||||
}
|
||||
|
@ -591,6 +650,40 @@ func (g *game) Update() error {
|
|||
}
|
||||
}
|
||||
|
||||
// Spawn garlic.
|
||||
if g.tick%144*20 == 0 {
|
||||
item := g.newItem(itemTypeGarlic)
|
||||
g.level.items = append(g.level.items, item)
|
||||
}
|
||||
|
||||
// Spawn vampires.
|
||||
if g.tick > 144*5 && g.tick%288 == 0 {
|
||||
for i := 0; i < g.tick/1440; i++ {
|
||||
if rand.Intn(2) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
creepType := TypeVampire
|
||||
c := g.newCreep(creepType)
|
||||
|
||||
g.level.creeps = append(g.level.creeps, c)
|
||||
}
|
||||
}
|
||||
|
||||
// Spawn bats.
|
||||
if g.tick > 144*5 && g.tick%144 == 0 {
|
||||
for i := 0; i < g.tick/1440; i++ {
|
||||
if rand.Intn(6) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
creepType := TypeBat
|
||||
c := g.newCreep(creepType)
|
||||
|
||||
g.level.creeps = append(g.level.creeps, c)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO debug only
|
||||
if inpututil.IsKeyJustPressed(ebiten.KeyV) {
|
||||
g.debugMode = !g.debugMode
|
||||
|
@ -622,6 +715,7 @@ func (g *game) Update() error {
|
|||
}
|
||||
}
|
||||
|
||||
g.tick++
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -746,21 +840,23 @@ func (g *game) Draw(screen *ebiten.Image) {
|
|||
|
||||
// tilePosition transforms X,Y coordinates into tile positions.
|
||||
func (g *game) tilePosition(x, y float64) (float64, float64) {
|
||||
tileSize := float64(g.currentLevel.tileSize)
|
||||
tileSize := float64(g.level.tileSize)
|
||||
return x * tileSize, y * tileSize
|
||||
}
|
||||
|
||||
func (g *game) renderSprite(x float64, y float64, offsetx float64, offsety float64, angle float64, sprite *ebiten.Image, target *ebiten.Image) int {
|
||||
func (g *game) renderSprite(x float64, y float64, offsetx float64, offsety float64, angle float64, scale float64, alpha float64, sprite *ebiten.Image, target *ebiten.Image) int {
|
||||
x, y = g.tilePosition(x, y)
|
||||
|
||||
// Skip drawing off-screen tiles.
|
||||
drawX, drawY := g.levelCoordinatesToScreen(x, y)
|
||||
padding := float64(g.currentLevel.tileSize) * 2
|
||||
padding := float64(g.level.tileSize) * 2
|
||||
if drawX+padding < 0 || drawY+padding < 0 || drawX > float64(g.w)+padding || drawY > float64(g.h)+padding {
|
||||
return 0
|
||||
}
|
||||
|
||||
g.op.GeoM.Reset()
|
||||
|
||||
g.op.GeoM.Scale(scale, scale)
|
||||
// Rotate
|
||||
g.op.GeoM.Translate(-16+offsetx, -16+offsety)
|
||||
g.op.GeoM.Rotate(angle)
|
||||
|
@ -774,7 +870,12 @@ func (g *game) renderSprite(x float64, y float64, offsetx float64, offsety float
|
|||
// Center.
|
||||
g.op.GeoM.Translate(float64(g.w/2.0), float64(g.h/2.0))
|
||||
|
||||
g.op.ColorM.Scale(1.0, 1.0, 1.0, alpha)
|
||||
|
||||
target.DrawImage(sprite, g.op)
|
||||
|
||||
g.op.ColorM.Reset()
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
|
@ -783,25 +884,33 @@ func (g *game) renderLevel(screen *ebiten.Image) int {
|
|||
var drawn int
|
||||
|
||||
var t *Tile
|
||||
for y := 0; y < g.currentLevel.h; y++ {
|
||||
for x := 0; x < g.currentLevel.w; x++ {
|
||||
t = g.currentLevel.tiles[y][x]
|
||||
for y := 0; y < g.level.h; y++ {
|
||||
for x := 0; x < g.level.w; x++ {
|
||||
t = g.level.tiles[y][x]
|
||||
if t == nil {
|
||||
continue // No tile at this position.
|
||||
}
|
||||
|
||||
for i := range t.sprites {
|
||||
drawn += g.renderSprite(float64(x), float64(y), 0, 0, 0, t.sprites[i], screen)
|
||||
drawn += g.renderSprite(float64(x), float64(y), 0, 0, 0, 1.0, 1.0, t.sprites[i], screen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range g.creeps {
|
||||
for _, item := range g.level.items {
|
||||
if item.health == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
drawn += g.renderSprite(item.x, item.y, 0, 0, 0, 1.0, 1.0, item.sprite, screen)
|
||||
}
|
||||
|
||||
for _, c := range g.level.creeps {
|
||||
if c.health == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
drawn += g.renderSprite(c.x, c.y, 0, 0, 0, c.sprites[c.frame], screen)
|
||||
drawn += g.renderSprite(c.x, c.y, 0, 0, 0, 1.0, 1.0, c.sprites[c.frame], screen)
|
||||
if c.frames > 1 && time.Since(c.lastFrame) >= 75*time.Millisecond {
|
||||
c.frame++
|
||||
if c.frame == c.frames {
|
||||
|
@ -812,7 +921,18 @@ func (g *game) renderLevel(screen *ebiten.Image) int {
|
|||
}
|
||||
|
||||
for _, p := range g.projectiles {
|
||||
drawn += g.renderSprite(p.x, p.y, 0, 0, p.angle, bulletImage, screen)
|
||||
drawn += g.renderSprite(p.x, p.y, 0, 0, p.angle, 1.0, 1.0, bulletImage, screen)
|
||||
}
|
||||
|
||||
repelTime := g.player.repelUntil.Sub(time.Now())
|
||||
if repelTime > 0 && repelTime < 7*time.Second {
|
||||
scale := repelTime.Seconds() + 1
|
||||
offset := 12 * scale
|
||||
alpha := 0.25
|
||||
if repelTime.Seconds() < 3 {
|
||||
alpha = repelTime.Seconds() / 12
|
||||
}
|
||||
drawn += g.renderSprite(g.player.x+0.25, g.player.y+0.25, -offset, -offset, 0, scale, alpha, g.garlicImage, screen)
|
||||
}
|
||||
|
||||
playerSprite := g.ojasSS.Frame1
|
||||
|
@ -825,14 +945,14 @@ func (g *game) renderLevel(screen *ebiten.Image) int {
|
|||
weaponSprite = g.player.weapon.sprite
|
||||
mul = -1
|
||||
}
|
||||
drawn += g.renderSprite(g.player.x, g.player.y, 0, 0, playerAngle, playerSprite, screen)
|
||||
drawn += g.renderSprite(g.player.x, g.player.y, 0, 0, playerAngle, 1.0, 1.0, playerSprite, screen)
|
||||
if g.player.weapon != nil {
|
||||
drawn += g.renderSprite(g.player.x, g.player.y, 11*mul, 9, playerAngle, weaponSprite, screen)
|
||||
drawn += g.renderSprite(g.player.x, g.player.y, 11*mul, 9, playerAngle, 1.0, 1.0, weaponSprite, screen)
|
||||
}
|
||||
|
||||
flashDuration := 40 * time.Millisecond
|
||||
if time.Since(g.player.weapon.lastFire) < flashDuration {
|
||||
drawn += g.renderSprite(g.player.x, g.player.y, 39, -1, g.player.angle, flashImage, screen)
|
||||
drawn += g.renderSprite(g.player.x, g.player.y, 39, -1, g.player.angle, 1.0, 1.0, flashImage, screen)
|
||||
}
|
||||
|
||||
return drawn
|
||||
|
@ -941,7 +1061,7 @@ func (g *game) addBloodSplatter(x, y float64) {
|
|||
}
|
||||
}
|
||||
|
||||
t := g.currentLevel.Tile(int(x), int(y))
|
||||
t := g.level.Tile(int(x), int(y))
|
||||
if t != nil {
|
||||
t.AddSprite(splatterSprite)
|
||||
}
|
||||
|
|
2
go.mod
2
go.mod
|
@ -13,7 +13,7 @@ require (
|
|||
github.com/hajimehoshi/go-mp3 v0.3.2 // indirect
|
||||
github.com/hajimehoshi/oto/v2 v2.1.0-alpha.2 // indirect
|
||||
github.com/jezek/xgb v0.0.0-20210312150743-0e0f116e1240 // indirect
|
||||
golang.org/x/exp v0.0.0-20211008200323-95152d363a1c // indirect
|
||||
golang.org/x/exp v0.0.0-20211011213208-1d87cf485e27 // indirect
|
||||
golang.org/x/mobile v0.0.0-20210924032853-1c027f395ef7 // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
|
||||
|
|
4
go.sum
4
go.sum
|
@ -288,8 +288,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||
golang.org/x/exp v0.0.0-20211008200323-95152d363a1c h1:SDv+vPR9zP9mz1NZ7rUDXvVbpr6dqRlFj+NRNv72etI=
|
||||
golang.org/x/exp v0.0.0-20211008200323-95152d363a1c/go.mod h1:a3o/VtDNHN+dCVLEpzjjUHOzR+Ln3DHX056ZPzoZGGA=
|
||||
golang.org/x/exp v0.0.0-20211011213208-1d87cf485e27 h1:xUVDmMyOkmVK1aEyyBO+z9LzF5UUQJrV12rZ70CvXnU=
|
||||
golang.org/x/exp v0.0.0-20211011213208-1d87cf485e27/go.mod h1:a3o/VtDNHN+dCVLEpzjjUHOzR+Ln3DHX056ZPzoZGGA=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
itemTypeGarlic = iota
|
||||
)
|
||||
|
||||
type gameItem struct {
|
||||
x, y float64
|
||||
|
||||
sprite *ebiten.Image
|
||||
|
||||
itemType int
|
||||
|
||||
level *Level
|
||||
player *gamePlayer
|
||||
|
||||
health int
|
||||
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func (item *gameItem) useScore() int {
|
||||
return 275
|
||||
}
|
37
level.go
37
level.go
|
@ -13,6 +13,12 @@ type Level struct {
|
|||
|
||||
tiles [][]*Tile // (Y,X) array of tiles
|
||||
tileSize int
|
||||
|
||||
items []*gameItem
|
||||
|
||||
creeps []*gameCreep
|
||||
|
||||
player *gamePlayer
|
||||
}
|
||||
|
||||
// Tile returns the tile at the provided coordinates, or nil.
|
||||
|
@ -42,6 +48,37 @@ func (l *Level) Clamp(x, y float64) (float64, float64) {
|
|||
return x, y
|
||||
}
|
||||
|
||||
func (l *Level) newSpawnLocation() (float64, float64) {
|
||||
SPAWNLOCATION:
|
||||
for {
|
||||
x := float64(rand.Intn(108))
|
||||
y := float64(rand.Intn(108))
|
||||
|
||||
// Too close to player.
|
||||
playerSafeSpace := 7.0
|
||||
dx, dy := deltaXY(x, y, l.player.x, l.player.y)
|
||||
if dx <= playerSafeSpace && dy <= playerSafeSpace {
|
||||
continue
|
||||
}
|
||||
|
||||
// Too close to garlic.
|
||||
garlicSafeSpace := 2.0
|
||||
for _, item := range l.items {
|
||||
if item.health == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
dx, dy = deltaXY(x, y, item.x, item.y)
|
||||
if dx <= garlicSafeSpace && dy <= garlicSafeSpace {
|
||||
continue SPAWNLOCATION
|
||||
}
|
||||
}
|
||||
|
||||
return x, y
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// NewLevel returns a new randomly generated Level.
|
||||
func NewLevel() (*Level, error) {
|
||||
// Create a 108x108 Level.
|
||||
|
|
Loading…
Reference in New Issue