Fireballs and shadows.
This commit is contained in:
BIN
assets/hot.png
Normal file
BIN
assets/hot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
@@ -26,6 +26,7 @@ const (
|
|||||||
WormDamaged ImgAssetName = "WormDamaged"
|
WormDamaged ImgAssetName = "WormDamaged"
|
||||||
Worm ImgAssetName = "WormDefault"
|
Worm ImgAssetName = "WormDefault"
|
||||||
Cloud ImgAssetName = "Cloud"
|
Cloud ImgAssetName = "Cloud"
|
||||||
|
Fireball ImgAssetName = "Fireball"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -57,6 +58,8 @@ var (
|
|||||||
wormdefault_img []byte
|
wormdefault_img []byte
|
||||||
//go:embed cloud.png
|
//go:embed cloud.png
|
||||||
cloud_img []byte
|
cloud_img []byte
|
||||||
|
//go:embed hot.png
|
||||||
|
fireball_img []byte
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadImages() {
|
func LoadImages() {
|
||||||
@@ -75,6 +78,7 @@ func LoadImages() {
|
|||||||
ImageBank[WormDamaged] = LoadImagesFatal(worm_img)
|
ImageBank[WormDamaged] = LoadImagesFatal(worm_img)
|
||||||
ImageBank[Worm] = LoadImagesFatal(wormdefault_img)
|
ImageBank[Worm] = LoadImagesFatal(wormdefault_img)
|
||||||
ImageBank[Cloud] = LoadImagesFatal(cloud_img)
|
ImageBank[Cloud] = LoadImagesFatal(cloud_img)
|
||||||
|
ImageBank[Fireball] = LoadImagesFatal(fireball_img)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,4 +24,5 @@ type Enemies interface {
|
|||||||
SetExplosionInitiated()
|
SetExplosionInitiated()
|
||||||
Health() int
|
Health() int
|
||||||
MaxHealth() int
|
MaxHealth() int
|
||||||
|
GetAngle() float64
|
||||||
}
|
}
|
||||||
|
|||||||
118
elements/fireball.go
Normal file
118
elements/fireball.go
Normal 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
|
||||||
|
}
|
||||||
@@ -171,3 +171,7 @@ func (f *FlyEye) Health() int {
|
|||||||
func (f *FlyEye) MaxHealth() int {
|
func (f *FlyEye) MaxHealth() int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FlyEye) GetAngle() float64 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package elements
|
|||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"math/rand/v2"
|
||||||
"mover/assets"
|
"mover/assets"
|
||||||
"mover/gamedata"
|
"mover/gamedata"
|
||||||
|
|
||||||
@@ -28,6 +29,9 @@ type FlyGoblin struct {
|
|||||||
toggle bool
|
toggle bool
|
||||||
sploding bool
|
sploding bool
|
||||||
damage bool
|
damage bool
|
||||||
|
called bool
|
||||||
|
deathcallback func()
|
||||||
|
fireballcallback func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFlyGoblin() *FlyGoblin {
|
func NewFlyGoblin() *FlyGoblin {
|
||||||
@@ -37,6 +41,7 @@ func NewFlyGoblin() *FlyGoblin {
|
|||||||
MaksDest: ebiten.NewImage(96, 96),
|
MaksDest: ebiten.NewImage(96, 96),
|
||||||
health: FG_MAXHEALTH,
|
health: FG_MAXHEALTH,
|
||||||
damageduration: 0,
|
damageduration: 0,
|
||||||
|
called: false,
|
||||||
}
|
}
|
||||||
fg.Maks.Fill(color.White)
|
fg.Maks.Fill(color.White)
|
||||||
return fg
|
return fg
|
||||||
@@ -61,6 +66,22 @@ func (f *FlyGoblin) Update() error {
|
|||||||
f.position.X += dx / 48
|
f.position.X += dx / 48
|
||||||
f.position.Y += dy / 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++
|
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)
|
f.Sprite.DrawImage(assets.ImageBank[assets.FlyEyeDying].SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), op)
|
||||||
if idx == 3 {
|
if idx == 3 {
|
||||||
f.state = gamedata.EnemyStateDead
|
f.state = gamedata.EnemyStateDead
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,3 +204,15 @@ func (f *FlyGoblin) Health() int {
|
|||||||
func (f *FlyGoblin) MaxHealth() int {
|
func (f *FlyGoblin) MaxHealth() int {
|
||||||
return FG_MAXHEALTH
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,12 +26,14 @@ type Canvas struct {
|
|||||||
|
|
||||||
initialized bool
|
initialized bool
|
||||||
goblinspawned bool
|
goblinspawned bool
|
||||||
|
goblindead bool
|
||||||
lastInputs gamedata.GameInputs
|
lastInputs gamedata.GameInputs
|
||||||
runtime float64
|
runtime float64
|
||||||
counter int
|
counter int
|
||||||
score int
|
score int
|
||||||
hero *elements.Hero
|
hero *elements.Hero
|
||||||
charge *elements.Explosion
|
charge *elements.Explosion
|
||||||
|
goblin *elements.FlyGoblin
|
||||||
enemies []elements.Enemies
|
enemies []elements.Enemies
|
||||||
projectiles []*elements.Projectile
|
projectiles []*elements.Projectile
|
||||||
gameover bool
|
gameover bool
|
||||||
@@ -49,6 +51,7 @@ func NewCanvas(a gamedata.Area) *Canvas {
|
|||||||
initialized: false,
|
initialized: false,
|
||||||
gameover: false,
|
gameover: false,
|
||||||
goblinspawned: false,
|
goblinspawned: false,
|
||||||
|
goblindead: false,
|
||||||
score: 0,
|
score: 0,
|
||||||
runtime: 0.,
|
runtime: 0.,
|
||||||
counter: 0,
|
counter: 0,
|
||||||
@@ -97,10 +100,35 @@ func (c *Canvas) Draw(drawimg *ebiten.Image) {
|
|||||||
c.Sprite.DrawImage(assets.ImageBank[assets.Weapon], op)
|
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 {
|
for _, e := range c.enemies {
|
||||||
e.Draw()
|
e.Draw()
|
||||||
|
|
||||||
|
xshift := float64(e.GetSprite().Bounds().Dx() / 2)
|
||||||
|
yshift := float64(e.GetSprite().Bounds().Dy() / 2)
|
||||||
|
|
||||||
op := &ebiten.DrawImageOptions{}
|
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)
|
c.Sprite.DrawImage(e.GetSprite(), op)
|
||||||
|
|
||||||
//do we need a health bar for this enemy?
|
//do we need a health bar for this enemy?
|
||||||
@@ -152,6 +180,7 @@ func (c *Canvas) Initialize() {
|
|||||||
c.counter = 0
|
c.counter = 0
|
||||||
c.runtime = 0.
|
c.runtime = 0.
|
||||||
c.goblinspawned = false
|
c.goblinspawned = false
|
||||||
|
c.goblindead = false
|
||||||
|
|
||||||
//temporary
|
//temporary
|
||||||
c.hero.Action = elements.HeroActionDefault
|
c.hero.Action = elements.HeroActionDefault
|
||||||
@@ -354,7 +383,18 @@ func (c *Canvas) UpdateEnemies() {
|
|||||||
}
|
}
|
||||||
if !c.gameover {
|
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
|
//spawn new enemies
|
||||||
f := 40000 / (c.counter + 1)
|
f := 40000 / (c.counter + 1)
|
||||||
|
|
||||||
@@ -382,13 +422,29 @@ func (c *Canvas) UpdateEnemies() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.goblinspawned && c.counter > 1200 {
|
func (c *Canvas) SpawnGoblin() {
|
||||||
newfg := elements.NewFlyGoblin()
|
newfg := elements.NewFlyGoblin()
|
||||||
c.enemies = append(c.enemies, newfg)
|
newfg.SetDeathEvent(c.GoblinDeathEvent)
|
||||||
c.goblinspawned = true
|
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})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
c.goblin = newfg
|
||||||
|
c.enemies = append(c.enemies, newfg)
|
||||||
|
c.goblinspawned = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Canvas) HasCollided(mask *ebiten.Image, size int) bool {
|
func (c *Canvas) HasCollided(mask *ebiten.Image, size int) bool {
|
||||||
@@ -430,3 +486,27 @@ func (c *Canvas) CleanupTargets() {
|
|||||||
}
|
}
|
||||||
c.enemies = c.enemies[:i]
|
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)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ func NewManager() Manager {
|
|||||||
return Manager{
|
return Manager{
|
||||||
Info: gamedata.GameInfo{
|
Info: gamedata.GameInfo{
|
||||||
Name: "survive",
|
Name: "survive",
|
||||||
Version: "0.26",
|
Version: "0.30",
|
||||||
Dimensions: gamedata.Area{
|
Dimensions: gamedata.Area{
|
||||||
Width: defaultWidth,
|
Width: defaultWidth,
|
||||||
Height: defaultHeight,
|
Height: defaultHeight,
|
||||||
|
|||||||
Reference in New Issue
Block a user