diff --git a/.gitignore b/.gitignore deleted file mode 100644 index ad13d12..0000000 --- a/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -danmaku -danmaku.exe -shaders/* diff --git a/ease.go b/ease.go deleted file mode 100644 index b531fbc..0000000 --- a/ease.go +++ /dev/null @@ -1,21 +0,0 @@ -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 7fe4ecd..4a29b8c 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,5 @@ module danmaku -go 1.23 +go 1.20 require github.com/gen2brain/raylib-go/raylib v0.0.0-20230719211022-1083eace2049 diff --git a/main.go b/main.go index 40e722d..0d1faa3 100644 --- a/main.go +++ b/main.go @@ -3,666 +3,292 @@ 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(body) +type movementPattern int +type shootingPattern int -// diz para uma bala como ela deve se mover. -type bulletMovementPattern func(*bullet) rl.Vector2 - -type duration float32 - -const second duration = 1 - -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 -// } +const ( + horizontal movementPattern = iota + circular movementPattern = iota +) type game struct { - arenaWidth int32 - arenaHeight int32 - interfaceWidth int32 - frame float32 - enemies []*enemy - waves []*wave - walls []plane - currentWave int - bullets []*bullet - score int - gameSpeed float32 // 1 = velocidade normal - backgroundColor rl.Color -} - -type plane struct { - normal rl.Vector2 - pos rl.Vector2 + screenWidth int32 + screenHeight int32 + time int + enemies []*enemy + bullets []*bullet } type bullet struct { - pos rl.Vector2 - speed rl.Vector2 - size float32 - dmg int - owner body - onHit func(body) - onDestroy func() + pos rl.Vector2 + speed rl.Vector2 + size float32 + dmg int + enemy bool +} + +type player struct { + pos rl.Vector2 + moveSpeed float32 + bulletMoveSpeed float32 + hitBoxRadius float32 } 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 - 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(), - } + pos rl.Vector2 + health int + movePattern func(*enemy)rl.Vector2 + shootPattern func() + hitBoxRadius float32 } 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.screenHeight) && v.X <= float32(g.screenWidth) } 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, rl.GetFrameTime()*g.gameSpeed)) + b.pos = rl.Vector2Add(b.pos, b.speed) - if !g.insideArena(b.pos) { - if b.onDestroy != nil { - b.onDestroy() - } - 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 float32, amount int, bulletSpeed, size float32) shootingPattern { - t := newTimer(second * duration(rate+rand.Float32())) - return func(e body) { +func (e *enemy) shoot(g *game) { + if g.time % 15 != 0 { + return + } - t.tick(g) - if !t.isTimeout() { - return - } - t.reset() - 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, - owner: e, - pos: e.Pos(), - }) - } - - g.bullets = append(g.bullets, bullets...) - } + g.bullets = append(g.bullets, &bullet{ + speed: rl.Vector2{X: 0, Y: 10}, + size: 4, + 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 horizonalPattern(g *game) (func(*enemy)rl.Vector2) { + direction := rl.Vector2{X: 4, Y: 0} -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 body) { + return func(e *enemy) rl.Vector2 { + result := rl.Vector2Add(direction, e.pos) - off.tick(g) - - if off.isTimeout() { - flag = !flag - off.reset() - } - - 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, - owner: e, - pos: e.Pos(), - }) - } + if !g.insideArena(result) { + direction = rl.Vector2Negate(direction) + } + return result + } } -func shootStraightDown(g *game) shootingPattern { - return func(e body) { - if int(g.frame)%10 != 0 { - return - } - g.bullets = append(g.bullets, &bullet{ - speed: rl.Vector2{X: 0, Y: 5}, - size: 12, - dmg: 1, - owner: e, - pos: e.Pos(), - }) - } +func circlePattern(g *game, center rl.Vector2) (func(*enemy)rl.Vector2) { + + t := float64(0.5) + + 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 + } } -// 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 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.owner.(*player) - 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 + // fmt.Println(distance) - 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) 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, index int) { + + if e.movePattern != nil { + e.pos = e.movePattern(e) + } + + if hit, bullet, idx := e.checkHit(g); hit { + e.health -= bullet.dmg + g.removeBullet(idx) + } + + if e.health <= 0 { + g.killEnemy(index) + return + } + + e.shoot(g) + + rl.DrawCircleV(e.pos, 5, rl.Blue) } -func (e *enemy) update(g *game) { - - if e.health <= 0 { - return - } - - enemyColor := rl.Blue - - if e.move != nil { - // e.pos = rl.Vector2Add(rl.Vector2Scale(e.move(e), g.gameSpeed), e.pos) - e.move(e) - // e.pos = e.move(e) - } - - 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 (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 (g *game) fullClear() bool { - for _, e := range g.enemies { - if e.health > 0 { - return false - } - } - return true +func (p *player) shoot(g *game){ + if g.time % 10 != 0 { + return + } + + if rl.IsMouseButtonDown(rl.MouseLeftButton) { + // não leva em consideração a velocidade do jogador + mouse := rl.GetMousePosition() + direction := rl.Vector2Subtract(mouse, p.pos) + direction = rl.Vector2Normalize(direction) + g.bullets = append(g.bullets, &bullet{ + pos: p.pos, + size: 2, + speed: rl.Vector2Scale(direction, p.bulletMoveSpeed), + dmg: 1, + enemy: false, + }) + } } -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 (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 (g *game) wavesOver() bool { - return g.currentWave == len(g.waves) -} +func (p *player) update(g *game) { -func (g *game) nextWave() bool { - g.currentWave++ - if g.wavesOver() { - return false - } - g.addEnemy(g.waves[g.currentWave].enemies...) - return true -} + p.move() + + p.shoot(g) + + p.checkHit(g) + + // hitbox + rl.DrawCircleV(p.pos, p.hitBoxRadius, rl.Red) + + // 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) addEnemy(e ...*enemy) { - g.enemies = append(g.enemies, e...) } func main() { - state := &game{ - arenaWidth: 450, - arenaHeight: 900, - interfaceWidth: 400, - 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, - }, - 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 + state := &game{screenWidth: 450, screenHeight: 700} - rl.SetTraceLog(rl.LogWarning | rl.LogDebug) + player := player{ + pos: rl.Vector2{X: 100, Y: 100}, + moveSpeed: 4, + bulletMoveSpeed: 8, + hitBoxRadius: 5, + } - rl.SetConfigFlags(rl.FlagMsaa4xHint) - rl.InitWindow(state.arenaWidth+state.interfaceWidth, state.arenaHeight, "danmaku") - targetFPS := 120 - rl.SetTargetFPS(int32(targetFPS)) + rl.SetTraceLog(rl.LogWarning | rl.LogDebug) + rl.InitWindow(state.screenWidth, state.screenHeight, "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}, + health: 1, + hitBoxRadius: 5, + movePattern: horizonalPattern(state), + }, + { + pos: rl.Vector2{X: 169, Y: 222}, + health: 1, + hitBoxRadius:5, + movePattern: horizonalPattern(state), + }, + { + pos: rl.Vector2{X: 400, Y: 400}, + health: 1, + hitBoxRadius:5, + // movePattern: circlePattern(state, rl.Vector2{X: 200, Y: 200}), + }, + { + pos: rl.Vector2{X: 200, Y: 200}, + health: 1, + hitBoxRadius:5, + // movePattern: circlePattern(state, rl.Vector2{X: 200, Y: 200}), + }} - 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{ - { - duration: newTimer(second * 10), - enemies: []*enemy{ - { - pos: rl.Vector2{X: 100, Y: -20}, - health: 100, - hitBoxRadius: 20, - move: statePipeline{ - { - duration: 1.1, - move: sineDescentMove(state, -20, 200, 1), - }, - { - move: sineHorizonalPattern(state, 0), - }, - }.MovementPattern(state), - shoot: burstShootAtPlayer(state, &player, 0.1, 400), - }, - { - 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, 400), - }, - }, - }, - { - duration: newTimer(second * 20), - enemies: []*enemy{ - { - pos: rl.Vector2{X: 100, Y: 100}, - health: 100, - hitBoxRadius: 20, - move: statePipeline{ - { - duration: 1.1, - move: sineDescentMove(state, -20, 200, 1), - }, - { - move: sineHorizonalPattern(state, 0), - }, - }.MovementPattern(state), - shoot: bulletExplosion(state, 1, 40, 300, 11), - }, - }, - }, - { - enemies: []*enemy{ - { - pos: rl.Vector2{X: 200, Y: 200}, - health: 100, - hitBoxRadius: 20, - move: statePipeline{ - { - duration: 1.1, - move: sineDescentMove(state, -20, 200, 1), - }, - { - move: sineHorizonalPattern(state, 0), - }, - }.MovementPattern(state), - shoot: bulletExplosion(state, 1, 20, 300, 11), - }, - { - pos: rl.Vector2{X: 100, Y: 100}, health: 100, - hitBoxRadius: 20, - move: statePipeline{ - { - duration: 1.1, - move: sineDescentMove(state, -20, 200, 1), - }, - { - move: sineHorizonalPattern(state, 0), - }, - }.MovementPattern(state), - shoot: burstShootAtPlayer(state, &player, 0.2, 400), - }, - { - pos: rl.Vector2{X: 50, Y: 250}, - health: 100, - hitBoxRadius: 20, - move: statePipeline{ - { - duration: 1.1, - move: sineDescentMove(state, -20, 200, 1), - }, - { - move: sineHorizonalPattern(state, 0), - }, - }.MovementPattern(state), - shoot: bulletExplosion(state, 1, 20, 300, 11), - // shoot: shootStraightDown(state), - }, - }, - }, - } - - currectScore := 0 - state.addEnemy(state.waves[0].enemies...) - - spawner := starsBackground(state) - - for ; !rl.WindowShouldClose(); state.frame += state.gameSpeed { + for ; !rl.WindowShouldClose(); state.time += 1 { rl.BeginDrawing() - rl.BeginShaderMode(shader) + rl.ClearBackground(rl.Black) - // rl.BeginTextureMode(target) - rl.ClearBackground(state.backgroundColor) - state.backgroundColor = rl.Black + rl.DrawText("danmaku", 20, 20, 20, rl.DarkGray) + rl.DrawLine(18, 42, state.screenWidth-18, 42, rl.Black) + rl.DrawFPS(0, 0) - player.update(state) + player.update(state) - if state.fullClear() || state.waveTimeout() { - if !state.nextWave() { - break - } - } + for i := range state.enemies { + state.enemies[i].update(state, i) + } - enemiesTotalLifeRemaining := 0 - for i := 0; i < len(state.enemies); i++ { - state.enemies[i].update(state) - enemiesTotalLifeRemaining += max(state.enemies[i].health, 0) - } - for i := 0; i < len(state.bullets); i++ { - state.bullets[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), - ) - - spawner.update(state) - - if player.focusMode { - state.gameSpeed = 0.3 - } else { - state.gameSpeed = 1 - } - - { // UI - currectScore += (state.score - currectScore) / 11 - rl.DrawText( - fmt.Sprint("score: ", strconv.Itoa(currectScore)), - state.arenaWidth, 0, 50, rl.White, - ) - - rl.DrawText( - 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("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) - rl.DrawFPS(0, 0) - } - - rl.EndShaderMode() rl.EndDrawing() - } rl.CloseWindow() diff --git a/movementPatterns.go b/movementPatterns.go deleted file mode 100644 index adfc584..0000000 --- a/movementPatterns.go +++ /dev/null @@ -1,138 +0,0 @@ -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 deleted file mode 100644 index 672ef9f..0000000 --- a/player.go +++ /dev/null @@ -1,243 +0,0 @@ -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 - 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, rl.Vector2Scale(p.speed, rl.GetFrameTime())) - - 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, 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) checkHit(g *game) { - for _, bullet := range g.bullets { - _, playerBullet := bullet.owner.(*player) - if playerBullet { - 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) - - if !p.focusMode && p.shoot != nil { - p.shoot(p) - } - - 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.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) - }, - }) - - } - -} diff --git a/windows.sh b/windows.sh deleted file mode 100644 index f3ece73..0000000 --- a/windows.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc GOOS=windows GOARCH=amd64 CGO_LDFLAGS="-static-libgcc -static -lpthread" go build