This commit is contained in:
silva guimaraes 2025-08-23 19:55:34 -03:00
parent a411573a06
commit d50bed0777
2 changed files with 292 additions and 143 deletions

237
main.go
View file

@ -3,13 +3,15 @@ package main
import ( import (
"fmt" "fmt"
"math" "math"
"math/rand"
"path"
"strconv" "strconv"
rl "github.com/gen2brain/raylib-go/raylib" rl "github.com/gen2brain/raylib-go/raylib"
) )
// diz para um inimigo em que condições atirar. acionado pelo movementPattern // diz para um inimigo em que condições atirar. acionado pelo movementPattern
type shootingPattern func(*enemy) type shootingPattern func(body)
// diz para uma bala como ela deve se mover. // diz para uma bala como ela deve se mover.
type bulletMovementPattern func(*bullet) rl.Vector2 type bulletMovementPattern func(*bullet) rl.Vector2
@ -18,10 +20,16 @@ type duration float32
const second duration = 1 const second duration = 1
type hazard interface { // inimigos e projéteis type body interface { // implementado por player e enemy
Pos() rl.Vector2 Pos() rl.Vector2
SetPos(rl.Vector2)
Direction() rl.Vector2
} }
// type hazard interface { // inimigos e projéteis
// body
// }
type game struct { type game struct {
arenaWidth int32 arenaWidth int32
arenaHeight int32 arenaHeight int32
@ -47,28 +55,32 @@ type bullet struct {
speed rl.Vector2 speed rl.Vector2
size float32 size float32
dmg int dmg int
enemy bool owner body
} onHit func(body)
onDestroy func()
type player struct {
pos rl.Vector2
speed rl.Vector2
moveSpeed float32
bulletMoveSpeed float32
hitBoxRadius float32
bulletSize float32
focusMode bool
focusSpeedDecrease float32
} }
type enemy struct { type enemy struct {
pos rl.Vector2 pos rl.Vector2
direction rl.Vector2
health int health int
move movementPattern move movementPattern
shoot shootingPattern shoot shootingPattern
hitBoxRadius float32 hitBoxRadius float32
} }
func (e *enemy) Pos() rl.Vector2 {
return e.pos
}
func (e *enemy) Direction() rl.Vector2 {
return e.direction
}
func (e *enemy) SetPos(x rl.Vector2) {
e.pos = x
}
type wave struct { type wave struct {
duration *timer duration *timer
enemies []*enemy enemies []*enemy
@ -117,9 +129,12 @@ func (g *game) removeBullet(index int) {
} }
func (b *bullet) update(g *game, index int) { func (b *bullet) update(g *game, index int) {
b.pos = rl.Vector2Add(b.pos, rl.Vector2Scale(b.speed, g.gameSpeed)) b.pos = rl.Vector2Add(b.pos, rl.Vector2Scale(b.speed, rl.GetFrameTime()*g.gameSpeed))
if !g.insideArena(b.pos) { if !g.insideArena(b.pos) {
if b.onDestroy != nil {
b.onDestroy()
}
g.removeBullet(index) g.removeBullet(index)
return return
} }
@ -127,9 +142,9 @@ func (b *bullet) update(g *game, index int) {
rl.DrawCircleV(b.pos, b.size, rl.Yellow) rl.DrawCircleV(b.pos, b.size, rl.Yellow)
} }
func bulletExplosion(g *game, rate, amount int, bulletSpeed, size float32) shootingPattern { func bulletExplosion(g *game, rate float32, amount int, bulletSpeed, size float32) shootingPattern {
t := newTimer(second * duration(rate)) t := newTimer(second * duration(rate+rand.Float32()))
return func(e *enemy) { return func(e body) {
t.tick(g) t.tick(g)
if !t.isTimeout() { if !t.isTimeout() {
@ -150,8 +165,8 @@ func bulletExplosion(g *game, rate, amount int, bulletSpeed, size float32) shoot
speed: direction, speed: direction,
size: size, size: size,
dmg: 1, dmg: 1,
enemy: true, owner: e,
pos: e.pos, pos: e.Pos(),
}) })
} }
@ -159,31 +174,31 @@ func bulletExplosion(g *game, rate, amount int, bulletSpeed, size float32) shoot
} }
} }
func ShootAtPlayer(g *game, p *player, rate int, // func ShootAtPlayer(g *game, p *player, rate int,
bulletMoveSpeed float32) shootingPattern { // bulletMoveSpeed float32) shootingPattern {
return func(e *enemy) { // return func(e body) {
if int(g.frame)%rate != 0 { // if int(g.frame)%rate != 0 {
return // return
} // }
direction := rl.Vector2Subtract(p.pos, e.pos) // direction := rl.Vector2Subtract(p.pos, e.Pos())
direction = rl.Vector2Normalize(direction) // direction = rl.Vector2Normalize(direction)
direction = rl.Vector2Scale(direction, bulletMoveSpeed) // direction = rl.Vector2Scale(direction, bulletMoveSpeed)
//
g.bullets = append(g.bullets, &bullet{ // g.bullets = append(g.bullets, &bullet{
speed: direction, // speed: direction,
size: 12, // size: 12,
dmg: 1, // dmg: 1,
enemy: true, // enemy: true,
pos: e.pos, // pos: e.Pos(),
}) // })
} // }
} // }
func burstShootAtPlayer(g *game, p *player, rate float32, bulletMoveSpeed float32) shootingPattern { func burstShootAtPlayer(g *game, p *player, rate float32, bulletMoveSpeed float32) shootingPattern {
flag := true flag := true
off := newTimer(second) off := newTimer(second)
on := newTimer(duration(float32(second) * rate)) on := newTimer(duration(float32(second) * rate))
return func(e *enemy) { return func(e body) {
off.tick(g) off.tick(g)
@ -202,7 +217,7 @@ func burstShootAtPlayer(g *game, p *player, rate float32, bulletMoveSpeed float3
} }
on.reset() on.reset()
direction := rl.Vector2Subtract(p.pos, e.pos) direction := rl.Vector2Subtract(p.pos, e.Pos())
direction = rl.Vector2Normalize(direction) direction = rl.Vector2Normalize(direction)
direction = rl.Vector2Scale(direction, bulletMoveSpeed) direction = rl.Vector2Scale(direction, bulletMoveSpeed)
@ -210,14 +225,14 @@ func burstShootAtPlayer(g *game, p *player, rate float32, bulletMoveSpeed float3
speed: direction, speed: direction,
size: 12, size: 12,
dmg: 1, dmg: 1,
enemy: true, owner: e,
pos: e.pos, pos: e.Pos(),
}) })
} }
} }
func shootStraightDown(g *game) shootingPattern { func shootStraightDown(g *game) shootingPattern {
return func(e *enemy) { return func(e body) {
if int(g.frame)%10 != 0 { if int(g.frame)%10 != 0 {
return return
} }
@ -225,8 +240,8 @@ func shootStraightDown(g *game) shootingPattern {
speed: rl.Vector2{X: 0, Y: 5}, speed: rl.Vector2{X: 0, Y: 5},
size: 12, size: 12,
dmg: 1, dmg: 1,
enemy: true, owner: e,
pos: e.pos, pos: e.Pos(),
}) })
} }
} }
@ -288,7 +303,7 @@ func shootStraightDown(g *game) shootingPattern {
func (e *enemy) checkHit(g *game) (bool, *bullet, int) { func (e *enemy) checkHit(g *game) (bool, *bullet, int) {
for index, bullet := range g.bullets { for index, bullet := range g.bullets {
playerBullet := !bullet.enemy _, playerBullet := bullet.owner.(*player)
if !playerBullet { if !playerBullet {
continue continue
} }
@ -306,6 +321,16 @@ func (g *game) killEnemy(index int) {
g.enemies = g.enemies[:len(g.enemies)-1] g.enemies = g.enemies[:len(g.enemies)-1]
} }
func (e *enemy) deleteBullets(g *game) {
for i := 0; i < len(g.bullets); i++ {
enemy, isEnemyBullet := g.bullets[i].owner.(*enemy)
if isEnemyBullet && enemy == e {
g.removeBullet(i)
i--
}
}
}
func (e *enemy) update(g *game) { func (e *enemy) update(g *game) {
if e.health <= 0 { if e.health <= 0 {
@ -321,19 +346,30 @@ func (e *enemy) update(g *game) {
} }
if hit, bullet, idx := e.checkHit(g); hit { if hit, bullet, idx := e.checkHit(g); hit {
g.score += 273 g.score += 273
e.health -= bullet.dmg e.health -= bullet.dmg
if bullet.onHit != nil {
bullet.onHit(e)
}
g.removeBullet(idx) g.removeBullet(idx)
enemyColor = rl.White enemyColor = rl.White
g.backgroundColor = rl.NewColor(20, 20, 20, 255) g.backgroundColor = rl.NewColor(20, 20, 20, 255)
if e.health <= 0 {
e.deleteBullets(g)
return
}
} }
rl.DrawCircleV(e.pos, e.hitBoxRadius, enemyColor) rl.DrawCircleV(e.pos, e.hitBoxRadius, enemyColor)
} }
func (g *game) fullClear() bool { func (g *game) fullClear() bool {
for _, e := range g.waves[g.currentWave].enemies { for _, e := range g.enemies {
if e.health != 0 { if e.health > 0 {
return false return false
} }
} }
@ -370,10 +406,9 @@ func (g *game) addEnemy(e ...*enemy) {
} }
func main() { func main() {
state := &game{ state := &game{
arenaWidth: 450, arenaWidth: 450,
arenaHeight: 700, arenaHeight: 900,
interfaceWidth: 400, interfaceWidth: 400,
gameSpeed: 1, gameSpeed: 1,
backgroundColor: rl.NewColor(0, 0, 0, 100), backgroundColor: rl.NewColor(0, 0, 0, 100),
@ -383,34 +418,36 @@ func main() {
X: float32(state.arenaWidth) / 2, X: float32(state.arenaWidth) / 2,
Y: float32(state.arenaHeight) * 0.8, Y: float32(state.arenaHeight) * 0.8,
}, },
moveSpeed: 4, direction: rl.Vector2{X: 0, Y: -1},
moveSpeed: 400,
focusSpeedDecrease: 0.5, focusSpeedDecrease: 0.5,
bulletMoveSpeed: 6, bulletMoveSpeed: 6,
bulletSize: 9, bulletSize: 9,
hitBoxRadius: 5, hitBoxRadius: 5,
shoot: snipe(state),
} }
var arena = []plane{ // var arena = []plane{
{ // {
normal: rl.Vector2{X: 0, Y: -1}, // normal: rl.Vector2{X: 0, Y: -1},
pos: rl.Vector2{X: 1, Y: 0}, // pos: rl.Vector2{X: 1, Y: 0},
}, // },
{ // {
normal: rl.Vector2{X: -1, Y: 0}, // normal: rl.Vector2{X: -1, Y: 0},
pos: rl.Vector2{X: float32(state.arenaWidth), Y: 0}, // pos: rl.Vector2{X: float32(state.arenaWidth), Y: 0},
}, // },
{ // {
normal: rl.Vector2{X: 0, Y: 1}, // normal: rl.Vector2{X: 0, Y: 1},
pos: rl.Vector2{X: 0, Y: float32(state.arenaHeight)}, // pos: rl.Vector2{X: 0, Y: float32(state.arenaHeight)},
}, // },
{ // {
normal: rl.Vector2{X: 1, Y: 0}, // normal: rl.Vector2{X: 1, Y: 0},
pos: rl.Vector2{X: 0, Y: 1}, // pos: rl.Vector2{X: 0, Y: 1},
}, // },
} // }
state.walls = arena // state.walls = arena
// rl.SetTraceLog(rl.LogWarning | rl.LogDebug) rl.SetTraceLog(rl.LogWarning | rl.LogDebug)
rl.SetConfigFlags(rl.FlagMsaa4xHint) rl.SetConfigFlags(rl.FlagMsaa4xHint)
rl.InitWindow(state.arenaWidth+state.interfaceWidth, state.arenaHeight, "danmaku") rl.InitWindow(state.arenaWidth+state.interfaceWidth, state.arenaHeight, "danmaku")
@ -425,7 +462,13 @@ func main() {
// state.arenaHeight, // state.arenaHeight,
// ) // )
// descentAndSine := jjjjjj shader_path := path.Join("shaders", "pixelized.glsl")
shader := rl.LoadShader("", shader_path)
// timeShaderLocation := rl.GetShaderLocation(shader, "time")
// target := rl.LoadRenderTexture(
// state.arenaWidth+state.interfaceWidth,
// state.arenaHeight,
// )
state.waves = []*wave{ state.waves = []*wave{
{ {
@ -444,7 +487,7 @@ func main() {
move: sineHorizonalPattern(state, 0), move: sineHorizonalPattern(state, 0),
}, },
}.MovementPattern(state), }.MovementPattern(state),
shoot: burstShootAtPlayer(state, &player, 0.1, 4), shoot: burstShootAtPlayer(state, &player, 0.1, 400),
}, },
{ {
pos: rl.Vector2{X: 200, Y: -20}, pos: rl.Vector2{X: 200, Y: -20},
@ -463,7 +506,7 @@ func main() {
move: sineHorizonalPattern(state, 1), move: sineHorizonalPattern(state, 1),
}, },
}.MovementPattern(state), }.MovementPattern(state),
shoot: burstShootAtPlayer(state, &player, 0.1, 4), shoot: burstShootAtPlayer(state, &player, 0.1, 400),
}, },
}, },
}, },
@ -483,7 +526,7 @@ func main() {
move: sineHorizonalPattern(state, 0), move: sineHorizonalPattern(state, 0),
}, },
}.MovementPattern(state), }.MovementPattern(state),
shoot: bulletExplosion(state, 1, 40, 2, 11), shoot: bulletExplosion(state, 1, 40, 300, 11),
}, },
}, },
}, },
@ -502,7 +545,7 @@ func main() {
move: sineHorizonalPattern(state, 0), move: sineHorizonalPattern(state, 0),
}, },
}.MovementPattern(state), }.MovementPattern(state),
shoot: bulletExplosion(state, 1, 20, 2, 11), shoot: bulletExplosion(state, 1, 20, 300, 11),
}, },
{ {
pos: rl.Vector2{X: 100, Y: 100}, health: 100, pos: rl.Vector2{X: 100, Y: 100}, health: 100,
@ -516,7 +559,7 @@ func main() {
move: sineHorizonalPattern(state, 0), move: sineHorizonalPattern(state, 0),
}, },
}.MovementPattern(state), }.MovementPattern(state),
shoot: burstShootAtPlayer(state, &player, 0.2, 4), shoot: burstShootAtPlayer(state, &player, 0.2, 400),
}, },
{ {
pos: rl.Vector2{X: 50, Y: 250}, pos: rl.Vector2{X: 50, Y: 250},
@ -531,7 +574,7 @@ func main() {
move: sineHorizonalPattern(state, 0), move: sineHorizonalPattern(state, 0),
}, },
}.MovementPattern(state), }.MovementPattern(state),
shoot: bulletExplosion(state, 1, 20, 2, 11), shoot: bulletExplosion(state, 1, 20, 300, 11),
// shoot: shootStraightDown(state), // shoot: shootStraightDown(state),
}, },
}, },
@ -541,8 +584,11 @@ func main() {
currectScore := 0 currectScore := 0
state.addEnemy(state.waves[0].enemies...) state.addEnemy(state.waves[0].enemies...)
spawner := starsBackground(state)
for ; !rl.WindowShouldClose(); state.frame += state.gameSpeed { for ; !rl.WindowShouldClose(); state.frame += state.gameSpeed {
rl.BeginDrawing() rl.BeginDrawing()
rl.BeginShaderMode(shader)
// rl.BeginTextureMode(target) // rl.BeginTextureMode(target)
rl.ClearBackground(state.backgroundColor) rl.ClearBackground(state.backgroundColor)
@ -559,9 +605,8 @@ func main() {
enemiesTotalLifeRemaining := 0 enemiesTotalLifeRemaining := 0
for i := 0; i < len(state.enemies); i++ { for i := 0; i < len(state.enemies); i++ {
state.enemies[i].update(state) state.enemies[i].update(state)
enemiesTotalLifeRemaining += state.enemies[i].health enemiesTotalLifeRemaining += max(state.enemies[i].health, 0)
} }
for i := 0; i < len(state.bullets); i++ { for i := 0; i < len(state.bullets); i++ {
state.bullets[i].update(state, i) state.bullets[i].update(state, i)
} }
@ -571,38 +616,14 @@ func main() {
rl.NewColor(0, 33, 59, 255), rl.NewColor(0, 33, 59, 255),
) )
spawner.update(state)
if player.focusMode { if player.focusMode {
state.gameSpeed = 0.3 state.gameSpeed = 0.3
} else { } else {
state.gameSpeed = 1 state.gameSpeed = 1
} }
// rl.EndTextureMode()
// { // shaders
// if rl.IsKeyPressed(rl.KeyF2) {
// shader = rl.LoadShader("", shader_path)
// fmt.Println("reloaded shader")
// }
//
// rl.SetShaderValue(
// shader, timeShaderLocation, []float32{float32(rl.GetTime())},
// rl.ShaderUniformFloat,
// )
// rl.BeginShaderMode(shader)
// // NOTE: Render texture must be y-flipped due to default
// // OpenGL coordinates (left-bottom)
// rl.DrawTextureRec(
// target.Texture,
// rl.NewRectangle(
// 0, 0, float32(target.Texture.Width), float32(-target.Texture.Height),
// ),
// rl.NewVector2(0, 0), rl.White,
// )
//
// rl.EndShaderMode()
// }
{ // UI { // UI
currectScore += (state.score - currectScore) / 11 currectScore += (state.score - currectScore) / 11
rl.DrawText( rl.DrawText(
@ -639,7 +660,9 @@ func main() {
rl.DrawFPS(0, 0) rl.DrawFPS(0, 0)
} }
rl.EndShaderMode()
rl.EndDrawing() rl.EndDrawing()
} }
rl.CloseWindow() rl.CloseWindow()

186
player.go
View file

@ -1,9 +1,36 @@
package main package main
import ( import (
"fmt"
rl "github.com/gen2brain/raylib-go/raylib" rl "github.com/gen2brain/raylib-go/raylib"
) )
type player struct {
pos rl.Vector2
speed rl.Vector2
direction rl.Vector2
moveSpeed float32
bulletMoveSpeed float32
hitBoxRadius float32
shoot shootingPattern
bulletSize float32
focusMode bool
focusSpeedDecrease float32
}
func (p *player) Pos() rl.Vector2 {
return p.pos
}
func (p *player) SetPos(x rl.Vector2) {
p.pos = x
}
func (p *player) Direction() rl.Vector2 {
return p.direction
}
func (p *player) move(g *game) { func (p *player) move(g *game) {
var moveSpeed float32 var moveSpeed float32
@ -34,7 +61,7 @@ func (p *player) move(g *game) {
p.speed = rl.Vector2Scale(p.speed, moveSpeed) p.speed = rl.Vector2Scale(p.speed, moveSpeed)
} }
result := rl.Vector2Add(p.pos, p.speed) result := rl.Vector2Add(p.pos, rl.Vector2Scale(p.speed, rl.GetFrameTime()))
if result.Y-p.hitBoxRadius < 0 || result.Y+p.hitBoxRadius > float32(g.arenaHeight) { if result.Y-p.hitBoxRadius < 0 || result.Y+p.hitBoxRadius > float32(g.arenaHeight) {
p.speed.Y = 0 p.speed.Y = 0
@ -43,38 +70,39 @@ func (p *player) move(g *game) {
p.speed.X = 0 p.speed.X = 0
} }
p.pos = rl.Vector2Add(p.pos, p.speed) p.pos = rl.Vector2Add(p.pos, rl.Vector2Scale(p.speed, rl.GetFrameTime()))
} }
func (p *player) shoot(g *game) { // func (p *player) shoot(g *game) {
if p.focusMode { // if p.focusMode {
return // return
} // }
//
if int(g.frame)%3 != 0 { // if int(g.frame)%3 != 0 {
return // return
} // }
//
if rl.IsMouseButtonDown(rl.MouseLeftButton) { // if rl.IsMouseButtonDown(rl.MouseLeftButton) {
mouse := rl.GetMousePosition() // mouse := rl.GetMousePosition()
direction := rl.Vector2Subtract(mouse, p.pos) // direction := rl.Vector2Subtract(mouse, p.pos)
direction = rl.Vector2Add(direction, p.speed) // direction = rl.Vector2Add(direction, p.speed)
direction = rl.Vector2Normalize(direction) // direction = rl.Vector2Normalize(direction)
direction = rl.Vector2Scale(direction, p.bulletMoveSpeed) // direction = rl.Vector2Scale(direction, p.bulletMoveSpeed)
//
g.bullets = append(g.bullets, &bullet{ // g.bullets = append(g.bullets, &bullet{
pos: p.pos, // pos: p.pos,
size: p.bulletSize, // size: p.bulletSize,
speed: direction, // speed: direction,
dmg: 1, // dmg: 1,
enemy: false, // enemy: false,
}) // })
} // }
} // }
func (p *player) checkHit(g *game) { func (p *player) checkHit(g *game) {
for _, bullet := range g.bullets { for _, bullet := range g.bullets {
if !bullet.enemy { _, playerBullet := bullet.owner.(*player)
if playerBullet {
continue continue
} }
distance := rl.Vector2Distance(p.pos, bullet.pos) - bullet.size distance := rl.Vector2Distance(p.pos, bullet.pos) - bullet.size
@ -96,7 +124,9 @@ func (p *player) update(g *game) {
p.move(g) p.move(g)
p.shoot(g) if !p.focusMode && p.shoot != nil {
p.shoot(p)
}
p.checkHit(g) p.checkHit(g)
@ -112,6 +142,102 @@ func (p *player) update(g *game) {
inverted = rl.Vector2Negate(inverted) inverted = rl.Vector2Negate(inverted)
inverted = rl.Vector2Normalize(inverted) inverted = rl.Vector2Normalize(inverted)
inverted = rl.Vector2Scale(inverted, 2000) inverted = rl.Vector2Scale(inverted, 2000)
rl.DrawLineV(p.pos, rl.Vector2Add(mouse, inverted), rl.NewColor(255, 0, 0, 100)) rl.DrawLineEx(p.pos, rl.Vector2Add(mouse, inverted), 3, rl.NewColor(255, 0, 0, 100))
}
func tripleFire(g *game) shootingPattern {
t := newTimer(second * 0.05)
return func(b body) {
if !t.isTimeout() {
t.tick(g)
return
}
t.reset()
if rl.IsMouseButtonDown(rl.MouseLeftButton) {
g.bullets = append(g.bullets, &bullet{
pos: b.Pos(),
size: 9,
speed: rl.Vector2Scale(
rl.Mat2MultiplyVector2(rl.Mat2Radians(0.3), b.Direction()),
600,
),
dmg: 1,
owner: b,
})
g.bullets = append(g.bullets, &bullet{
pos: b.Pos(),
size: 9,
speed: rl.Vector2Scale(
rl.Mat2MultiplyVector2(rl.Mat2Radians(0), b.Direction()),
600,
),
dmg: 1,
owner: b,
})
g.bullets = append(g.bullets, &bullet{
pos: b.Pos(),
size: 9,
speed: rl.Vector2Scale(
rl.Mat2MultiplyVector2(rl.Mat2Radians(-0.3), b.Direction()),
600,
),
dmg: 1,
owner: b,
})
}
// rl.matrix
}
}
func snipe(g *game) shootingPattern {
t := newTimer(1)
hits := 0
return func(b body) {
p, ok := b.(*player)
if !ok {
panic(b)
}
if !t.isTimeout() {
t.tick(g)
return
}
if !rl.IsMouseButtonPressed(rl.MouseLeftButton) {
return
}
t.reset()
mouse := rl.GetMousePosition()
direction := rl.Vector2Subtract(mouse, p.pos)
direction = rl.Vector2Add(direction, rl.Vector2Scale(p.speed, rl.GetFrameTime()*g.gameSpeed))
direction = rl.Vector2Normalize(direction)
direction = rl.Vector2Scale(direction, p.bulletMoveSpeed*700)
g.bullets = append(g.bullets, &bullet{
pos: b.Pos(),
size: p.bulletSize,
speed: direction,
dmg: 10 * hits,
owner: b,
onHit: func(b body) {
hits += 2
fmt.Println("hit!", hits)
},
onDestroy: func() {
hits--
hits = max(hits, 0)
fmt.Println("hit!", hits)
},
})
}
} }