Fireballs and shadows.

This commit is contained in:
2024-11-16 19:03:07 -05:00
parent 1d65d0046e
commit e049e8c3d0
8 changed files with 287 additions and 46 deletions

BIN
assets/hot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -26,6 +26,7 @@ const (
WormDamaged ImgAssetName = "WormDamaged"
Worm ImgAssetName = "WormDefault"
Cloud ImgAssetName = "Cloud"
Fireball ImgAssetName = "Fireball"
)
var (
@@ -57,6 +58,8 @@ var (
wormdefault_img []byte
//go:embed cloud.png
cloud_img []byte
//go:embed hot.png
fireball_img []byte
)
func LoadImages() {
@@ -75,6 +78,7 @@ func LoadImages() {
ImageBank[WormDamaged] = LoadImagesFatal(worm_img)
ImageBank[Worm] = LoadImagesFatal(wormdefault_img)
ImageBank[Cloud] = LoadImagesFatal(cloud_img)
ImageBank[Fireball] = LoadImagesFatal(fireball_img)
}

View File

@@ -24,4 +24,5 @@ type Enemies interface {
SetExplosionInitiated()
Health() int
MaxHealth() int
GetAngle() float64
}

118
elements/fireball.go Normal file
View File

@@ -0,0 +1,118 @@
package elements
import (
"image"
"math"
"mover/assets"
"mover/gamedata"
"github.com/hajimehoshi/ebiten/v2"
)
type FireBall struct {
Sprite *ebiten.Image
position gamedata.Coordinates
angle float64
velocity float64
cycle int
}
func NewFireBall(angle, velocity float64) *FireBall {
fb := &FireBall{
Sprite: ebiten.NewImage(50, 50),
cycle: 0,
angle: angle,
velocity: velocity,
}
return fb
}
func (fb *FireBall) Update() error {
fb.position.X += fb.velocity * math.Cos(fb.angle)
fb.position.Y += fb.velocity * math.Sin(fb.angle)
fb.cycle++
return nil
}
func (fb *FireBall) Draw() {
fb.Sprite.Clear()
//fb.Sprite.Fill(color.RGBA{R: 0xff, G: 0x00, B: 0x00, A: 0xff})
idx := fb.cycle / 8 % 5
x0 := idx * 50
x1 := x0 + 50
y0 := 0
y1 := 50
fb.Sprite.DrawImage(assets.ImageBank[assets.Fireball].SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), nil)
}
func (fb *FireBall) GetPosition() gamedata.Coordinates {
return fb.position
}
func (fb *FireBall) SetPosition(pos gamedata.Coordinates) {
fb.position = pos
}
func (fb *FireBall) SetTarget(gamedata.Coordinates) {
}
func (fb *FireBall) GetAngle() float64 {
return fb.angle
}
func (fb *FireBall) GetVelocity() float64 {
return fb.velocity
}
func (fb *FireBall) GetSprite() *ebiten.Image {
return fb.Sprite
}
func (fb *FireBall) ClearTouched() {
}
func (fb *FireBall) ExplosionInitiated() bool {
return false
}
func (fb *FireBall) GetEnemyState() gamedata.EnemyState {
return gamedata.EnemyStateDefault
}
func (fb *FireBall) SetHit() {
}
func (fb *FireBall) SetToggle() {
}
func (fb *FireBall) IsToggled() bool {
return false
}
func (fb *FireBall) SetTouched() {
}
func (fb *FireBall) IsTouched() bool {
return false
}
func (fb *FireBall) SetExplosionInitiated() {
}
func (fb *FireBall) Health() int {
return 0
}
func (fb *FireBall) MaxHealth() int {
return 1
}

View File

@@ -171,3 +171,7 @@ func (f *FlyEye) Health() int {
func (f *FlyEye) MaxHealth() int {
return 1
}
func (f *FlyEye) GetAngle() float64 {
return 0
}

View File

@@ -3,6 +3,7 @@ package elements
import (
"image"
"image/color"
"math/rand/v2"
"mover/assets"
"mover/gamedata"
@@ -28,6 +29,9 @@ type FlyGoblin struct {
toggle bool
sploding bool
damage bool
called bool
deathcallback func()
fireballcallback func()
}
func NewFlyGoblin() *FlyGoblin {
@@ -37,6 +41,7 @@ func NewFlyGoblin() *FlyGoblin {
MaksDest: ebiten.NewImage(96, 96),
health: FG_MAXHEALTH,
damageduration: 0,
called: false,
}
fg.Maks.Fill(color.White)
return fg
@@ -61,6 +66,22 @@ func (f *FlyGoblin) Update() error {
f.position.X += dx / 48
f.position.Y += dy / 48
//10% chance to summon fireball
fb := rand.Float64() >= 0.9
if (f.cycle/8)%4 == 0 && fb {
if f.fireballcallback != nil {
f.fireballcallback()
}
}
}
if f.state == gamedata.EnemyStateDead && !f.called {
f.called = true
if f.deathcallback != nil {
f.deathcallback()
}
}
f.cycle++
@@ -107,6 +128,7 @@ func (f *FlyGoblin) Draw() {
f.Sprite.DrawImage(assets.ImageBank[assets.FlyEyeDying].SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), op)
if idx == 3 {
f.state = gamedata.EnemyStateDead
}
}
@@ -182,3 +204,15 @@ func (f *FlyGoblin) Health() int {
func (f *FlyGoblin) MaxHealth() int {
return FG_MAXHEALTH
}
func (f *FlyGoblin) SetDeathEvent(somefunc func()) {
f.deathcallback = somefunc
}
func (f *FlyGoblin) SetFireballCallback(somefunc func()) {
f.fireballcallback = somefunc
}
func (f *FlyGoblin) GetAngle() float64 {
return 0
}

View File

@@ -26,12 +26,14 @@ type Canvas struct {
initialized bool
goblinspawned bool
goblindead bool
lastInputs gamedata.GameInputs
runtime float64
counter int
score int
hero *elements.Hero
charge *elements.Explosion
goblin *elements.FlyGoblin
enemies []elements.Enemies
projectiles []*elements.Projectile
gameover bool
@@ -49,6 +51,7 @@ func NewCanvas(a gamedata.Area) *Canvas {
initialized: false,
gameover: false,
goblinspawned: false,
goblindead: false,
score: 0,
runtime: 0.,
counter: 0,
@@ -97,10 +100,35 @@ func (c *Canvas) Draw(drawimg *ebiten.Image) {
c.Sprite.DrawImage(assets.ImageBank[assets.Weapon], op)
}
for _, es := range c.enemies {
if es.GetEnemyState() < gamedata.EnemyStateExploding {
dx := float64(assets.ImageBank[assets.FlyEyeShadow].Bounds().Dx()) / 2
dy := float64(assets.ImageBank[assets.FlyEyeShadow].Bounds().Dy()) / 2
sx := float64(es.GetSprite().Bounds().Dx()) / 48
sy := float64(es.GetSprite().Bounds().Dy()) / 48
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(-dx, -dy)
op.GeoM.Scale(sx, sy)
op.GeoM.Translate(es.GetPosition().X, es.GetPosition().Y+float64(es.GetSprite().Bounds().Dx())/2)
c.Sprite.DrawImage(assets.ImageBank[assets.FlyEyeShadow], op)
}
}
for _, e := range c.enemies {
e.Draw()
xshift := float64(e.GetSprite().Bounds().Dx() / 2)
yshift := float64(e.GetSprite().Bounds().Dy() / 2)
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(e.GetPosition().X-float64(e.GetSprite().Bounds().Dx())/2, e.GetPosition().Y-float64(e.GetSprite().Bounds().Dy())/2)
op.GeoM.Translate(-xshift, -yshift)
op.GeoM.Rotate(e.GetAngle())
op.GeoM.Translate(e.GetPosition().X, e.GetPosition().Y)
//op := &ebiten.DrawImageOptions{}
//op.GeoM.Translate(e.GetPosition().X-float64(e.GetSprite().Bounds().Dx())/2, e.GetPosition().Y-float64(e.GetSprite().Bounds().Dy())/2)
c.Sprite.DrawImage(e.GetSprite(), op)
//do we need a health bar for this enemy?
@@ -152,6 +180,7 @@ func (c *Canvas) Initialize() {
c.counter = 0
c.runtime = 0.
c.goblinspawned = false
c.goblindead = false
//temporary
c.hero.Action = elements.HeroActionDefault
@@ -354,7 +383,18 @@ func (c *Canvas) UpdateEnemies() {
}
if !c.gameover {
if !c.goblinspawned {
if !c.goblinspawned || c.goblindead {
c.SpawnFlyEyes()
}
if !c.goblinspawned { //&& c.counter > 1200 && !c.goblindead {
c.SpawnGoblin()
}
}
}
func (c *Canvas) SpawnFlyEyes() {
//spawn new enemies
f := 40000 / (c.counter + 1)
@@ -380,15 +420,31 @@ func (c *Canvas) UpdateEnemies() {
c.enemies = append(c.enemies, newenemy)
}
}
func (c *Canvas) SpawnGoblin() {
newfg := elements.NewFlyGoblin()
newfg.SetDeathEvent(c.GoblinDeathEvent)
newfg.SetFireballCallback(c.GoblinFireballEvent)
x0 := rand.Float64() * 640
y0 := rand.Float64() * 480
quadrant := rand.IntN(3)
switch quadrant {
case 0:
newfg.SetPosition(gamedata.Coordinates{X: x0, Y: -96})
case 1:
newfg.SetPosition(gamedata.Coordinates{X: x0, Y: 480 + 48})
case 2:
newfg.SetPosition(gamedata.Coordinates{X: -96, Y: y0})
case 3:
newfg.SetPosition(gamedata.Coordinates{X: 640 + x0, Y: y0})
}
if !c.goblinspawned && c.counter > 1200 {
newfg := elements.NewFlyGoblin()
c.goblin = newfg
c.enemies = append(c.enemies, newfg)
c.goblinspawned = true
}
}
}
func (c *Canvas) HasCollided(mask *ebiten.Image, size int) bool {
@@ -430,3 +486,27 @@ func (c *Canvas) CleanupTargets() {
}
c.enemies = c.enemies[:i]
}
func (c *Canvas) GoblinDeathEvent() {
c.goblindead = true
c.goblinspawned = false
c.score += 10
}
func (c *Canvas) GoblinFireballEvent() {
if !c.gameover {
velocity := 8.
dx := c.hero.Pos.X - c.goblin.GetPosition().X
dy := c.hero.Pos.Y - c.goblin.GetPosition().Y
angle := math.Atan2(dy, dx)
//add some randomness to the angle
arand := rand.Float64() * math.Pi / 3
newfb := elements.NewFireBall(angle+arand, velocity)
newfb.SetPosition(c.goblin.GetPosition())
c.enemies = append(c.enemies, newfb)
}
}

View File

@@ -26,7 +26,7 @@ func NewManager() Manager {
return Manager{
Info: gamedata.GameInfo{
Name: "survive",
Version: "0.26",
Version: "0.30",
Dimensions: gamedata.Area{
Width: defaultWidth,
Height: defaultHeight,