2021-10-06 04:05:02 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2021-10-08 04:00:33 +00:00
|
|
|
"math"
|
2021-10-06 04:05:02 +00:00
|
|
|
"math/rand"
|
|
|
|
"sync"
|
2021-10-11 06:10:58 +00:00
|
|
|
"time"
|
2021-10-06 04:05:02 +00:00
|
|
|
|
|
|
|
"github.com/hajimehoshi/ebiten/v2"
|
|
|
|
)
|
|
|
|
|
2021-10-11 06:10:58 +00:00
|
|
|
const (
|
|
|
|
TypeVampire = iota
|
|
|
|
TypeBat
|
|
|
|
TypeGhost
|
|
|
|
)
|
|
|
|
|
2021-10-06 14:18:38 +00:00
|
|
|
type gameCreep struct {
|
2021-10-11 06:10:58 +00:00
|
|
|
x, y float64
|
|
|
|
|
|
|
|
sprites []*ebiten.Image
|
|
|
|
|
|
|
|
frame int
|
|
|
|
frames int
|
|
|
|
lastFrame time.Time
|
|
|
|
|
|
|
|
creepType int
|
2021-10-06 04:05:02 +00:00
|
|
|
|
|
|
|
moveX, moveY float64
|
|
|
|
|
|
|
|
tick int
|
|
|
|
nextAction int
|
|
|
|
|
2021-10-08 04:00:33 +00:00
|
|
|
level *Level
|
|
|
|
player *gamePlayer
|
2021-10-06 14:18:38 +00:00
|
|
|
|
2021-10-06 15:03:13 +00:00
|
|
|
health int
|
|
|
|
|
2021-10-06 04:05:02 +00:00
|
|
|
sync.Mutex
|
|
|
|
}
|
|
|
|
|
2021-10-11 06:10:58 +00:00
|
|
|
func (c *gameCreep) queueNextAction() {
|
|
|
|
if c.creepType == TypeBat {
|
|
|
|
c.nextAction = 288 + rand.Intn(288)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
c.nextAction = 144 + rand.Intn(720)
|
|
|
|
}
|
|
|
|
|
2021-10-12 03:22:13 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-10-06 14:18:38 +00:00
|
|
|
func (c *gameCreep) doNextAction() {
|
2021-10-11 07:52:48 +00:00
|
|
|
c.queueNextAction()
|
|
|
|
|
2021-10-08 04:00:33 +00:00
|
|
|
randMovementA := (rand.Float64() - 0.5) / 7
|
|
|
|
randMovementB := (rand.Float64() - 0.5) / 7
|
2021-10-11 07:52:48 +00:00
|
|
|
|
|
|
|
dx, dy := deltaXY(c.x, c.y, c.player.x, c.player.y)
|
|
|
|
seekDistance := 7.0
|
|
|
|
if (dx < seekDistance && dy < seekDistance) || rand.Intn(7) == 0 {
|
2021-10-08 04:00:33 +00:00
|
|
|
// Seek player.
|
|
|
|
c.moveX = c.x - c.player.x
|
|
|
|
if c.moveX < 0 {
|
|
|
|
c.moveX = math.Abs(randMovementA)
|
|
|
|
} else {
|
|
|
|
c.moveX = math.Abs(randMovementA) * -1
|
|
|
|
}
|
|
|
|
c.moveY = c.y - c.player.y
|
|
|
|
if c.moveY < 0 {
|
|
|
|
c.moveY = math.Abs(randMovementB)
|
|
|
|
} else {
|
|
|
|
c.moveY = math.Abs(randMovementB) * -1
|
|
|
|
}
|
2021-10-11 07:52:48 +00:00
|
|
|
|
|
|
|
c.nextAction *= 2
|
2021-10-08 04:00:33 +00:00
|
|
|
} else {
|
|
|
|
c.moveX = randMovementA
|
|
|
|
c.moveY = randMovementB
|
|
|
|
}
|
2021-10-06 15:03:13 +00:00
|
|
|
|
|
|
|
if c.x <= 2 && c.moveX < 0 {
|
|
|
|
c.moveX *= 1
|
|
|
|
} else if c.x >= float64(c.level.w-3) && c.moveX > 0 {
|
|
|
|
c.moveX *= 1
|
|
|
|
}
|
|
|
|
if c.y <= 2 && c.moveY > 0 {
|
|
|
|
c.moveY *= 1
|
|
|
|
} else if c.y >= float64(c.level.h-3) && c.moveY < 0 {
|
|
|
|
c.moveY *= 1
|
|
|
|
}
|
2021-10-06 04:05:02 +00:00
|
|
|
}
|
|
|
|
|
2021-10-06 14:18:38 +00:00
|
|
|
func (c *gameCreep) Update() {
|
2021-10-06 04:05:02 +00:00
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
|
|
|
|
2021-10-06 15:03:13 +00:00
|
|
|
if c.health == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-10-06 04:05:02 +00:00
|
|
|
c.tick++
|
|
|
|
if c.tick >= c.nextAction {
|
|
|
|
c.doNextAction()
|
|
|
|
c.tick = 0
|
|
|
|
}
|
|
|
|
|
2021-10-06 15:03:13 +00:00
|
|
|
x, y := c.x+c.moveX, c.y+c.moveY
|
|
|
|
clampX, clampY := c.level.Clamp(x, y)
|
|
|
|
c.x, c.y = clampX, clampY
|
|
|
|
if clampX != x || clampY != y {
|
|
|
|
c.nextAction = 0
|
2021-10-12 03:22:13 +00:00
|
|
|
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()
|
|
|
|
}
|
2021-10-06 15:03:13 +00:00
|
|
|
}
|
2021-10-06 04:05:02 +00:00
|
|
|
}
|
|
|
|
|
2021-10-06 14:18:38 +00:00
|
|
|
func (c *gameCreep) Position() (float64, float64) {
|
2021-10-06 04:05:02 +00:00
|
|
|
c.Lock()
|
|
|
|
defer c.Unlock()
|
|
|
|
return c.x, c.y
|
|
|
|
}
|
2021-10-11 07:52:48 +00:00
|
|
|
|
|
|
|
func (c *gameCreep) killScore() int {
|
|
|
|
switch c.creepType {
|
|
|
|
case TypeVampire:
|
|
|
|
return 50
|
|
|
|
case TypeBat:
|
|
|
|
return 125
|
|
|
|
case TypeGhost:
|
|
|
|
return 75
|
|
|
|
default:
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
}
|