Skip to content

Commit

Permalink
Merge pull request #35 from pankona/green-bug-impl
Browse files Browse the repository at this point in the history
implement green bugs update
  • Loading branch information
pankona authored Jun 26, 2024
2 parents 8fb9807 + 62485a2 commit 8fffa57
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 15 deletions.
208 changes: 196 additions & 12 deletions bugs.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (
"math"

"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/vector"

_ "embed"
"image/color"
_ "image/png"
)

Expand Down Expand Up @@ -71,7 +73,7 @@ func newBug(game *Game, bugColor bugColor, x, y int, onDestroy func(b *bug)) *bu
}()
bugImage := bugsImage.SubImage(rect).(*ebiten.Image)

return &bug{
bug := &bug{
game: game,

x: x,
Expand All @@ -93,6 +95,31 @@ func newBug(game *Game, bugColor bugColor, x, y int, onDestroy func(b *bug)) *bu

onDestroy: onDestroy,
}

switch bugColor {
case bugsRed:
bug.speed = 5
bug.attackPower = 1
bug.attackRange = 1
bug.health = 2
bug.name = "Red bug"
case bugsBlue:
bug.speed = 4
bug.attackPower = 1
bug.attackRange = 1
bug.health = 3
bug.name = "Blue bug"
case bugsGreen:
bug.speed = 3
bug.attackPower = 1
bug.attackRange = 50
bug.health = 4
bug.name = "Green bug"
default:
log.Fatal("invalid bug color")
}

return bug
}

