From fdacb476812643372f44b42f0d3dba497ea64504 Mon Sep 17 00:00:00 2001 From: silva guimaraes Date: Sun, 23 Jul 2023 00:19:54 -0300 Subject: [PATCH 01/10] resolver clipping --- main.go | 108 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 33 deletions(-) diff --git a/main.go b/main.go index 0d1faa3..a3ad6d2 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "fmt" "math" + "strconv" rl "github.com/gen2brain/raylib-go/raylib" ) @@ -16,11 +17,13 @@ const ( ) type game struct { - screenWidth int32 - screenHeight int32 + arenaWidth int32 + arenaHeight int32 + interfaceWidth int32 time int enemies []*enemy bullets []*bullet + score int } type bullet struct { @@ -33,9 +36,11 @@ type bullet struct { type player struct { pos rl.Vector2 + speed rl.Vector2 moveSpeed float32 bulletMoveSpeed float32 hitBoxRadius float32 + bulletSize float32 } type enemy struct { @@ -48,7 +53,7 @@ type enemy struct { func (g game) insideArena(v rl.Vector2) bool { return v.X >= 0 && v.Y >= 0 && - v.Y <= float32(g.screenHeight) && v.X <= float32(g.screenWidth) + v.Y <= float32(g.arenaHeight) && v.X <= float32(g.arenaWidth) } func (g *game) removeBullet(index int) { @@ -71,8 +76,6 @@ func (e *enemy) shoot(g *game) { if g.time % 15 != 0 { return } - - g.bullets = append(g.bullets, &bullet{ speed: rl.Vector2{X: 0, Y: 10}, size: 4, @@ -148,13 +151,17 @@ func (g *game) killEnemy(index int) { func (e *enemy) update(g *game, index int) { + enemyColor := rl.Blue + if e.movePattern != nil { e.pos = e.movePattern(e) } if hit, bullet, idx := e.checkHit(g); hit { + g.score += 273 e.health -= bullet.dmg g.removeBullet(idx) + enemyColor = rl.White } if e.health <= 0 { @@ -164,30 +171,54 @@ func (e *enemy) update(g *game, index int) { e.shoot(g) - rl.DrawCircleV(e.pos, 5, rl.Blue) + rl.DrawCircleV(e.pos, e.hitBoxRadius, enemyColor) } -func (p *player) move() { - if rl.IsKeyDown(rl.KeyW) { p.pos.Y -= p.moveSpeed } - if rl.IsKeyDown(rl.KeyS) { p.pos.Y += p.moveSpeed } - if rl.IsKeyDown(rl.KeyA) { p.pos.X -= p.moveSpeed } - if rl.IsKeyDown(rl.KeyD) { p.pos.X += p.moveSpeed } +func (p *player) move(g *game) { + p.speed = rl.Vector2{X: 0, Y: 0} + + if rl.IsKeyDown(rl.KeyW) { p.speed.Y -= 1 } + if rl.IsKeyDown(rl.KeyS) { p.speed.Y += 1 } + if rl.IsKeyDown(rl.KeyA) { p.speed.X -= 1 } + if rl.IsKeyDown(rl.KeyD) { p.speed.X += 1 } + + if !(p.speed.X == 0 && p.speed.Y == 0) { + // jogador se move mais rapido na diagonal caso o contrario + p.speed = rl.Vector2Normalize(p.speed) + p.speed = rl.Vector2Scale(p.speed, p.moveSpeed) + } + + result := rl.Vector2Add(p.pos, p.speed) + + if result.Y - p.hitBoxRadius < 0 || + result.Y + p.hitBoxRadius > float32(g.arenaHeight) { + p.speed.Y = 0 + } + if result.X - p.hitBoxRadius < 0 || + result.X + p.hitBoxRadius > float32(g.arenaWidth) { + p.speed.X = 0 + } + + p.pos = rl.Vector2Add(p.pos, p.speed) } func (p *player) shoot(g *game){ - if g.time % 10 != 0 { + if g.time % 5 != 0 { return } if rl.IsMouseButtonDown(rl.MouseLeftButton) { - // não leva em consideração a velocidade do jogador + // (mal) leva em consideração a velocidade do jogador mouse := rl.GetMousePosition() direction := rl.Vector2Subtract(mouse, p.pos) + direction = rl.Vector2Add(direction, p.speed) direction = rl.Vector2Normalize(direction) + direction = rl.Vector2Scale(direction, p.bulletMoveSpeed) + g.bullets = append(g.bullets, &bullet{ pos: p.pos, - size: 2, - speed: rl.Vector2Scale(direction, p.bulletMoveSpeed), + size: p.bulletSize, + speed: direction, dmg: 1, enemy: false, }) @@ -210,7 +241,7 @@ func (p *player) checkHit(g *game) { func (p *player) update(g *game) { - p.move() + p.move(g) p.shoot(g) @@ -231,56 +262,60 @@ func (p *player) update(g *game) { func main() { - state := &game{screenWidth: 450, screenHeight: 700} + state := &game{arenaWidth: 450, arenaHeight: 700, interfaceWidth: 300} player := player{ pos: rl.Vector2{X: 100, Y: 100}, moveSpeed: 4, - bulletMoveSpeed: 8, + bulletMoveSpeed: 13, + bulletSize: 8, hitBoxRadius: 5, } rl.SetTraceLog(rl.LogWarning | rl.LogDebug) - rl.InitWindow(state.screenWidth, state.screenHeight, "danmaku") + rl.InitWindow(state.arenaWidth + state.interfaceWidth, state.arenaHeight, "danmaku") rl.SetTargetFPS(60) state.enemies = []*enemy{ { pos: rl.Vector2{X: 200, Y: 200}, - health: 1, - hitBoxRadius: 5, + health: 10, + hitBoxRadius: 10, movePattern: horizonalPattern(state), }, { pos: rl.Vector2{X: 169, Y: 222}, - health: 1, - hitBoxRadius:5, + health: 10, + hitBoxRadius:10, movePattern: horizonalPattern(state), }, { pos: rl.Vector2{X: 400, Y: 400}, - health: 1, - hitBoxRadius:5, + health: 10, + hitBoxRadius:10, // movePattern: circlePattern(state, rl.Vector2{X: 200, Y: 200}), }, { pos: rl.Vector2{X: 200, Y: 200}, - health: 1, - hitBoxRadius:5, + health: 10, + hitBoxRadius:10, // movePattern: circlePattern(state, rl.Vector2{X: 200, Y: 200}), - }} + }, + } + + currectScore := 0 for ; !rl.WindowShouldClose(); state.time += 1 { - rl.BeginDrawing() - rl.ClearBackground(rl.Black) + rl.BeginDrawing() + rl.ClearBackground(rl.Black) - rl.DrawText("danmaku", 20, 20, 20, rl.DarkGray) - rl.DrawLine(18, 42, state.screenWidth-18, 42, rl.Black) + rl.DrawText("danmaku babe bullet shoot shoot", 20, 20, 20, rl.DarkGray) + rl.DrawLine(18, 42, state.arenaWidth-18, 42, rl.Black) rl.DrawFPS(0, 0) player.update(state) - for i := range state.enemies { + for i := 0; i < len(state.enemies); i++ { state.enemies[i].update(state, i) } @@ -288,6 +323,13 @@ func main() { state.bullets[i].update(state, i) } + rl.DrawRectangle( + state.arenaWidth, 0, state.interfaceWidth, state.arenaHeight, + rl.NewColor(0, 33, 59, 255), + ) + currectScore += (state.score - currectScore) / 11 + rl.DrawText(strconv.Itoa(currectScore), state.arenaWidth, 0, 50, rl.White) + rl.EndDrawing() } From 1ddc892c70a53c6337cf8531f0a69ffbb9c0beb9 Mon Sep 17 00:00:00 2001 From: silva guimaraes Date: Sun, 23 Jul 2023 13:57:02 -0300 Subject: [PATCH 02/10] =?UTF-8?q?implementar=20padro=CC=83es=20de=20tiro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 186 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 122 insertions(+), 64 deletions(-) diff --git a/main.go b/main.go index a3ad6d2..3b56283 100644 --- a/main.go +++ b/main.go @@ -2,25 +2,24 @@ package main import ( "fmt" - "math" "strconv" rl "github.com/gen2brain/raylib-go/raylib" ) -type movementPattern int -type shootingPattern int +type movementPattern func(*enemy)rl.Vector2 +type shootingPattern func(*enemy) +type bulletMovementPattern func(*bullet)rl.Vector2 -const ( - horizontal movementPattern = iota - circular movementPattern = iota -) +type hazard interface { // inimigos e projéteis + Pos() rl.Vector2 +} type game struct { arenaWidth int32 arenaHeight int32 interfaceWidth int32 - time int + frame int enemies []*enemy bullets []*bullet score int @@ -46,9 +45,10 @@ type player struct { type enemy struct { pos rl.Vector2 health int - movePattern func(*enemy)rl.Vector2 - shootPattern func() + move movementPattern + shoot shootingPattern hitBoxRadius float32 + bulletMoveSpeed float32 } func (g game) insideArena(v rl.Vector2) bool { @@ -72,25 +72,66 @@ func (b *bullet) update(g *game, index int) { rl.DrawCircleV(b.pos, b.size, rl.Yellow) } -func (e *enemy) shoot(g *game) { - if g.time % 15 != 0 { - return + +func burstShootAtPlayer(g *game, p *player) shootingPattern { + flag := true + return func(e *enemy) { + if g.frame % 100 == 0 { + flag = !flag + } + + if !flag { + return + } + + if g.frame % 2 == 0 { + return + } + + direction := rl.Vector2Subtract(p.pos, e.pos) + direction = rl.Vector2Normalize(direction) + direction = rl.Vector2Scale(direction, e.bulletMoveSpeed) + + g.bullets = append(g.bullets, &bullet{ + speed: direction, + size: 12, + dmg: 1, + enemy: true, + pos: e.pos, + }) } - g.bullets = append(g.bullets, &bullet{ - speed: rl.Vector2{X: 0, Y: 10}, - size: 4, - dmg: 1, - enemy: true, - pos: e.pos, - }) } -func horizonalPattern(g *game) (func(*enemy)rl.Vector2) { +func shootStraightDown(g *game) shootingPattern { + return func(e *enemy) { + if g.frame % 10 != 0 { + return + } + g.bullets = append(g.bullets, &bullet{ + speed: rl.Vector2{X: 0, Y: 5}, + size: 12, + dmg: 1, + enemy: true, + pos: e.pos, + }) + } +} + +func shootStill() movementPattern { + return func(e *enemy) rl.Vector2 { + e.shoot(e) + return e.pos + } +} + +func horizonalPattern(g *game) movementPattern { direction := rl.Vector2{X: 4, Y: 0} return func(e *enemy) rl.Vector2 { result := rl.Vector2Add(direction, e.pos) + e.shoot(e) + if !g.insideArena(result) { direction = rl.Vector2Negate(direction) } @@ -98,31 +139,43 @@ func horizonalPattern(g *game) (func(*enemy)rl.Vector2) { } } -func circlePattern(g *game, center rl.Vector2) (func(*enemy)rl.Vector2) { +// func aimPlayerPattern(g *game, p *player) movementPattern { +// } - t := float64(0.5) +func foobarPattern(g *game) movementPattern { + + pos := rl.Vector2{} + state := 0 + wait := 0 return func(e *enemy) rl.Vector2 { - // x' = (x - x₀) * cos(θ) - (y - y₀) * sin(θ) + x₀ - // y' = (x - x₀) * sin(θ) + (y - y₀) * cos(θ) + y₀ - // x' = x * cos(θ) - y * sin(θ) - // y' = x * sin(θ) + y * cos(θ) - - // result := center - // - // result.X = result.X + (e.pos.X - result.X) * float32(math.Cos(t)) - - // (e.pos.Y - result.Y) * float32(math.Sin(t)) - // - // result.Y = result.Y + (e.pos.Y - result.Y) * float32(math.Sin(t)) + - // (e.pos.Y - result.Y) * float32(math.Cos(t)) - - result := center - result.X = result.X * float32(math.Cos(t)) - result.Y * float32(math.Sin(t)) - result.Y = result.X * float32(math.Sin(t)) - result.Y * float32(math.Cos(t)) - - t += .08 - return result + switch state { + case 0: // init + pos.X = e.pos.X + state = 1 + return pos + case 1: // descer + pos.Y += 1 + if pos.Y >= 100 { state = 2; wait = 50 } + return pos + case 2: // atirar por um tempo + e.shoot(e) + wait -= 1 + if wait <= 0 { state = 3; wait = 60 } + return pos + case 3: // wait + wait -= 1 + if wait <= 0 { state = 4 } + return pos + case 4: // retornar + pos.Y -= 3 + if pos.Y - e.hitBoxRadius < 0 { + e.health = 0 + } + return pos + } + panic(state) } } @@ -134,7 +187,6 @@ func (e *enemy) checkHit(g *game) (bool, *bullet, int) { continue } distance := rl.Vector2Distance(e.pos, bullet.pos) - bullet.size - // fmt.Println(distance) if distance < e.hitBoxRadius { return true, bullet, index @@ -153,8 +205,8 @@ func (e *enemy) update(g *game, index int) { enemyColor := rl.Blue - if e.movePattern != nil { - e.pos = e.movePattern(e) + if e.move != nil { + e.pos = e.move(e) } if hit, bullet, idx := e.checkHit(g); hit { @@ -169,8 +221,6 @@ func (e *enemy) update(g *game, index int) { return } - e.shoot(g) - rl.DrawCircleV(e.pos, e.hitBoxRadius, enemyColor) } @@ -203,12 +253,11 @@ func (p *player) move(g *game) { } func (p *player) shoot(g *game){ - if g.time % 5 != 0 { + if g.frame % 5 != 0 { return } if rl.IsMouseButtonDown(rl.MouseLeftButton) { - // (mal) leva em consideração a velocidade do jogador mouse := rl.GetMousePosition() direction := rl.Vector2Subtract(mouse, p.pos) direction = rl.Vector2Add(direction, p.speed) @@ -281,31 +330,40 @@ func main() { pos: rl.Vector2{X: 200, Y: 200}, health: 10, hitBoxRadius: 10, - movePattern: horizonalPattern(state), - }, - { - pos: rl.Vector2{X: 169, Y: 222}, - health: 10, - hitBoxRadius:10, - movePattern: horizonalPattern(state), - }, - { - pos: rl.Vector2{X: 400, Y: 400}, - health: 10, - hitBoxRadius:10, - // movePattern: circlePattern(state, rl.Vector2{X: 200, Y: 200}), + bulletMoveSpeed: 6, + move: horizonalPattern(state), + // shoot: shootStraightDown(state), + shoot: burstShootAtPlayer(state, &player), }, + // { + // pos: rl.Vector2{X: 169, Y: 222}, + // health: 10, + // hitBoxRadius:10, + // bulletMoveSpeed: 6, + // move: horizonalPattern(state), + // shoot: shootStraightDown(state), + // }, + // { + // pos: rl.Vector2{X: 400, Y: 400}, + // health: 10, + // hitBoxRadius:10, + // bulletMoveSpeed: 6, + // move: foobarPattern(state), + // shoot: shootStraightDown(state), + // }, { pos: rl.Vector2{X: 200, Y: 200}, health: 10, hitBoxRadius:10, - // movePattern: circlePattern(state, rl.Vector2{X: 200, Y: 200}), + bulletMoveSpeed: 6, + move: shootStill(), + shoot: shootStraightDown(state), }, } currectScore := 0 - for ; !rl.WindowShouldClose(); state.time += 1 { + for ; !rl.WindowShouldClose(); state.frame += 1 { rl.BeginDrawing() rl.ClearBackground(rl.Black) From 7fdf53b7ad38b83c776cf50097ccad8217da49f1 Mon Sep 17 00:00:00 2001 From: silva guimaraes Date: Sun, 23 Jul 2023 14:21:36 -0300 Subject: [PATCH 03/10] remover bulletMoveSpeed de inimigos --- main.go | 103 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 76 insertions(+), 27 deletions(-) diff --git a/main.go b/main.go index 3b56283..412ec92 100644 --- a/main.go +++ b/main.go @@ -40,6 +40,8 @@ type player struct { bulletMoveSpeed float32 hitBoxRadius float32 bulletSize float32 + focusMode bool + focusSpeedDecrease float32 } type enemy struct { @@ -48,7 +50,6 @@ type enemy struct { move movementPattern shoot shootingPattern hitBoxRadius float32 - bulletMoveSpeed float32 } func (g game) insideArena(v rl.Vector2) bool { @@ -72,8 +73,29 @@ func (b *bullet) update(g *game, index int) { rl.DrawCircleV(b.pos, b.size, rl.Yellow) } +func ShootAtPlayer(g *game, p *player, rate int, +bulletMoveSpeed float32) shootingPattern { + return func(e *enemy) { + if g.frame % rate != 0 { + return + } + direction := rl.Vector2Subtract(p.pos, e.pos) + direction = rl.Vector2Normalize(direction) + direction = rl.Vector2Scale(direction, bulletMoveSpeed) -func burstShootAtPlayer(g *game, p *player) shootingPattern { + g.bullets = append(g.bullets, &bullet{ + speed: direction, + size: 12, + dmg: 1, + enemy: true, + pos: e.pos, + }) + } +} + + +func burstShootAtPlayer(g *game, p *player, +rate int, bulletMoveSpeed float32) shootingPattern { flag := true return func(e *enemy) { if g.frame % 100 == 0 { @@ -84,13 +106,13 @@ func burstShootAtPlayer(g *game, p *player) shootingPattern { return } - if g.frame % 2 == 0 { + if g.frame % rate != 0 { return } direction := rl.Vector2Subtract(p.pos, e.pos) direction = rl.Vector2Normalize(direction) - direction = rl.Vector2Scale(direction, e.bulletMoveSpeed) + direction = rl.Vector2Scale(direction, bulletMoveSpeed) g.bullets = append(g.bullets, &bullet{ speed: direction, @@ -225,6 +247,14 @@ func (e *enemy) update(g *game, index int) { } func (p *player) move(g *game) { + + var moveSpeed float32 + if p.focusMode { + moveSpeed = p.moveSpeed * p.focusSpeedDecrease + } else { + moveSpeed = p.moveSpeed + } + p.speed = rl.Vector2{X: 0, Y: 0} if rl.IsKeyDown(rl.KeyW) { p.speed.Y -= 1 } @@ -235,7 +265,7 @@ func (p *player) move(g *game) { if !(p.speed.X == 0 && p.speed.Y == 0) { // jogador se move mais rapido na diagonal caso o contrario p.speed = rl.Vector2Normalize(p.speed) - p.speed = rl.Vector2Scale(p.speed, p.moveSpeed) + p.speed = rl.Vector2Scale(p.speed, moveSpeed) } result := rl.Vector2Add(p.pos, p.speed) @@ -253,6 +283,10 @@ func (p *player) move(g *game) { } func (p *player) shoot(g *game){ + if p.focusMode { + return + } + if g.frame % 5 != 0 { return } @@ -288,8 +322,19 @@ func (p *player) checkHit(g *game) { } } +func (p *player) checkFocus() { + // raylib não entende keybindings customizadas através do xmodmap? + if rl.IsKeyDown(rl.KeyLeftShift) || rl.IsKeyDown(rl.KeyRightShift) { + p.focusMode = true + } else { + p.focusMode = false + } +} + func (p *player) update(g *game) { + p.checkFocus() + p.move(g) p.shoot(g) @@ -299,6 +344,9 @@ func (p *player) update(g *game) { // hitbox rl.DrawCircleV(p.pos, p.hitBoxRadius, rl.Red) + if p.focusMode { + return + } // mira mouse := rl.GetMousePosition() inverted := rl.Vector2Subtract(p.pos, mouse) @@ -314,8 +362,12 @@ func main() { state := &game{arenaWidth: 450, arenaHeight: 700, interfaceWidth: 300} player := player{ - pos: rl.Vector2{X: 100, Y: 100}, + pos: rl.Vector2{ + X: float32(state.arenaWidth) / 2, + Y: float32(state.arenaHeight) * 0.8, + }, moveSpeed: 4, + focusSpeedDecrease: 0.5, bulletMoveSpeed: 13, bulletSize: 8, hitBoxRadius: 5, @@ -328,21 +380,18 @@ func main() { state.enemies = []*enemy{ { pos: rl.Vector2{X: 200, Y: 200}, - health: 10, - hitBoxRadius: 10, - bulletMoveSpeed: 6, + health: 100, + hitBoxRadius: 20, move: horizonalPattern(state), - // shoot: shootStraightDown(state), - shoot: burstShootAtPlayer(state, &player), + shoot: burstShootAtPlayer(state, &player, 8, 4), + }, + { + pos: rl.Vector2{X: 169, Y: 285}, + health: 10, + hitBoxRadius:10, + move: horizonalPattern(state), + shoot: ShootAtPlayer(state, &player, 16, 3), }, - // { - // pos: rl.Vector2{X: 169, Y: 222}, - // health: 10, - // hitBoxRadius:10, - // bulletMoveSpeed: 6, - // move: horizonalPattern(state), - // shoot: shootStraightDown(state), - // }, // { // pos: rl.Vector2{X: 400, Y: 400}, // health: 10, @@ -351,14 +400,14 @@ func main() { // move: foobarPattern(state), // shoot: shootStraightDown(state), // }, - { - pos: rl.Vector2{X: 200, Y: 200}, - health: 10, - hitBoxRadius:10, - bulletMoveSpeed: 6, - move: shootStill(), - shoot: shootStraightDown(state), - }, + // { + // pos: rl.Vector2{X: 200, Y: 200}, + // health: 10, + // hitBoxRadius:10, + // bulletMoveSpeed: 6, + // move: shootStill(), + // shoot: shootStraightDown(state), + // }, } currectScore := 0 From c90fd3d14a122372f37b5604078f3a6d381e2179 Mon Sep 17 00:00:00 2001 From: silva guimaraes Date: Sun, 23 Jul 2023 21:10:39 -0300 Subject: [PATCH 04/10] =?UTF-8?q?implementar=20explosa=CC=83o=20de=20balas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 76 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/main.go b/main.go index 412ec92..a6cb2e3 100644 --- a/main.go +++ b/main.go @@ -2,13 +2,17 @@ package main import ( "fmt" + "math" "strconv" rl "github.com/gen2brain/raylib-go/raylib" ) +// diz para um inimigo como ele deve se mover type movementPattern func(*enemy)rl.Vector2 +// diz para um inimigo em que condições atirar. acionado pelo movementPattern type shootingPattern func(*enemy) +// diz para uma bala como ela deve se mover. type bulletMovementPattern func(*bullet)rl.Vector2 type hazard interface { // inimigos e projéteis @@ -73,6 +77,36 @@ func (b *bullet) update(g *game, index int) { rl.DrawCircleV(b.pos, b.size, rl.Yellow) } +func bulletExplosion(g *game, rate, amount int, bulletSpeed, size float32) shootingPattern { + return func(e *enemy) { + if g.frame % rate != 0 { + return + } + + // radius := e.hitBoxRadius + + var bullets []*bullet + + for i := 0; i < amount; i++ { + angle := 2.0 * math.Pi * float64(i) / float64(amount) + cos := math.Cos(angle) + sin := math.Sin(angle) + direction := rl.Vector2{X: float32(cos), Y: float32(sin)} + direction = rl.Vector2Scale(direction, bulletSpeed) + + bullets = append(bullets, &bullet{ + speed: direction, + size: size, + dmg: 1, + enemy: true, + pos: e.pos, + }) + } + + g.bullets = append(g.bullets, bullets...) + } +} + func ShootAtPlayer(g *game, p *player, rate int, bulletMoveSpeed float32) shootingPattern { return func(e *enemy) { @@ -93,7 +127,6 @@ bulletMoveSpeed float32) shootingPattern { } } - func burstShootAtPlayer(g *game, p *player, rate int, bulletMoveSpeed float32) shootingPattern { flag := true @@ -287,7 +320,7 @@ func (p *player) shoot(g *game){ return } - if g.frame % 5 != 0 { + if g.frame % 3 != 0 { return } @@ -368,8 +401,8 @@ func main() { }, moveSpeed: 4, focusSpeedDecrease: 0.5, - bulletMoveSpeed: 13, - bulletSize: 8, + bulletMoveSpeed: 6, + bulletSize: 9, hitBoxRadius: 5, } @@ -383,31 +416,22 @@ func main() { health: 100, hitBoxRadius: 20, move: horizonalPattern(state), - shoot: burstShootAtPlayer(state, &player, 8, 4), + shoot: bulletExplosion(state, 60, 20, 2, 11), }, { - pos: rl.Vector2{X: 169, Y: 285}, - health: 10, - hitBoxRadius:10, + pos: rl.Vector2{X: 100, Y: 100}, + health: 100, + hitBoxRadius: 20, move: horizonalPattern(state), - shoot: ShootAtPlayer(state, &player, 16, 3), + shoot: burstShootAtPlayer(state, &player, 20, 4), + }, + { + pos: rl.Vector2{X: 50, Y: 250}, + health: 100, + hitBoxRadius: 20, + move: horizonalPattern(state), + shoot: bulletExplosion(state, 60, 20, 2, 11), }, - // { - // pos: rl.Vector2{X: 400, Y: 400}, - // health: 10, - // hitBoxRadius:10, - // bulletMoveSpeed: 6, - // move: foobarPattern(state), - // shoot: shootStraightDown(state), - // }, - // { - // pos: rl.Vector2{X: 200, Y: 200}, - // health: 10, - // hitBoxRadius:10, - // bulletMoveSpeed: 6, - // move: shootStill(), - // shoot: shootStraightDown(state), - // }, } currectScore := 0 @@ -437,6 +461,8 @@ func main() { currectScore += (state.score - currectScore) / 11 rl.DrawText(strconv.Itoa(currectScore), state.arenaWidth, 0, 50, rl.White) + rl.DrawText(strconv.Itoa(len(state.bullets)), state.arenaWidth, 50, 50, rl.White) + rl.EndDrawing() } From 8159246e2cd330b6c3ae065ec5cf46a8279182de Mon Sep 17 00:00:00 2001 From: silva guimaraes Date: Mon, 24 Jul 2023 14:03:30 -0300 Subject: [PATCH 05/10] poder slow motion --- main.go | 110 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 57 insertions(+), 53 deletions(-) diff --git a/main.go b/main.go index a6cb2e3..c88fd50 100644 --- a/main.go +++ b/main.go @@ -23,10 +23,11 @@ type game struct { arenaWidth int32 arenaHeight int32 interfaceWidth int32 - frame int + frame float32 enemies []*enemy bullets []*bullet score int + gameSpeed float32 // 1 = velocidade normal } type bullet struct { @@ -67,7 +68,7 @@ func (g *game) removeBullet(index int) { } func (b *bullet) update(g *game, index int) { - b.pos = rl.Vector2Add(b.pos, b.speed) + b.pos = rl.Vector2Add(b.pos, rl.Vector2Scale(b.speed, g.gameSpeed)) if !g.insideArena(b.pos) { g.removeBullet(index) @@ -79,7 +80,7 @@ func (b *bullet) update(g *game, index int) { func bulletExplosion(g *game, rate, amount int, bulletSpeed, size float32) shootingPattern { return func(e *enemy) { - if g.frame % rate != 0 { + if int(g.frame) % rate != 0 { return } @@ -110,7 +111,7 @@ func bulletExplosion(g *game, rate, amount int, bulletSpeed, size float32) shoot func ShootAtPlayer(g *game, p *player, rate int, bulletMoveSpeed float32) shootingPattern { return func(e *enemy) { - if g.frame % rate != 0 { + if int(g.frame) % rate != 0 { return } direction := rl.Vector2Subtract(p.pos, e.pos) @@ -131,7 +132,7 @@ func burstShootAtPlayer(g *game, p *player, rate int, bulletMoveSpeed float32) shootingPattern { flag := true return func(e *enemy) { - if g.frame % 100 == 0 { + if int(g.frame) % 100 == 0 { flag = !flag } @@ -139,7 +140,7 @@ rate int, bulletMoveSpeed float32) shootingPattern { return } - if g.frame % rate != 0 { + if int(g.frame) % rate != 0 { return } @@ -159,7 +160,7 @@ rate int, bulletMoveSpeed float32) shootingPattern { func shootStraightDown(g *game) shootingPattern { return func(e *enemy) { - if g.frame % 10 != 0 { + if int(g.frame) % 10 != 0 { return } g.bullets = append(g.bullets, &bullet{ @@ -175,7 +176,7 @@ func shootStraightDown(g *game) shootingPattern { func shootStill() movementPattern { return func(e *enemy) rl.Vector2 { e.shoot(e) - return e.pos + return rl.Vector2{X: 0, Y: 0} } } @@ -183,57 +184,53 @@ func horizonalPattern(g *game) movementPattern { direction := rl.Vector2{X: 4, Y: 0} return func(e *enemy) rl.Vector2 { - result := rl.Vector2Add(direction, e.pos) - e.shoot(e) + result := rl.Vector2Add(direction, e.pos) if !g.insideArena(result) { direction = rl.Vector2Negate(direction) } - return result + return direction } } -// func aimPlayerPattern(g *game, p *player) movementPattern { +// func foobarPattern(g *game) movementPattern { +// +// pos := rl.Vector2{} +// state := 0 +// wait := 0 +// +// return func(e *enemy) rl.Vector2 { +// +// switch state { +// case 0: // init +// pos.X = e.pos.X +// state = 1 +// return pos +// case 1: // descer +// pos.Y += 1 +// if pos.Y >= 100 { state = 2; wait = 50 } +// return pos +// case 2: // atirar por um tempo +// e.shoot(e) +// wait -= 1 +// if wait <= 0 { state = 3; wait = 60 } +// return pos +// case 3: // wait +// wait -= 1 +// if wait <= 0 { state = 4 } +// return pos +// case 4: // retornar +// pos.Y -= 3 +// if pos.Y - e.hitBoxRadius < 0 { +// e.health = 0 +// } +// return pos +// } +// panic(state) +// } // } -func foobarPattern(g *game) movementPattern { - - pos := rl.Vector2{} - state := 0 - wait := 0 - - return func(e *enemy) rl.Vector2 { - - switch state { - case 0: // init - pos.X = e.pos.X - state = 1 - return pos - case 1: // descer - pos.Y += 1 - if pos.Y >= 100 { state = 2; wait = 50 } - return pos - case 2: // atirar por um tempo - e.shoot(e) - wait -= 1 - if wait <= 0 { state = 3; wait = 60 } - return pos - case 3: // wait - wait -= 1 - if wait <= 0 { state = 4 } - return pos - case 4: // retornar - pos.Y -= 3 - if pos.Y - e.hitBoxRadius < 0 { - e.health = 0 - } - return pos - } - panic(state) - } -} - func (e *enemy) checkHit(g *game) (bool, *bullet, int) { for index, bullet := range g.bullets { @@ -261,7 +258,8 @@ func (e *enemy) update(g *game, index int) { enemyColor := rl.Blue if e.move != nil { - e.pos = e.move(e) + e.pos = rl.Vector2Add(rl.Vector2Scale(e.move(e), g.gameSpeed), e.pos) + // e.pos = e.move(e) } if hit, bullet, idx := e.checkHit(g); hit { @@ -320,7 +318,7 @@ func (p *player) shoot(g *game){ return } - if g.frame % 3 != 0 { + if int(g.frame) % 3 != 0 { return } @@ -392,7 +390,7 @@ func (p *player) update(g *game) { func main() { - state := &game{arenaWidth: 450, arenaHeight: 700, interfaceWidth: 300} + state := &game{arenaWidth: 450, arenaHeight: 700, interfaceWidth: 300, gameSpeed: 1} player := player{ pos: rl.Vector2{ @@ -436,7 +434,7 @@ func main() { currectScore := 0 - for ; !rl.WindowShouldClose(); state.frame += 1 { + for ; !rl.WindowShouldClose(); state.frame += state.gameSpeed { rl.BeginDrawing() rl.ClearBackground(rl.Black) @@ -463,6 +461,12 @@ func main() { rl.DrawText(strconv.Itoa(len(state.bullets)), state.arenaWidth, 50, 50, rl.White) + if player.focusMode { + state.gameSpeed = 0.3 + } else { + state.gameSpeed = 1 + } + rl.EndDrawing() } From df56b0237ee21a8d9ca7a9a476344510c828d223 Mon Sep 17 00:00:00 2001 From: silva guimaraes Date: Thu, 27 Jul 2023 12:36:01 -0300 Subject: [PATCH 06/10] suporte para shaders --- main.go | 84 ++++++++++++++++++++++++++++++++++++++++++++++-------- windows.sh | 3 ++ 2 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 windows.sh diff --git a/main.go b/main.go index c88fd50..3519f71 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "fmt" "math" + // "path" "strconv" rl "github.com/gen2brain/raylib-go/raylib" @@ -28,6 +29,7 @@ type game struct { bullets []*bullet score int gameSpeed float32 // 1 = velocidade normal + backgroundColor rl.Color } type bullet struct { @@ -267,6 +269,7 @@ func (e *enemy) update(g *game, index int) { e.health -= bullet.dmg g.removeBullet(idx) enemyColor = rl.White + g.backgroundColor = rl.NewColor(20, 20, 20, 255) } if e.health <= 0 { @@ -348,7 +351,7 @@ func (p *player) checkHit(g *game) { // fmt.Println(distance) if distance < p.hitBoxRadius { - fmt.Println("hit!") + // fmt.Println("hit!") } } } @@ -390,8 +393,13 @@ func (p *player) update(g *game) { func main() { - state := &game{arenaWidth: 450, arenaHeight: 700, interfaceWidth: 300, gameSpeed: 1} - + state := &game{ + arenaWidth: 450, + arenaHeight: 700, + interfaceWidth: 300, + gameSpeed: 1, + backgroundColor: rl.NewColor(0, 0, 0, 100), + } player := player{ pos: rl.Vector2{ X: float32(state.arenaWidth) / 2, @@ -404,10 +412,21 @@ func main() { hitBoxRadius: 5, } - rl.SetTraceLog(rl.LogWarning | rl.LogDebug) + // rl.SetTraceLog(rl.LogWarning | rl.LogDebug) + + rl.SetConfigFlags(rl.FlagMsaa4xHint) rl.InitWindow(state.arenaWidth + state.interfaceWidth, state.arenaHeight, "danmaku") rl.SetTargetFPS(60) + + // shader_path := path.Join("shaders", "trails.glsl") + // shader := rl.LoadShader("", shader_path) + // timeShaderLocation := rl.GetShaderLocation(shader, "time") + // target := rl.LoadRenderTexture( + // state.arenaWidth + state.interfaceWidth, + // state.arenaHeight, + // ) + state.enemies = []*enemy{ { pos: rl.Vector2{X: 200, Y: 200}, @@ -436,11 +455,10 @@ func main() { for ; !rl.WindowShouldClose(); state.frame += state.gameSpeed { rl.BeginDrawing() - rl.ClearBackground(rl.Black) - rl.DrawText("danmaku babe bullet shoot shoot", 20, 20, 20, rl.DarkGray) - rl.DrawLine(18, 42, state.arenaWidth-18, 42, rl.Black) - rl.DrawFPS(0, 0) + // rl.BeginTextureMode(target) + rl.ClearBackground(state.backgroundColor) + state.backgroundColor = rl.Black player.update(state) @@ -456,10 +474,6 @@ func main() { state.arenaWidth, 0, state.interfaceWidth, state.arenaHeight, rl.NewColor(0, 33, 59, 255), ) - currectScore += (state.score - currectScore) / 11 - rl.DrawText(strconv.Itoa(currectScore), state.arenaWidth, 0, 50, rl.White) - - rl.DrawText(strconv.Itoa(len(state.bullets)), state.arenaWidth, 50, 50, rl.White) if player.focusMode { state.gameSpeed = 0.3 @@ -467,6 +481,52 @@ func main() { 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 + currectScore += (state.score - currectScore) / 11 + rl.DrawText(strconv.Itoa(currectScore), state.arenaWidth, 0, 50, rl.White) + + rl.DrawText( + strconv.Itoa(len(state.bullets)), state.arenaWidth, 50, 50, rl.White, + ) + + rl.DrawText( + fmt.Sprintf("%f", state.frame), state.arenaWidth, 100, 50, rl.White, + ) + rl.DrawText( + fmt.Sprintf("%d", int(state.frame)), state.arenaWidth, 150, 50, rl.White, + ) + rl.DrawText("danmaku babe bullet shoot shoot", 20, 20, 20, rl.DarkGray) + rl.DrawLine(18, 42, state.arenaWidth-18, 42, rl.Black) + rl.DrawFPS(0, 0) + } + + rl.EndDrawing() } diff --git a/windows.sh b/windows.sh new file mode 100644 index 0000000..f3ece73 --- /dev/null +++ b/windows.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc GOOS=windows GOARCH=amd64 CGO_LDFLAGS="-static-libgcc -static -lpthread" go build From 9a0383488df76d663e9179f4bda488401eded6d9 Mon Sep 17 00:00:00 2001 From: silva guimaraes Date: Sat, 25 Jan 2025 23:28:00 -0300 Subject: [PATCH 07/10] timer --- main.go | 925 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 525 insertions(+), 400 deletions(-) diff --git a/main.go b/main.go index 3519f71..2bd9be0 100644 --- a/main.go +++ b/main.go @@ -3,530 +3,655 @@ package main import ( "fmt" "math" - // "path" "strconv" rl "github.com/gen2brain/raylib-go/raylib" ) // diz para um inimigo como ele deve se mover -type movementPattern func(*enemy)rl.Vector2 +type movementPattern func(*enemy) rl.Vector2 + // diz para um inimigo em que condições atirar. acionado pelo movementPattern type shootingPattern func(*enemy) + // diz para uma bala como ela deve se mover. -type bulletMovementPattern func(*bullet)rl.Vector2 +type bulletMovementPattern func(*bullet) rl.Vector2 type hazard interface { // inimigos e projéteis - Pos() rl.Vector2 + Pos() rl.Vector2 } type game struct { - arenaWidth int32 - arenaHeight int32 - interfaceWidth int32 - frame float32 - enemies []*enemy - bullets []*bullet - score int - gameSpeed float32 // 1 = velocidade normal - backgroundColor rl.Color + arenaWidth int32 + arenaHeight int32 + interfaceWidth int32 + frame float32 + enemies []*enemy + waves []*wave + currentWave int + bullets []*bullet + score int + gameSpeed float32 // 1 = velocidade normal + backgroundColor rl.Color } type bullet struct { - pos rl.Vector2 - speed rl.Vector2 - size float32 - dmg int - enemy bool + pos rl.Vector2 + speed rl.Vector2 + size float32 + dmg int + enemy bool } type player struct { - pos rl.Vector2 - speed rl.Vector2 - moveSpeed float32 - bulletMoveSpeed float32 - hitBoxRadius float32 - bulletSize float32 - focusMode bool - focusSpeedDecrease float32 + pos rl.Vector2 + speed rl.Vector2 + moveSpeed float32 + bulletMoveSpeed float32 + hitBoxRadius float32 + bulletSize float32 + focusMode bool + focusSpeedDecrease float32 } type enemy struct { - pos rl.Vector2 - health int - move movementPattern - shoot shootingPattern - hitBoxRadius float32 + pos rl.Vector2 + health int + move movementPattern + shoot shootingPattern + hitBoxRadius float32 +} + +type wave struct { + enemies []*enemy + entrance movementPattern } func (g game) insideArena(v rl.Vector2) bool { - return v.X >= 0 && v.Y >= 0 && - v.Y <= float32(g.arenaHeight) && v.X <= float32(g.arenaWidth) + return v.X >= 0 && v.Y >= 0 && + v.Y <= float32(g.arenaHeight) && v.X <= float32(g.arenaWidth) } func (g *game) removeBullet(index int) { - g.bullets[index] = g.bullets[len(g.bullets)-1] - g.bullets = g.bullets[:len(g.bullets)-1] + g.bullets[index] = g.bullets[len(g.bullets)-1] + g.bullets = g.bullets[:len(g.bullets)-1] } 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, g.gameSpeed)) - if !g.insideArena(b.pos) { - g.removeBullet(index) - return - } + if !g.insideArena(b.pos) { + g.removeBullet(index) + return + } - 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 { - return func(e *enemy) { - if int(g.frame) % rate != 0 { - return - } + t := newTimer(second) + return func(e *enemy) { - // radius := e.hitBoxRadius + t.tick(g) + if !t.isTimeout() { + return + } + t.reset() - var bullets []*bullet + var bullets []*bullet - for i := 0; i < amount; i++ { - angle := 2.0 * math.Pi * float64(i) / float64(amount) - cos := math.Cos(angle) - sin := math.Sin(angle) - direction := rl.Vector2{X: float32(cos), Y: float32(sin)} - direction = rl.Vector2Scale(direction, bulletSpeed) + for i := 0; i < amount; i++ { + angle := 2.0 * math.Pi * float64(i) / float64(amount) + cos := math.Cos(angle) + sin := math.Sin(angle) + direction := rl.Vector2{X: float32(cos), Y: float32(sin)} + direction = rl.Vector2Scale(direction, bulletSpeed) - bullets = append(bullets, &bullet{ - speed: direction, - size: size, - dmg: 1, - enemy: true, - pos: e.pos, - }) - } + bullets = append(bullets, &bullet{ + speed: direction, + size: size, + dmg: 1, + enemy: true, + pos: e.pos, + }) + } - g.bullets = append(g.bullets, bullets...) - } + g.bullets = append(g.bullets, bullets...) + } } -func ShootAtPlayer(g *game, p *player, rate int, -bulletMoveSpeed float32) shootingPattern { - return func(e *enemy) { - if int(g.frame) % rate != 0 { - return - } - direction := rl.Vector2Subtract(p.pos, e.pos) - direction = rl.Vector2Normalize(direction) - direction = rl.Vector2Scale(direction, bulletMoveSpeed) +func ShootAtPlayer(g *game, p *player, rate int, + bulletMoveSpeed float32) shootingPattern { + return func(e *enemy) { + if int(g.frame)%rate != 0 { + return + } + direction := rl.Vector2Subtract(p.pos, e.pos) + direction = rl.Vector2Normalize(direction) + direction = rl.Vector2Scale(direction, bulletMoveSpeed) - g.bullets = append(g.bullets, &bullet{ - speed: direction, - size: 12, - dmg: 1, - enemy: true, - pos: e.pos, - }) - } + g.bullets = append(g.bullets, &bullet{ + speed: direction, + size: 12, + dmg: 1, + enemy: true, + pos: e.pos, + }) + } } -func burstShootAtPlayer(g *game, p *player, -rate int, bulletMoveSpeed float32) shootingPattern { - flag := true - return func(e *enemy) { - if int(g.frame) % 100 == 0 { - flag = !flag - } +type timer struct { + time, ttl float32 + start float64 +} - if !flag { - return - } +func (t *timer) tick(g *game) { + t.time += rl.GetFrameTime() * g.gameSpeed +} - if int(g.frame) % rate != 0 { - return - } +func (t *timer) isTimeout() bool { + return t.time >= t.ttl +} - direction := rl.Vector2Subtract(p.pos, e.pos) - direction = rl.Vector2Normalize(direction) - direction = rl.Vector2Scale(direction, bulletMoveSpeed) +func (t *timer) reset() { + t.start = float64(t.time) + t.time = 0 +} - g.bullets = append(g.bullets, &bullet{ - speed: direction, - size: 12, - dmg: 1, - enemy: true, - pos: e.pos, - }) - } +func newTimer(duration float32) *timer { + return &timer { + time: 0, + ttl: duration, + start: rl.GetTime(), + } +} + +var second float32 = 1 + +func burstShootAtPlayer(g *game, p *player, rate float32, bulletMoveSpeed float32) shootingPattern { + flag := true + off := newTimer(second) + on := newTimer(second*rate) + return func(e *enemy) { + + fmt.Printf("\r %f %f", rl.GetTime(), rl.GetFrameTime()) + + off.tick(g) + + if off.isTimeout() { + flag = !flag + fmt.Println() + fmt.Println(off) + off.reset() + fmt.Println(off) + fmt.Println() + } + + if !flag { + return + } + + on.tick(g) + if !on.isTimeout() { + return + } + on.reset() + + direction := rl.Vector2Subtract(p.pos, e.pos) + direction = rl.Vector2Normalize(direction) + direction = rl.Vector2Scale(direction, bulletMoveSpeed) + + g.bullets = append(g.bullets, &bullet{ + speed: direction, + size: 12, + dmg: 1, + enemy: true, + pos: e.pos, + }) + } } func shootStraightDown(g *game) shootingPattern { - return func(e *enemy) { - if int(g.frame) % 10 != 0 { - return - } - g.bullets = append(g.bullets, &bullet{ - speed: rl.Vector2{X: 0, Y: 5}, - size: 12, - dmg: 1, - enemy: true, - pos: e.pos, - }) - } + return func(e *enemy) { + if int(g.frame)%10 != 0 { + return + } + g.bullets = append(g.bullets, &bullet{ + speed: rl.Vector2{X: 0, Y: 5}, + size: 12, + dmg: 1, + enemy: true, + pos: e.pos, + }) + } } func shootStill() movementPattern { - return func(e *enemy) rl.Vector2 { - e.shoot(e) - return rl.Vector2{X: 0, Y: 0} - } + return func(e *enemy) rl.Vector2 { + e.shoot(e) + return rl.Vector2{X: 0, Y: 0} + } } func horizonalPattern(g *game) movementPattern { - direction := rl.Vector2{X: 4, Y: 0} + direction := rl.Vector2{X: 4, Y: 0} + + return func(e *enemy) rl.Vector2 { + e.shoot(e) + + result := rl.Vector2Add(direction, e.pos) + if !g.insideArena(result) { + direction = rl.Vector2Negate(direction) + } + return direction + } +} + +func sineHorizonalPattern(g *game) movementPattern { + direction := rl.Vector2{X: 4, Y: 0} + + return func(e *enemy) rl.Vector2 { + if e.shoot != nil { + e.shoot(e) + } + + + result := rl.Vector2Add(direction, e.pos) + if !g.insideArena(result) { + direction = rl.Vector2Negate(direction) + } + + sine := rl.Vector2{ + X: 0, + Y: float32(math.Sin(float64(g.frame*0.04))*2), + } + + return rl.Vector2Add(sine, direction) + } +} + +func foobarPattern(g *game) movementPattern { + + pos := rl.Vector2{} + state := 0 + wait := 0 return func(e *enemy) rl.Vector2 { - e.shoot(e) - result := rl.Vector2Add(direction, e.pos) - if !g.insideArena(result) { - direction = rl.Vector2Negate(direction) + switch state { + case 0: // init + pos.X = e.pos.X + state = 1 + return pos + case 1: // descer + pos.Y += 1 + if pos.Y >= 100 { state = 2; wait = 50 } + return pos + case 2: // atirar por um tempo + e.shoot(e) + wait -= 1 + if wait <= 0 { state = 3; wait = 60 } + return pos + case 3: // wait + wait -= 1 + if wait <= 0 { state = 4 } + return pos + case 4: // retornar + pos.Y -= 3 + if pos.Y - e.hitBoxRadius < 0 { + e.health = 0 + } + return pos } - return direction + panic(state) } } -// func foobarPattern(g *game) movementPattern { -// -// pos := rl.Vector2{} -// state := 0 -// wait := 0 -// -// return func(e *enemy) rl.Vector2 { -// -// switch state { -// case 0: // init -// pos.X = e.pos.X -// state = 1 -// return pos -// case 1: // descer -// pos.Y += 1 -// if pos.Y >= 100 { state = 2; wait = 50 } -// return pos -// case 2: // atirar por um tempo -// e.shoot(e) -// wait -= 1 -// if wait <= 0 { state = 3; wait = 60 } -// return pos -// case 3: // wait -// wait -= 1 -// if wait <= 0 { state = 4 } -// return pos -// case 4: // retornar -// pos.Y -= 3 -// if pos.Y - e.hitBoxRadius < 0 { -// e.health = 0 -// } -// return pos -// } -// panic(state) -// } -// } - func (e *enemy) checkHit(g *game) (bool, *bullet, int) { - for index, bullet := range g.bullets { + for index, bullet := range g.bullets { - playerBullet := !bullet.enemy - if !playerBullet { - continue - } - distance := rl.Vector2Distance(e.pos, bullet.pos) - bullet.size + playerBullet := !bullet.enemy + if !playerBullet { + continue + } + distance := rl.Vector2Distance(e.pos, bullet.pos) - bullet.size - if distance < e.hitBoxRadius { - return true, bullet, index - } - } - return false, nil, 0 + if distance < e.hitBoxRadius { + return true, bullet, index + } + } + return false, nil, 0 } func (g *game) killEnemy(index int) { - g.enemies[index] = g.enemies[len(g.enemies)-1] - g.enemies = g.enemies[:len(g.enemies)-1] + g.enemies[index] = g.enemies[len(g.enemies)-1] + g.enemies = g.enemies[:len(g.enemies)-1] } +func (e *enemy) update(g *game) { -func (e *enemy) update(g *game, index int) { + if e.health <= 0 { + return + } - enemyColor := rl.Blue + enemyColor := rl.Blue - if e.move != nil { - e.pos = rl.Vector2Add(rl.Vector2Scale(e.move(e), g.gameSpeed), e.pos) - // e.pos = e.move(e) - } + if e.move != nil { + e.pos = rl.Vector2Add(rl.Vector2Scale(e.move(e), g.gameSpeed), e.pos) + // e.pos = e.move(e) + } - if hit, bullet, idx := e.checkHit(g); hit { - g.score += 273 - e.health -= bullet.dmg - g.removeBullet(idx) - enemyColor = rl.White - g.backgroundColor = rl.NewColor(20, 20, 20, 255) - } + if hit, bullet, idx := e.checkHit(g); hit { + g.score += 273 + e.health -= bullet.dmg + g.removeBullet(idx) + enemyColor = rl.White + g.backgroundColor = rl.NewColor(20, 20, 20, 255) + } - if e.health <= 0 { - g.killEnemy(index) - return - } - rl.DrawCircleV(e.pos, e.hitBoxRadius, enemyColor) + rl.DrawCircleV(e.pos, e.hitBoxRadius, enemyColor) } func (p *player) move(g *game) { - var moveSpeed float32 - if p.focusMode { - moveSpeed = p.moveSpeed * p.focusSpeedDecrease - } else { - moveSpeed = p.moveSpeed - } + var moveSpeed float32 + if p.focusMode { + moveSpeed = p.moveSpeed * p.focusSpeedDecrease + } else { + moveSpeed = p.moveSpeed + } - p.speed = rl.Vector2{X: 0, Y: 0} + p.speed = rl.Vector2{X: 0, Y: 0} - if rl.IsKeyDown(rl.KeyW) { p.speed.Y -= 1 } - if rl.IsKeyDown(rl.KeyS) { p.speed.Y += 1 } - if rl.IsKeyDown(rl.KeyA) { p.speed.X -= 1 } - if rl.IsKeyDown(rl.KeyD) { p.speed.X += 1 } + if rl.IsKeyDown(rl.KeyW) { + p.speed.Y -= 1 + } + if rl.IsKeyDown(rl.KeyS) { + p.speed.Y += 1 + } + if rl.IsKeyDown(rl.KeyA) { + p.speed.X -= 1 + } + if rl.IsKeyDown(rl.KeyD) { + p.speed.X += 1 + } - if !(p.speed.X == 0 && p.speed.Y == 0) { - // jogador se move mais rapido na diagonal caso o contrario - p.speed = rl.Vector2Normalize(p.speed) - p.speed = rl.Vector2Scale(p.speed, moveSpeed) - } + if !(p.speed.X == 0 && p.speed.Y == 0) { + // jogador se move mais rapido na diagonal caso o contrario + p.speed = rl.Vector2Normalize(p.speed) + p.speed = rl.Vector2Scale(p.speed, moveSpeed) + } - result := rl.Vector2Add(p.pos, p.speed) + result := rl.Vector2Add(p.pos, p.speed) - if result.Y - p.hitBoxRadius < 0 || - result.Y + p.hitBoxRadius > float32(g.arenaHeight) { - p.speed.Y = 0 - } - if result.X - p.hitBoxRadius < 0 || - result.X + p.hitBoxRadius > float32(g.arenaWidth) { - p.speed.X = 0 - } - - p.pos = rl.Vector2Add(p.pos, p.speed) + if result.Y-p.hitBoxRadius < 0 || + result.Y+p.hitBoxRadius > float32(g.arenaHeight) { + p.speed.Y = 0 + } + if result.X-p.hitBoxRadius < 0 || + result.X+p.hitBoxRadius > float32(g.arenaWidth) { + p.speed.X = 0 + } + + p.pos = rl.Vector2Add(p.pos, p.speed) } -func (p *player) shoot(g *game){ - if p.focusMode { - return - } +func (p *player) shoot(g *game) { + if p.focusMode { + return + } - if int(g.frame) % 3 != 0 { - return - } + if int(g.frame)%3 != 0 { + return + } - if rl.IsMouseButtonDown(rl.MouseLeftButton) { - mouse := rl.GetMousePosition() - direction := rl.Vector2Subtract(mouse, p.pos) - direction = rl.Vector2Add(direction, p.speed) - direction = rl.Vector2Normalize(direction) - direction = rl.Vector2Scale(direction, p.bulletMoveSpeed) + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + mouse := rl.GetMousePosition() + direction := rl.Vector2Subtract(mouse, p.pos) + direction = rl.Vector2Add(direction, p.speed) + direction = rl.Vector2Normalize(direction) + direction = rl.Vector2Scale(direction, p.bulletMoveSpeed) - g.bullets = append(g.bullets, &bullet{ - pos: p.pos, - size: p.bulletSize, - speed: direction, - dmg: 1, - enemy: false, - }) - } + g.bullets = append(g.bullets, &bullet{ + pos: p.pos, + size: p.bulletSize, + speed: direction, + dmg: 1, + enemy: false, + }) + } } func (p *player) checkHit(g *game) { - for _, bullet := range g.bullets { - if !bullet.enemy { - continue - } - distance := rl.Vector2Distance(p.pos, bullet.pos) - bullet.size - // fmt.Println(distance) + for _, bullet := range g.bullets { + if !bullet.enemy { + continue + } + distance := rl.Vector2Distance(p.pos, bullet.pos) - bullet.size + // fmt.Println(distance) - if distance < p.hitBoxRadius { - // fmt.Println("hit!") - } - } + if distance < p.hitBoxRadius { + // fmt.Println("hit!") + } + } } func (p *player) checkFocus() { - // raylib não entende keybindings customizadas através do xmodmap? - if rl.IsKeyDown(rl.KeyLeftShift) || rl.IsKeyDown(rl.KeyRightShift) { - p.focusMode = true - } else { - p.focusMode = false - } + // raylib não entende keybindings customizadas através do xmodmap? + if rl.IsKeyDown(rl.KeyLeftShift) || rl.IsKeyDown(rl.KeyRightShift) { + p.focusMode = true + } else { + p.focusMode = false + } } func (p *player) update(g *game) { - p.checkFocus() + p.checkFocus() - p.move(g) + p.move(g) - p.shoot(g) + p.shoot(g) - p.checkHit(g) + p.checkHit(g) - // hitbox - rl.DrawCircleV(p.pos, p.hitBoxRadius, rl.Red) + // hitbox + rl.DrawCircleV(p.pos, p.hitBoxRadius, rl.Red) - if p.focusMode { - return - } - // mira - mouse := rl.GetMousePosition() - inverted := rl.Vector2Subtract(p.pos, mouse) - inverted = rl.Vector2Negate(inverted) - inverted = rl.Vector2Normalize(inverted) - inverted = rl.Vector2Scale(inverted, 2000) - rl.DrawLineV(p.pos, rl.Vector2Add(mouse, inverted), rl.NewColor(255, 0, 0, 100)) + if p.focusMode { + return + } + // mira + mouse := rl.GetMousePosition() + inverted := rl.Vector2Subtract(p.pos, mouse) + inverted = rl.Vector2Negate(inverted) + inverted = rl.Vector2Normalize(inverted) + inverted = rl.Vector2Scale(inverted, 2000) + rl.DrawLineV(p.pos, rl.Vector2Add(mouse, inverted), rl.NewColor(255, 0, 0, 100)) } +func (g *game) fullClear() bool { + for _, e := range g.waves[g.currentWave].enemies { + if e.health != 0 { + return false + } + } + return true +} + func main() { - state := &game{ - arenaWidth: 450, - arenaHeight: 700, - interfaceWidth: 300, - gameSpeed: 1, - backgroundColor: rl.NewColor(0, 0, 0, 100), - } - player := player{ - pos: rl.Vector2{ - X: float32(state.arenaWidth) / 2, - Y: float32(state.arenaHeight) * 0.8, - }, - moveSpeed: 4, - focusSpeedDecrease: 0.5, - bulletMoveSpeed: 6, - bulletSize: 9, - hitBoxRadius: 5, - } + state := &game{ + arenaWidth: 450, + arenaHeight: 700, + interfaceWidth: 300, + gameSpeed: 1, + backgroundColor: rl.NewColor(0, 0, 0, 100), + } + player := player{ + pos: rl.Vector2{ + X: float32(state.arenaWidth) / 2, + Y: float32(state.arenaHeight) * 0.8, + }, + moveSpeed: 4, + focusSpeedDecrease: 0.5, + bulletMoveSpeed: 6, + bulletSize: 9, + hitBoxRadius: 5, + } - // rl.SetTraceLog(rl.LogWarning | rl.LogDebug) - - rl.SetConfigFlags(rl.FlagMsaa4xHint) - rl.InitWindow(state.arenaWidth + state.interfaceWidth, state.arenaHeight, "danmaku") - rl.SetTargetFPS(60) + // rl.SetTraceLog(rl.LogWarning | rl.LogDebug) + + rl.SetConfigFlags(rl.FlagMsaa4xHint) + rl.InitWindow(state.arenaWidth+state.interfaceWidth, state.arenaHeight, "danmaku") + targetFPS := 120 + rl.SetTargetFPS(int32(targetFPS)) + + // shader_path := path.Join("shaders", "trails.glsl") + // shader := rl.LoadShader("", shader_path) + // timeShaderLocation := rl.GetShaderLocation(shader, "time") + // target := rl.LoadRenderTexture( + // state.arenaWidth + state.interfaceWidth, + // state.arenaHeight, + // ) + + state.waves = []*wave{ + { + enemies: []*enemy{ + { + pos: rl.Vector2{X: 100, Y: 100}, + health: 100, + hitBoxRadius: 20, + move: sineHorizonalPattern(state), + shoot: burstShootAtPlayer(state, &player, 0.1, 4), + }, + }, + }, + { + enemies: []*enemy{ + { + pos: rl.Vector2{X: 100, Y: 100}, + health: 100, + hitBoxRadius: 20, + move: horizonalPattern(state), + shoot: bulletExplosion(state, targetFPS, 20, 2, 11), + }, + }, + }, + { + enemies: []*enemy{ + { + pos: rl.Vector2{X: 200, Y: 200}, + health: 100, + hitBoxRadius: 20, + move: horizonalPattern(state), + shoot: bulletExplosion(state, targetFPS, 20, 2, 11), + }, + { + pos: rl.Vector2{X: 100, Y: 100}, + health: 100, + hitBoxRadius: 20, + move: horizonalPattern(state), + shoot: burstShootAtPlayer(state, &player, 0.2, 4), + }, + { + pos: rl.Vector2{X: 50, Y: 250}, + health: 100, + hitBoxRadius: 20, + move: horizonalPattern(state), + shoot: bulletExplosion(state, targetFPS, 20, 2, 11), + // shoot: shootStraightDown(state), + }, + }, + }, + } + + currectScore := 0 + + for ; !rl.WindowShouldClose(); state.frame += state.gameSpeed { + rl.BeginDrawing() + + // rl.BeginTextureMode(target) + rl.ClearBackground(state.backgroundColor) + state.backgroundColor = rl.Black + + player.update(state) + + if state.fullClear() { + state.currentWave++ + } + + if state.currentWave >= len(state.waves) { + break + } + state.enemies = state.waves[state.currentWave].enemies + for i := 0; i < len(state.enemies); i++ { + state.enemies[i].update(state) + } + + for i := 0; i < len(state.bullets); i++ { + state.bullets[i].update(state, i) + } + + rl.DrawRectangle( + state.arenaWidth, 0, state.interfaceWidth, state.arenaHeight, + rl.NewColor(0, 33, 59, 255), + ) + + if player.focusMode { + state.gameSpeed = 0.3 + } else { + state.gameSpeed = 1 + } - // shader_path := path.Join("shaders", "trails.glsl") - // shader := rl.LoadShader("", shader_path) - // timeShaderLocation := rl.GetShaderLocation(shader, "time") - // target := rl.LoadRenderTexture( - // state.arenaWidth + state.interfaceWidth, - // state.arenaHeight, - // ) + // rl.EndTextureMode() - state.enemies = []*enemy{ - { - pos: rl.Vector2{X: 200, Y: 200}, - health: 100, - hitBoxRadius: 20, - move: horizonalPattern(state), - shoot: bulletExplosion(state, 60, 20, 2, 11), - }, - { - pos: rl.Vector2{X: 100, Y: 100}, - health: 100, - hitBoxRadius: 20, - move: horizonalPattern(state), - shoot: burstShootAtPlayer(state, &player, 20, 4), - }, - { - pos: rl.Vector2{X: 50, Y: 250}, - health: 100, - hitBoxRadius: 20, - move: horizonalPattern(state), - shoot: bulletExplosion(state, 60, 20, 2, 11), - }, - } + // { // 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() + // } - currectScore := 0 + { // UI + currectScore += (state.score - currectScore) / 11 + rl.DrawText(strconv.Itoa(currectScore), state.arenaWidth, 0, 50, rl.White) - for ; !rl.WindowShouldClose(); state.frame += state.gameSpeed { - rl.BeginDrawing() + rl.DrawText( + strconv.Itoa(len(state.bullets)), state.arenaWidth, 50, 50, rl.White, + ) - // rl.BeginTextureMode(target) - rl.ClearBackground(state.backgroundColor) - state.backgroundColor = rl.Black + rl.DrawText( + fmt.Sprintf("%f", state.frame), state.arenaWidth, 100, 50, rl.White, + ) + rl.DrawText( + fmt.Sprintf("%d", int(state.frame)), state.arenaWidth, 150, 50, rl.White, + ) + rl.DrawText("danmaku babe bullet shoot shoot", 20, 20, 20, rl.DarkGray) + rl.DrawLine(18, 42, state.arenaWidth-18, 42, rl.Black) + rl.DrawFPS(0, 0) + } - player.update(state) - - for i := 0; i < len(state.enemies); i++ { - state.enemies[i].update(state, i) - } - - for i := 0; i < len(state.bullets); i++ { - state.bullets[i].update(state, i) - } - - rl.DrawRectangle( - state.arenaWidth, 0, state.interfaceWidth, state.arenaHeight, - rl.NewColor(0, 33, 59, 255), - ) - - if player.focusMode { - state.gameSpeed = 0.3 - } else { - 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 - currectScore += (state.score - currectScore) / 11 - rl.DrawText(strconv.Itoa(currectScore), state.arenaWidth, 0, 50, rl.White) - - rl.DrawText( - strconv.Itoa(len(state.bullets)), state.arenaWidth, 50, 50, rl.White, - ) - - rl.DrawText( - fmt.Sprintf("%f", state.frame), state.arenaWidth, 100, 50, rl.White, - ) - rl.DrawText( - fmt.Sprintf("%d", int(state.frame)), state.arenaWidth, 150, 50, rl.White, - ) - rl.DrawText("danmaku babe bullet shoot shoot", 20, 20, 20, rl.DarkGray) - rl.DrawLine(18, 42, state.arenaWidth-18, 42, rl.Black) - rl.DrawFPS(0, 0) - } - - rl.EndDrawing() } From 277c6d070a65c3fa6e6f6ba88a2743b81fa61073 Mon Sep 17 00:00:00 2001 From: silva guimaraes Date: Tue, 28 Jan 2025 08:22:30 -0300 Subject: [PATCH 08/10] gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ad13d12 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +danmaku +danmaku.exe +shaders/* From a411573a063707b86f0933e805234600ecd88001 Mon Sep 17 00:00:00 2001 From: silva guimaraes Date: Tue, 28 Jan 2025 08:23:02 -0300 Subject: [PATCH 09/10] =?UTF-8?q?organiza=C3=A7=C3=A3o=20de=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ease.go | 21 ++ go.mod | 2 +- main.go | 517 +++++++++++++++++++++----------------------- movementPatterns.go | 138 ++++++++++++ player.go | 117 ++++++++++ 5 files changed, 529 insertions(+), 266 deletions(-) create mode 100644 ease.go create mode 100644 movementPatterns.go create mode 100644 player.go diff --git a/ease.go b/ease.go new file mode 100644 index 0000000..b531fbc --- /dev/null +++ b/ease.go @@ -0,0 +1,21 @@ +package main + +import ( + "math" +) + +func easeInOutCubic(x float32) float32 { + if x < 0.5 { + return 4 * x * x * x + } else { + return 1 - float32(math.Pow(float64(-2*x+2), 3))/2 + } +} + +func lerp(v0, v1, t float32) float32 { + return (1-t)*v0 + t*v1 +} + +func easeInOutSine(x float32) float32 { + return -float32(math.Cos(math.Pi*float64(x))-1) / 2 +} diff --git a/go.mod b/go.mod index 4a29b8c..7fe4ecd 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,5 @@ module danmaku -go 1.20 +go 1.23 require github.com/gen2brain/raylib-go/raylib v0.0.0-20230719211022-1083eace2049 diff --git a/main.go b/main.go index 2bd9be0..5157ded 100644 --- a/main.go +++ b/main.go @@ -8,15 +8,16 @@ import ( rl "github.com/gen2brain/raylib-go/raylib" ) -// diz para um inimigo como ele deve se mover -type movementPattern func(*enemy) rl.Vector2 - // diz para um inimigo em que condições atirar. acionado pelo movementPattern type shootingPattern func(*enemy) // diz para uma bala como ela deve se mover. type bulletMovementPattern func(*bullet) rl.Vector2 +type duration float32 + +const second duration = 1 + type hazard interface { // inimigos e projéteis Pos() rl.Vector2 } @@ -28,6 +29,7 @@ type game struct { frame float32 enemies []*enemy waves []*wave + walls []plane currentWave int bullets []*bullet score int @@ -35,6 +37,11 @@ type game struct { backgroundColor rl.Color } +type plane struct { + normal rl.Vector2 + pos rl.Vector2 +} + type bullet struct { pos rl.Vector2 speed rl.Vector2 @@ -63,10 +70,42 @@ type enemy struct { } type wave struct { + duration *timer enemies []*enemy entrance movementPattern } +type timer struct { + ttl duration + time float32 + start float64 +} + +func (t *timer) tick(g *game) { + t.time += rl.GetFrameTime() * g.gameSpeed +} + +func (t *timer) isTimeout() bool { + return t.time >= float32(t.ttl) +} + +func (t *timer) reset() { + t.start = float64(t.time) + t.time = 0 +} + +func (t *timer) unit() float32 { + return t.time / float32(t.ttl) +} + +func newTimer(duration duration) *timer { + return &timer{ + time: 0, + ttl: duration, + start: rl.GetTime(), + } +} + func (g game) insideArena(v rl.Vector2) bool { return v.X >= 0 && v.Y >= 0 && v.Y <= float32(g.arenaHeight) && v.X <= float32(g.arenaWidth) @@ -89,7 +128,7 @@ func (b *bullet) update(g *game, index int) { } func bulletExplosion(g *game, rate, amount int, bulletSpeed, size float32) shootingPattern { - t := newTimer(second) + t := newTimer(second * duration(rate)) return func(e *enemy) { t.tick(g) @@ -140,51 +179,17 @@ func ShootAtPlayer(g *game, p *player, rate int, } } -type timer struct { - time, ttl float32 - start float64 -} - -func (t *timer) tick(g *game) { - t.time += rl.GetFrameTime() * g.gameSpeed -} - -func (t *timer) isTimeout() bool { - return t.time >= t.ttl -} - -func (t *timer) reset() { - t.start = float64(t.time) - t.time = 0 -} - -func newTimer(duration float32) *timer { - return &timer { - time: 0, - ttl: duration, - start: rl.GetTime(), - } -} - -var second float32 = 1 - func burstShootAtPlayer(g *game, p *player, rate float32, bulletMoveSpeed float32) shootingPattern { flag := true off := newTimer(second) - on := newTimer(second*rate) + on := newTimer(duration(float32(second) * rate)) return func(e *enemy) { - fmt.Printf("\r %f %f", rl.GetTime(), rl.GetFrameTime()) - off.tick(g) if off.isTimeout() { flag = !flag - fmt.Println() - fmt.Println(off) off.reset() - fmt.Println(off) - fmt.Println() } if !flag { @@ -226,86 +231,59 @@ func shootStraightDown(g *game) shootingPattern { } } -func shootStill() movementPattern { - return func(e *enemy) rl.Vector2 { - e.shoot(e) - return rl.Vector2{X: 0, Y: 0} - } -} +// func detectWallCollision(planes []plane, initialPos, direction rl.Vector2) float32 { +// p := initialPos +// w := direction +// var closest = math.Inf(1) +// for _, plane := range planes { +// c := plane.pos +// n := plane.normal +// denominator := rl.Vector2DotProduct(w, n) +// if denominator == 0 { +// continue +// } +// t := rl.Vector2DotProduct(rl.Vector2Subtract(p, c), n) / denominator +// closest = min(float64(t), closest) +// } +// return float32(-closest) +// } -func horizonalPattern(g *game) movementPattern { - direction := rl.Vector2{X: 4, Y: 0} - - return func(e *enemy) rl.Vector2 { - e.shoot(e) - - result := rl.Vector2Add(direction, e.pos) - if !g.insideArena(result) { - direction = rl.Vector2Negate(direction) - } - return direction - } -} - -func sineHorizonalPattern(g *game) movementPattern { - direction := rl.Vector2{X: 4, Y: 0} - - return func(e *enemy) rl.Vector2 { - if e.shoot != nil { - e.shoot(e) - } - - - result := rl.Vector2Add(direction, e.pos) - if !g.insideArena(result) { - direction = rl.Vector2Negate(direction) - } - - sine := rl.Vector2{ - X: 0, - Y: float32(math.Sin(float64(g.frame*0.04))*2), - } - - return rl.Vector2Add(sine, direction) - } -} - -func foobarPattern(g *game) movementPattern { - - pos := rl.Vector2{} - state := 0 - wait := 0 - - return func(e *enemy) rl.Vector2 { - - switch state { - case 0: // init - pos.X = e.pos.X - state = 1 - return pos - case 1: // descer - pos.Y += 1 - if pos.Y >= 100 { state = 2; wait = 50 } - return pos - case 2: // atirar por um tempo - e.shoot(e) - wait -= 1 - if wait <= 0 { state = 3; wait = 60 } - return pos - case 3: // wait - wait -= 1 - if wait <= 0 { state = 4 } - return pos - case 4: // retornar - pos.Y -= 3 - if pos.Y - e.hitBoxRadius < 0 { - e.health = 0 - } - return pos - } - panic(state) - } -} +// func foobarPattern(g *game) movementPattern { +// +// pos := rl.Vector2{} +// state := 0 +// wait := 0 +// +// return func(e *enemy) rl.Vector2 { +// +// switch state { +// case 0: // init +// pos.X = e.pos.X +// state = 1 +// return pos +// case 1: // descer +// pos.Y += 1 +// if pos.Y >= 100 { state = 2; wait = 50 } +// return pos +// case 2: // atirar por um tempo +// e.shoot(e) +// wait -= 1 +// if wait <= 0 { state = 3; wait = 60 } +// return pos +// case 3: // wait +// wait -= 1 +// if wait <= 0 { state = 4 } +// return pos +// case 4: // retornar +// pos.Y -= 3 +// if pos.Y - e.hitBoxRadius < 0 { +// e.health = 0 +// } +// return pos +// } +// panic(state) +// } +// } func (e *enemy) checkHit(g *game) (bool, *bullet, int) { for index, bullet := range g.bullets { @@ -337,7 +315,8 @@ func (e *enemy) update(g *game) { enemyColor := rl.Blue if e.move != nil { - e.pos = rl.Vector2Add(rl.Vector2Scale(e.move(e), g.gameSpeed), e.pos) + // e.pos = rl.Vector2Add(rl.Vector2Scale(e.move(e), g.gameSpeed), e.pos) + e.move(e) // e.pos = e.move(e) } @@ -349,129 +328,9 @@ func (e *enemy) update(g *game) { g.backgroundColor = rl.NewColor(20, 20, 20, 255) } - rl.DrawCircleV(e.pos, e.hitBoxRadius, enemyColor) } -func (p *player) move(g *game) { - - var moveSpeed float32 - if p.focusMode { - moveSpeed = p.moveSpeed * p.focusSpeedDecrease - } else { - moveSpeed = p.moveSpeed - } - - p.speed = rl.Vector2{X: 0, Y: 0} - - if rl.IsKeyDown(rl.KeyW) { - p.speed.Y -= 1 - } - if rl.IsKeyDown(rl.KeyS) { - p.speed.Y += 1 - } - if rl.IsKeyDown(rl.KeyA) { - p.speed.X -= 1 - } - if rl.IsKeyDown(rl.KeyD) { - p.speed.X += 1 - } - - if !(p.speed.X == 0 && p.speed.Y == 0) { - // jogador se move mais rapido na diagonal caso o contrario - p.speed = rl.Vector2Normalize(p.speed) - p.speed = rl.Vector2Scale(p.speed, moveSpeed) - } - - result := rl.Vector2Add(p.pos, p.speed) - - if result.Y-p.hitBoxRadius < 0 || - result.Y+p.hitBoxRadius > float32(g.arenaHeight) { - p.speed.Y = 0 - } - if result.X-p.hitBoxRadius < 0 || - result.X+p.hitBoxRadius > float32(g.arenaWidth) { - p.speed.X = 0 - } - - p.pos = rl.Vector2Add(p.pos, p.speed) -} - -func (p *player) shoot(g *game) { - if p.focusMode { - return - } - - if int(g.frame)%3 != 0 { - return - } - - if rl.IsMouseButtonDown(rl.MouseLeftButton) { - mouse := rl.GetMousePosition() - direction := rl.Vector2Subtract(mouse, p.pos) - direction = rl.Vector2Add(direction, p.speed) - direction = rl.Vector2Normalize(direction) - direction = rl.Vector2Scale(direction, p.bulletMoveSpeed) - - g.bullets = append(g.bullets, &bullet{ - pos: p.pos, - size: p.bulletSize, - speed: direction, - dmg: 1, - enemy: false, - }) - } -} - -func (p *player) checkHit(g *game) { - for _, bullet := range g.bullets { - if !bullet.enemy { - continue - } - distance := rl.Vector2Distance(p.pos, bullet.pos) - bullet.size - // fmt.Println(distance) - - if distance < p.hitBoxRadius { - // fmt.Println("hit!") - } - } -} - -func (p *player) checkFocus() { - // raylib não entende keybindings customizadas através do xmodmap? - if rl.IsKeyDown(rl.KeyLeftShift) || rl.IsKeyDown(rl.KeyRightShift) { - p.focusMode = true - } else { - p.focusMode = false - } -} - -func (p *player) update(g *game) { - - p.checkFocus() - - p.move(g) - - p.shoot(g) - - p.checkHit(g) - - // hitbox - rl.DrawCircleV(p.pos, p.hitBoxRadius, rl.Red) - - if p.focusMode { - return - } - // mira - mouse := rl.GetMousePosition() - inverted := rl.Vector2Subtract(p.pos, mouse) - inverted = rl.Vector2Negate(inverted) - inverted = rl.Vector2Normalize(inverted) - inverted = rl.Vector2Scale(inverted, 2000) - rl.DrawLineV(p.pos, rl.Vector2Add(mouse, inverted), rl.NewColor(255, 0, 0, 100)) - -} - func (g *game) fullClear() bool { for _, e := range g.waves[g.currentWave].enemies { if e.health != 0 { @@ -481,12 +340,41 @@ func (g *game) fullClear() bool { return true } +func (g *game) waveTimeout() bool { + currentWave := g.waves[g.currentWave] + if currentWave.duration == nil { + return false + } + if currentWave.duration.isTimeout() { + return true + } + currentWave.duration.tick(g) + return false +} + +func (g *game) wavesOver() bool { + return g.currentWave == len(g.waves) +} + +func (g *game) nextWave() bool { + g.currentWave++ + if g.wavesOver() { + return false + } + g.addEnemy(g.waves[g.currentWave].enemies...) + return true +} + +func (g *game) addEnemy(e ...*enemy) { + g.enemies = append(g.enemies, e...) +} + func main() { state := &game{ arenaWidth: 450, arenaHeight: 700, - interfaceWidth: 300, + interfaceWidth: 400, gameSpeed: 1, backgroundColor: rl.NewColor(0, 0, 0, 100), } @@ -502,6 +390,26 @@ func main() { hitBoxRadius: 5, } + var arena = []plane{ + { + normal: rl.Vector2{X: 0, Y: -1}, + pos: rl.Vector2{X: 1, Y: 0}, + }, + { + normal: rl.Vector2{X: -1, Y: 0}, + pos: rl.Vector2{X: float32(state.arenaWidth), Y: 0}, + }, + { + normal: rl.Vector2{X: 0, Y: 1}, + pos: rl.Vector2{X: 0, Y: float32(state.arenaHeight)}, + }, + { + normal: rl.Vector2{X: 1, Y: 0}, + pos: rl.Vector2{X: 0, Y: 1}, + }, + } + state.walls = arena + // rl.SetTraceLog(rl.LogWarning | rl.LogDebug) rl.SetConfigFlags(rl.FlagMsaa4xHint) @@ -517,26 +425,65 @@ func main() { // state.arenaHeight, // ) + // descentAndSine := jjjjjj + state.waves = []*wave{ { + duration: newTimer(second * 10), enemies: []*enemy{ { - pos: rl.Vector2{X: 100, Y: 100}, + pos: rl.Vector2{X: 100, Y: -20}, health: 100, hitBoxRadius: 20, - move: sineHorizonalPattern(state), - shoot: burstShootAtPlayer(state, &player, 0.1, 4), + move: statePipeline{ + { + duration: 1.1, + move: sineDescentMove(state, -20, 200, 1), + }, + { + move: sineHorizonalPattern(state, 0), + }, + }.MovementPattern(state), + shoot: burstShootAtPlayer(state, &player, 0.1, 4), + }, + { + pos: rl.Vector2{X: 200, Y: -20}, + health: 100, + hitBoxRadius: 20, + move: statePipeline{ + { + duration: 5, + move: shootStill(), + }, + { + duration: 1.1, + move: descentMove(state, -20, 200, 1), + }, + { + move: sineHorizonalPattern(state, 1), + }, + }.MovementPattern(state), + shoot: burstShootAtPlayer(state, &player, 0.1, 4), }, }, }, { + duration: newTimer(second * 20), enemies: []*enemy{ { pos: rl.Vector2{X: 100, Y: 100}, health: 100, hitBoxRadius: 20, - move: horizonalPattern(state), - shoot: bulletExplosion(state, targetFPS, 20, 2, 11), + move: statePipeline{ + { + duration: 1.1, + move: sineDescentMove(state, -20, 200, 1), + }, + { + move: sineHorizonalPattern(state, 0), + }, + }.MovementPattern(state), + shoot: bulletExplosion(state, 1, 40, 2, 11), }, }, }, @@ -546,22 +493,45 @@ func main() { pos: rl.Vector2{X: 200, Y: 200}, health: 100, hitBoxRadius: 20, - move: horizonalPattern(state), - shoot: bulletExplosion(state, targetFPS, 20, 2, 11), + move: statePipeline{ + { + duration: 1.1, + move: sineDescentMove(state, -20, 200, 1), + }, + { + move: sineHorizonalPattern(state, 0), + }, + }.MovementPattern(state), + shoot: bulletExplosion(state, 1, 20, 2, 11), }, { - pos: rl.Vector2{X: 100, Y: 100}, - health: 100, + pos: rl.Vector2{X: 100, Y: 100}, health: 100, hitBoxRadius: 20, - move: horizonalPattern(state), - shoot: burstShootAtPlayer(state, &player, 0.2, 4), + move: statePipeline{ + { + duration: 1.1, + move: sineDescentMove(state, -20, 200, 1), + }, + { + move: sineHorizonalPattern(state, 0), + }, + }.MovementPattern(state), + shoot: burstShootAtPlayer(state, &player, 0.2, 4), }, { pos: rl.Vector2{X: 50, Y: 250}, health: 100, hitBoxRadius: 20, - move: horizonalPattern(state), - shoot: bulletExplosion(state, targetFPS, 20, 2, 11), + move: statePipeline{ + { + duration: 1.1, + move: sineDescentMove(state, -20, 200, 1), + }, + { + move: sineHorizonalPattern(state, 0), + }, + }.MovementPattern(state), + shoot: bulletExplosion(state, 1, 20, 2, 11), // shoot: shootStraightDown(state), }, }, @@ -569,6 +539,7 @@ func main() { } currectScore := 0 + state.addEnemy(state.waves[0].enemies...) for ; !rl.WindowShouldClose(); state.frame += state.gameSpeed { rl.BeginDrawing() @@ -579,16 +550,16 @@ func main() { player.update(state) - if state.fullClear() { - state.currentWave++ + if state.fullClear() || state.waveTimeout() { + if !state.nextWave() { + break + } } - if state.currentWave >= len(state.waves) { - break - } - state.enemies = state.waves[state.currentWave].enemies + enemiesTotalLifeRemaining := 0 for i := 0; i < len(state.enemies); i++ { state.enemies[i].update(state) + enemiesTotalLifeRemaining += state.enemies[i].health } for i := 0; i < len(state.bullets); i++ { @@ -606,7 +577,6 @@ func main() { state.gameSpeed = 1 } - // rl.EndTextureMode() // { // shaders @@ -635,17 +605,34 @@ func main() { { // UI currectScore += (state.score - currectScore) / 11 - rl.DrawText(strconv.Itoa(currectScore), state.arenaWidth, 0, 50, rl.White) - rl.DrawText( - strconv.Itoa(len(state.bullets)), state.arenaWidth, 50, 50, rl.White, + fmt.Sprint("score: ", strconv.Itoa(currectScore)), + state.arenaWidth, 0, 50, rl.White, ) rl.DrawText( - fmt.Sprintf("%f", state.frame), state.arenaWidth, 100, 50, rl.White, + fmt.Sprint("bullets: ", strconv.Itoa(len(state.bullets))), + state.arenaWidth, 50, 50, rl.White, + ) + + rl.DrawText( + fmt.Sprintf("wave: %d/%d", state.currentWave, len(state.waves)), + state.arenaWidth, 100, 50, rl.White, + ) + + rl.DrawText( + fmt.Sprintf("t: %f", rl.GetTime()), state.arenaWidth, 150, 50, rl.White, ) rl.DrawText( - fmt.Sprintf("%d", int(state.frame)), state.arenaWidth, 150, 50, rl.White, + fmt.Sprintf("sec/f: %.5f", rl.GetFrameTime()), state.arenaWidth, 200, 50, rl.White, + ) + rl.DrawText( + fmt.Sprintf("total life: %d", enemiesTotalLifeRemaining), + state.arenaWidth, 250, 50, rl.White, + ) + rl.DrawText( + fmt.Sprintf("speed: %f", state.gameSpeed), + state.arenaWidth, 300, 50, rl.White, ) rl.DrawText("danmaku babe bullet shoot shoot", 20, 20, 20, rl.DarkGray) rl.DrawLine(18, 42, state.arenaWidth-18, 42, rl.Black) diff --git a/movementPatterns.go b/movementPatterns.go new file mode 100644 index 0000000..adfc584 --- /dev/null +++ b/movementPatterns.go @@ -0,0 +1,138 @@ +package main + +import ( + "math" + + rl "github.com/gen2brain/raylib-go/raylib" +) + +type movementPattern func(*enemy) *enemy + +type patternDuration struct { + duration duration + move movementPattern +} + +type statePipeline []patternDuration + +func shootStill() movementPattern { + return func(e *enemy) *enemy { + if e.shoot != nil { + e.shoot(e) + } + return e + } +} + +func (sp statePipeline) MovementPattern(g *game) movementPattern { + state := -1 + t := newTimer(0) + return func(e *enemy) *enemy { + if !t.isTimeout() { + t.tick(g) + } else if state < len(sp)-1 { + state++ + t = newTimer(sp[state].duration) + } + sp[state].move(e) + return e + } +} + +func horizonalPattern(g *game) movementPattern { + direction := 1 + + return func(e *enemy) *enemy { + if e.shoot != nil { + e.shoot(e) + } + + delta := rl.Vector2{ + X: 400, + Y: 0, + } + + if e.pos.X < e.hitBoxRadius || e.pos.X > float32(g.arenaWidth-int32(e.hitBoxRadius)) { + direction = -direction + } + + e.pos = rl.Vector2Add( + e.pos, + rl.Vector2Scale( + rl.Vector2{X: float32(direction) * delta.X, Y: delta.Y}, + rl.GetFrameTime()*g.gameSpeed, + ), + ) + return e + } +} + +func descentMove(g *game, y0, y1 float32, d duration) movementPattern { + t := newTimer(d) + return func(e *enemy) *enemy { + + if e.shoot != nil { + e.shoot(e) + } + + if !t.isTimeout() { + t.tick(g) + } else { + return e + } + + e.pos.Y = lerp(y0, y1, easeInOutSine(t.unit())) + return e + } +} + +func sineDescentMove(g *game, y0, y1 float32, d duration) movementPattern { + t := newTimer(d) + return func(e *enemy) *enemy { + + if e.shoot != nil { + e.shoot(e) + } + + if !t.isTimeout() { + t.tick(g) + } else { + return e + } + + e.pos.Y = lerp(y0, y1, easeInOutSine(t.unit())) + e.pos.X += float32(math.Sin(rl.GetTime() * 5 * float64(g.gameSpeed))) + + return e + } +} + +func sineHorizonalPattern(g *game, offset float64) movementPattern { + direction := 1 + + return func(e *enemy) *enemy { + if e.shoot != nil { + e.shoot(e) + } + + sine := math.Sin(rl.GetTime()*5*float64(g.gameSpeed)+offset) * 150 + + delta := rl.Vector2{ + X: 400, + Y: float32(sine), + } + + if e.pos.X < e.hitBoxRadius || e.pos.X > float32(g.arenaWidth-int32(e.hitBoxRadius)) { + direction = -direction + } + + e.pos = rl.Vector2Add( + e.pos, + rl.Vector2Scale( + rl.Vector2{X: float32(direction) * delta.X, Y: delta.Y}, + rl.GetFrameTime()*g.gameSpeed, + ), + ) + return e + } +} diff --git a/player.go b/player.go new file mode 100644 index 0000000..472e154 --- /dev/null +++ b/player.go @@ -0,0 +1,117 @@ +package main + +import ( + rl "github.com/gen2brain/raylib-go/raylib" +) + +func (p *player) move(g *game) { + + var moveSpeed float32 + if p.focusMode { + moveSpeed = p.moveSpeed * p.focusSpeedDecrease + } else { + moveSpeed = p.moveSpeed + } + + p.speed = rl.Vector2{X: 0, Y: 0} + + if rl.IsKeyDown(rl.KeyW) { + p.speed.Y -= 1 + } + if rl.IsKeyDown(rl.KeyS) { + p.speed.Y += 1 + } + if rl.IsKeyDown(rl.KeyA) { + p.speed.X -= 1 + } + if rl.IsKeyDown(rl.KeyD) { + p.speed.X += 1 + } + + if !(p.speed.X == 0 && p.speed.Y == 0) { + // jogador se move mais rapido na diagonal caso o contrario + p.speed = rl.Vector2Normalize(p.speed) + p.speed = rl.Vector2Scale(p.speed, moveSpeed) + } + + result := rl.Vector2Add(p.pos, p.speed) + + if result.Y-p.hitBoxRadius < 0 || result.Y+p.hitBoxRadius > float32(g.arenaHeight) { + p.speed.Y = 0 + } + if result.X-p.hitBoxRadius < 0 || result.X+p.hitBoxRadius > float32(g.arenaWidth) { + p.speed.X = 0 + } + + p.pos = rl.Vector2Add(p.pos, p.speed) +} + +func (p *player) shoot(g *game) { + if p.focusMode { + return + } + + if int(g.frame)%3 != 0 { + return + } + + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + mouse := rl.GetMousePosition() + direction := rl.Vector2Subtract(mouse, p.pos) + direction = rl.Vector2Add(direction, p.speed) + direction = rl.Vector2Normalize(direction) + direction = rl.Vector2Scale(direction, p.bulletMoveSpeed) + + g.bullets = append(g.bullets, &bullet{ + pos: p.pos, + size: p.bulletSize, + speed: direction, + dmg: 1, + enemy: false, + }) + } +} + +func (p *player) checkHit(g *game) { + for _, bullet := range g.bullets { + if !bullet.enemy { + continue + } + distance := rl.Vector2Distance(p.pos, bullet.pos) - bullet.size + + if distance < p.hitBoxRadius { + // fmt.Println("hit!") + } + } +} + +func (p *player) checkFocus() { + // raylib não entende keybindings customizadas através do xmodmap? + p.focusMode = rl.IsKeyDown(rl.KeyLeftShift) || rl.IsKeyDown(rl.KeyRightShift) +} + +func (p *player) update(g *game) { + + p.checkFocus() + + p.move(g) + + p.shoot(g) + + p.checkHit(g) + + // hitbox + rl.DrawCircleV(p.pos, p.hitBoxRadius, rl.Red) + + if p.focusMode { + return + } + // mira + mouse := rl.GetMousePosition() + inverted := rl.Vector2Subtract(p.pos, mouse) + inverted = rl.Vector2Negate(inverted) + inverted = rl.Vector2Normalize(inverted) + inverted = rl.Vector2Scale(inverted, 2000) + rl.DrawLineV(p.pos, rl.Vector2Add(mouse, inverted), rl.NewColor(255, 0, 0, 100)) + +} From d50bed0777b70e52256cfe9448cb45439707dab6 Mon Sep 17 00:00:00 2001 From: silva guimaraes Date: Sat, 23 Aug 2025 19:55:34 -0300 Subject: [PATCH 10/10] Backup --- main.go | 249 +++++++++++++++++++++++++++++------------------------- player.go | 186 +++++++++++++++++++++++++++++++++------- 2 files changed, 292 insertions(+), 143 deletions(-) diff --git a/main.go b/main.go index 5157ded..40e722d 100644 --- a/main.go +++ b/main.go @@ -3,13 +3,15 @@ package main import ( "fmt" "math" + "math/rand" + "path" "strconv" rl "github.com/gen2brain/raylib-go/raylib" ) // 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. type bulletMovementPattern func(*bullet) rl.Vector2 @@ -18,10 +20,16 @@ type duration float32 const second duration = 1 -type hazard interface { // inimigos e projéteis +type body interface { // implementado por player e enemy Pos() rl.Vector2 + SetPos(rl.Vector2) + Direction() rl.Vector2 } +// type hazard interface { // inimigos e projéteis +// body +// } + type game struct { arenaWidth int32 arenaHeight int32 @@ -43,32 +51,36 @@ type plane struct { } type bullet struct { - pos rl.Vector2 - speed rl.Vector2 - size float32 - dmg int - enemy bool -} - -type player struct { - pos rl.Vector2 - speed rl.Vector2 - moveSpeed float32 - bulletMoveSpeed float32 - hitBoxRadius float32 - bulletSize float32 - focusMode bool - focusSpeedDecrease float32 + pos rl.Vector2 + speed rl.Vector2 + size float32 + dmg int + owner body + onHit func(body) + onDestroy func() } type enemy struct { pos rl.Vector2 + direction rl.Vector2 health int move movementPattern shoot shootingPattern 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 { duration *timer enemies []*enemy @@ -117,9 +129,12 @@ func (g *game) removeBullet(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 b.onDestroy != nil { + b.onDestroy() + } g.removeBullet(index) return } @@ -127,9 +142,9 @@ func (b *bullet) update(g *game, index int) { rl.DrawCircleV(b.pos, b.size, rl.Yellow) } -func bulletExplosion(g *game, rate, amount int, bulletSpeed, size float32) shootingPattern { - t := newTimer(second * duration(rate)) - return func(e *enemy) { +func bulletExplosion(g *game, rate float32, amount int, bulletSpeed, size float32) shootingPattern { + t := newTimer(second * duration(rate+rand.Float32())) + return func(e body) { t.tick(g) if !t.isTimeout() { @@ -150,8 +165,8 @@ func bulletExplosion(g *game, rate, amount int, bulletSpeed, size float32) shoot speed: direction, size: size, dmg: 1, - enemy: true, - pos: e.pos, + owner: e, + 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, - bulletMoveSpeed float32) shootingPattern { - return func(e *enemy) { - if int(g.frame)%rate != 0 { - return - } - direction := rl.Vector2Subtract(p.pos, e.pos) - direction = rl.Vector2Normalize(direction) - direction = rl.Vector2Scale(direction, bulletMoveSpeed) - - g.bullets = append(g.bullets, &bullet{ - speed: direction, - size: 12, - dmg: 1, - enemy: true, - pos: e.pos, - }) - } -} +// func ShootAtPlayer(g *game, p *player, rate int, +// bulletMoveSpeed float32) shootingPattern { +// return func(e body) { +// if int(g.frame)%rate != 0 { +// return +// } +// direction := rl.Vector2Subtract(p.pos, e.Pos()) +// direction = rl.Vector2Normalize(direction) +// direction = rl.Vector2Scale(direction, bulletMoveSpeed) +// +// g.bullets = append(g.bullets, &bullet{ +// speed: direction, +// size: 12, +// dmg: 1, +// enemy: true, +// pos: e.Pos(), +// }) +// } +// } func burstShootAtPlayer(g *game, p *player, rate float32, bulletMoveSpeed float32) shootingPattern { flag := true off := newTimer(second) on := newTimer(duration(float32(second) * rate)) - return func(e *enemy) { + return func(e body) { off.tick(g) @@ -202,7 +217,7 @@ func burstShootAtPlayer(g *game, p *player, rate float32, bulletMoveSpeed float3 } on.reset() - direction := rl.Vector2Subtract(p.pos, e.pos) + direction := rl.Vector2Subtract(p.pos, e.Pos()) direction = rl.Vector2Normalize(direction) direction = rl.Vector2Scale(direction, bulletMoveSpeed) @@ -210,14 +225,14 @@ func burstShootAtPlayer(g *game, p *player, rate float32, bulletMoveSpeed float3 speed: direction, size: 12, dmg: 1, - enemy: true, - pos: e.pos, + owner: e, + pos: e.Pos(), }) } } func shootStraightDown(g *game) shootingPattern { - return func(e *enemy) { + return func(e body) { if int(g.frame)%10 != 0 { return } @@ -225,8 +240,8 @@ func shootStraightDown(g *game) shootingPattern { speed: rl.Vector2{X: 0, Y: 5}, size: 12, dmg: 1, - enemy: true, - pos: e.pos, + owner: e, + pos: e.Pos(), }) } } @@ -288,7 +303,7 @@ func shootStraightDown(g *game) shootingPattern { func (e *enemy) checkHit(g *game) (bool, *bullet, int) { for index, bullet := range g.bullets { - playerBullet := !bullet.enemy + _, playerBullet := bullet.owner.(*player) if !playerBullet { continue } @@ -306,6 +321,16 @@ func (g *game) killEnemy(index int) { 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) { if e.health <= 0 { @@ -321,19 +346,30 @@ func (e *enemy) update(g *game) { } if hit, bullet, idx := e.checkHit(g); hit { + g.score += 273 e.health -= bullet.dmg + + if bullet.onHit != nil { + bullet.onHit(e) + } + g.removeBullet(idx) enemyColor = rl.White g.backgroundColor = rl.NewColor(20, 20, 20, 255) + + if e.health <= 0 { + e.deleteBullets(g) + return + } } rl.DrawCircleV(e.pos, e.hitBoxRadius, enemyColor) } func (g *game) fullClear() bool { - for _, e := range g.waves[g.currentWave].enemies { - if e.health != 0 { + for _, e := range g.enemies { + if e.health > 0 { return false } } @@ -370,10 +406,9 @@ func (g *game) addEnemy(e ...*enemy) { } func main() { - state := &game{ arenaWidth: 450, - arenaHeight: 700, + arenaHeight: 900, interfaceWidth: 400, gameSpeed: 1, backgroundColor: rl.NewColor(0, 0, 0, 100), @@ -383,34 +418,36 @@ func main() { X: float32(state.arenaWidth) / 2, Y: float32(state.arenaHeight) * 0.8, }, - moveSpeed: 4, + direction: rl.Vector2{X: 0, Y: -1}, + moveSpeed: 400, focusSpeedDecrease: 0.5, bulletMoveSpeed: 6, bulletSize: 9, hitBoxRadius: 5, + shoot: snipe(state), } - var arena = []plane{ - { - normal: rl.Vector2{X: 0, Y: -1}, - pos: rl.Vector2{X: 1, Y: 0}, - }, - { - normal: rl.Vector2{X: -1, Y: 0}, - pos: rl.Vector2{X: float32(state.arenaWidth), Y: 0}, - }, - { - normal: rl.Vector2{X: 0, Y: 1}, - pos: rl.Vector2{X: 0, Y: float32(state.arenaHeight)}, - }, - { - normal: rl.Vector2{X: 1, Y: 0}, - pos: rl.Vector2{X: 0, Y: 1}, - }, - } - state.walls = arena + // var arena = []plane{ + // { + // normal: rl.Vector2{X: 0, Y: -1}, + // pos: rl.Vector2{X: 1, Y: 0}, + // }, + // { + // normal: rl.Vector2{X: -1, Y: 0}, + // pos: rl.Vector2{X: float32(state.arenaWidth), Y: 0}, + // }, + // { + // normal: rl.Vector2{X: 0, Y: 1}, + // pos: rl.Vector2{X: 0, Y: float32(state.arenaHeight)}, + // }, + // { + // normal: rl.Vector2{X: 1, Y: 0}, + // pos: rl.Vector2{X: 0, Y: 1}, + // }, + // } + // state.walls = arena - // rl.SetTraceLog(rl.LogWarning | rl.LogDebug) + rl.SetTraceLog(rl.LogWarning | rl.LogDebug) rl.SetConfigFlags(rl.FlagMsaa4xHint) rl.InitWindow(state.arenaWidth+state.interfaceWidth, state.arenaHeight, "danmaku") @@ -421,11 +458,17 @@ func main() { // shader := rl.LoadShader("", shader_path) // timeShaderLocation := rl.GetShaderLocation(shader, "time") // target := rl.LoadRenderTexture( - // state.arenaWidth + state.interfaceWidth, - // state.arenaHeight, + // state.arenaWidth+state.interfaceWidth, + // 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{ { @@ -444,7 +487,7 @@ func main() { move: sineHorizonalPattern(state, 0), }, }.MovementPattern(state), - shoot: burstShootAtPlayer(state, &player, 0.1, 4), + shoot: burstShootAtPlayer(state, &player, 0.1, 400), }, { pos: rl.Vector2{X: 200, Y: -20}, @@ -463,7 +506,7 @@ func main() { move: sineHorizonalPattern(state, 1), }, }.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), }, }.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), }, }.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, @@ -516,7 +559,7 @@ func main() { move: sineHorizonalPattern(state, 0), }, }.MovementPattern(state), - shoot: burstShootAtPlayer(state, &player, 0.2, 4), + shoot: burstShootAtPlayer(state, &player, 0.2, 400), }, { pos: rl.Vector2{X: 50, Y: 250}, @@ -531,7 +574,7 @@ func main() { move: sineHorizonalPattern(state, 0), }, }.MovementPattern(state), - shoot: bulletExplosion(state, 1, 20, 2, 11), + shoot: bulletExplosion(state, 1, 20, 300, 11), // shoot: shootStraightDown(state), }, }, @@ -541,8 +584,11 @@ func main() { currectScore := 0 state.addEnemy(state.waves[0].enemies...) + spawner := starsBackground(state) + for ; !rl.WindowShouldClose(); state.frame += state.gameSpeed { rl.BeginDrawing() + rl.BeginShaderMode(shader) // rl.BeginTextureMode(target) rl.ClearBackground(state.backgroundColor) @@ -559,9 +605,8 @@ func main() { enemiesTotalLifeRemaining := 0 for i := 0; i < len(state.enemies); i++ { 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++ { state.bullets[i].update(state, i) } @@ -571,38 +616,14 @@ func main() { rl.NewColor(0, 33, 59, 255), ) + spawner.update(state) + if player.focusMode { state.gameSpeed = 0.3 } else { 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 currectScore += (state.score - currectScore) / 11 rl.DrawText( @@ -639,7 +660,9 @@ func main() { rl.DrawFPS(0, 0) } + rl.EndShaderMode() rl.EndDrawing() + } rl.CloseWindow() diff --git a/player.go b/player.go index 472e154..672ef9f 100644 --- a/player.go +++ b/player.go @@ -1,9 +1,36 @@ package main import ( + "fmt" + 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) { var moveSpeed float32 @@ -34,7 +61,7 @@ func (p *player) move(g *game) { 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) { p.speed.Y = 0 @@ -43,38 +70,39 @@ func (p *player) move(g *game) { 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) { - if p.focusMode { - return - } - - if int(g.frame)%3 != 0 { - return - } - - if rl.IsMouseButtonDown(rl.MouseLeftButton) { - mouse := rl.GetMousePosition() - direction := rl.Vector2Subtract(mouse, p.pos) - direction = rl.Vector2Add(direction, p.speed) - direction = rl.Vector2Normalize(direction) - direction = rl.Vector2Scale(direction, p.bulletMoveSpeed) - - g.bullets = append(g.bullets, &bullet{ - pos: p.pos, - size: p.bulletSize, - speed: direction, - dmg: 1, - enemy: false, - }) - } -} +// func (p *player) shoot(g *game) { +// if p.focusMode { +// return +// } +// +// if int(g.frame)%3 != 0 { +// return +// } +// +// if rl.IsMouseButtonDown(rl.MouseLeftButton) { +// mouse := rl.GetMousePosition() +// direction := rl.Vector2Subtract(mouse, p.pos) +// direction = rl.Vector2Add(direction, p.speed) +// direction = rl.Vector2Normalize(direction) +// direction = rl.Vector2Scale(direction, p.bulletMoveSpeed) +// +// g.bullets = append(g.bullets, &bullet{ +// pos: p.pos, +// size: p.bulletSize, +// speed: direction, +// dmg: 1, +// enemy: false, +// }) +// } +// } func (p *player) checkHit(g *game) { for _, bullet := range g.bullets { - if !bullet.enemy { + _, playerBullet := bullet.owner.(*player) + if playerBullet { continue } distance := rl.Vector2Distance(p.pos, bullet.pos) - bullet.size @@ -96,7 +124,9 @@ func (p *player) update(g *game) { p.move(g) - p.shoot(g) + if !p.focusMode && p.shoot != nil { + p.shoot(p) + } p.checkHit(g) @@ -112,6 +142,102 @@ func (p *player) update(g *game) { inverted = rl.Vector2Negate(inverted) inverted = rl.Vector2Normalize(inverted) 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) + }, + }) + + } }