func redBug() image.Rectangle {
Expand Down Expand Up @@ -122,6 +149,69 @@ func (b *bug) Update() {

func (b *bug) attack(a Damager) {
a.Damage(b.attackPower)

// エフェクトを表示する
switch b.selfColor {
case bugsRed:
// TODO: implement
case bugsBlue:
// TODO: implement
case bugsGreen:
tx, ty := a.(Building).Position()
e := newGreenBugAttackEffect(b.game, b.x, b.y, tx, ty)
b.game.updateHandler.Add(e)
b.game.drawHandler.Add(e)
}
}

type greenBugAttackEffect struct {
game *Game

currentX, currentY int
startX, startY int
targetX, targetY int

erapsedFrame int

zindex int
}

func newGreenBugAttackEffect(game *Game, startX, startY, targetX, targetY int) *greenBugAttackEffect {
return &greenBugAttackEffect{
game: game,

currentX: startX,
currentY: startY,
startX: startX,
startY: startY,
targetX: targetX,
targetY: targetY,

zindex: 220,
}
}

func (e *greenBugAttackEffect) Update() {
// 攻撃エフェクトを描画する
// 直線上に移動するエフェクトを描画する
// 30 frame かけて target に向かって移動する
e.currentX = e.startX + (e.targetX-e.startX)*e.erapsedFrame/30
e.currentY = e.startY + (e.targetY-e.startY)*e.erapsedFrame/30
if e.erapsedFrame <= 30 {
e.erapsedFrame++
return
}
e.game.updateHandler.Remove(e)
e.game.drawHandler.Remove(e)
}

func (e *greenBugAttackEffect) Draw(screen *ebiten.Image) {
// 直線上に移動するエフェクトを描画する
vector.StrokeLine(screen, float32(e.startX), float32(e.startY), float32(e.currentX), float32(e.currentY), 10, color.RGBA{R: 128, G: 128, B: 128, A: 128}, true)
}

func (e *greenBugAttackEffect) ZIndex() int {
return e.zindex
}

type Damager interface {
Expand Down Expand Up @@ -195,14 +285,21 @@ func redBugUpdate(b *bug) {

// house に向かう
var moveTargetX, moveTargetY int
var found bool

for _, building := range b.game.buildings {
if building.Name() == "House" {
moveTargetX, moveTargetY = building.Position()
found = true
break
}
}

if !found {
// すべての建物が破壊されている場合はその場にとどまる
return
}

// ターゲットへの直線距離を計算
dx := moveTargetX - b.x
dy := moveTargetY - b.y
Expand Down Expand Up @@ -261,6 +358,10 @@ func blueBugUpdate(b *bug) {

// 対象の建物と bugs の攻撃範囲を踏まえた当たり判定を行う
// bugs は size + attackRange の範囲を当たり判定として用いる
if nearestBuilding == nil {
// すべての建物が破壊されている場合はその場にとどまる
return
}
target := nearestBuilding.(Building)
x, y := target.Position()
width, height := target.Size()
Expand Down Expand Up @@ -328,20 +429,103 @@ func blueBugUpdate(b *bug) {
}

func greenBugUpdate(b *bug) {
// todo: implement
// 緑虫の特徴
// 家に向かって一直線に進む。
// 攻撃は一定時間ごとに行う。攻撃範囲が広い。飛び道具のようなものを放つ。
// 攻撃範囲に任意の障害物が入ったとき、その障害物に向かって攻撃を行う。
// 体力は青虫よりも多い。
// 出現頻度は低い。
// 動きは遅い。

// target に向かう途中に障害物が攻撃射程に入ったとき、その障害物を target とする
// いずれかの建物が攻撃レンジに入っているか確認
var attackTarget Damager
for _, building := range b.game.buildings {
x, y := building.Position()
width, height := building.Size()

// 対象の建物と bugs の攻撃範囲を踏まえた当たり判定を行う
// bugs は size + attackRange の範囲を当たり判定として用いる
if intersects(
// bug
rect{
b.x - b.width/2 - int(b.attackRange), b.y - b.height/2 - int(b.attackRange),
b.width + int(b.attackRange)*2, b.height + int(b.attackRange)*2,
},
// building
rect{x - width/2, y - height/2,
width, height},
) {
// 攻撃射程圏内であるので、その建物を attack 対象にする
attackTarget = building.(Damager)

break
}
}

// attack target がいるならば攻撃する。そうでないならば house に向かう
if attackTarget != nil {
// クールダウン中でなければ攻撃
if b.attackCooldown <= 0 {
b.attack(attackTarget)
b.attackCooldown = 60
} else {
// クールダウンを消化する
b.attackCooldown -= 1
}

return
}

// house に向かう
var moveTargetX, moveTargetY int
var found bool
for _, building := range b.game.buildings {
if building.Name() == "House" {
moveTargetX, moveTargetY = building.Position()
found = true
break
}
}

if !found {
// すべての建物が破壊されている場合はその場にとどまる
return
}

// ターゲットへの直線距離を計算
dx := moveTargetX - b.x
dy := moveTargetY - b.y

// 移動方向のラジアンを計算
angle := math.Atan2(float64(dy), float64(dx))

// 回避動作
// 虫同士がぴったり重ならないようにするための計算
// やや自信のないロジックではある
avoidX, avoidY := 0.0, 0.0
for _, e := range b.game.enemies {
ee := e.(*bug)
if ee != b {
distX := float64(ee.x - b.x)
distY := float64(ee.y - b.y)
distance := math.Sqrt(distX*distX + distY*distY)
if distance > 0 && distance < float64(b.width) {
avoidX -= distX / distance
avoidY -= distY / distance
}
}
}

// 移動
moveX := math.Cos(angle)*b.speed + avoidX
moveY := math.Sin(angle)*b.speed + avoidY
b.x += int(moveX)
b.y += int(moveY)
}

func (b *bug) Name() string {
switch b.selfColor {
case bugsRed:
return "Red bug"
case bugsBlue:
return "Blue bug"
case bugsGreen:
return "Green bug"
}
log.Fatal("invalid bug color")
return ""
return b.name
}

func (b *bug) Position() (int, int) {
Expand Down
1 change: 1 addition & 0 deletions house.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func newHouse(game *Game) *house {
// TODO: 爆発したり消えたりする処理を書く
// ここでフラグを設定しといて、Update() や Draw で続きの処理を行うのもあり
// いったんシンプルに消す
h.game.RemoveBuilding(h)
h.game.drawHandler.Remove(h)
},
}
Expand Down
9 changes: 6 additions & 3 deletions wavectl.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,14 @@ func generateSpawnInfos(num int) []spawnInfo {
y = rand.Intn(screenHeight)
}

// 赤虫:青虫 = 4:6 で生成する
if rand.Intn(10) < 4 {
// 赤虫:青虫:緑 = 3:5:2 で生成する
r := rand.Intn(10)
if r < 3 {
infos = append(infos, spawnInfo{bugsRed, x, y})
} else {
} else if r < 8 {
infos = append(infos, spawnInfo{bugsBlue, x, y})
} else {
infos = append(infos, spawnInfo{bugsGreen, x, y})
}
}

Expand Down

0 comments on commit 8fffa57

Please sign in to comment.