This commit is contained in:
silva guimaraes 2025-08-23 19:53:45 -03:00
parent 2c2eaf9507
commit 730e697258

669
main.go
View file

@ -4,508 +4,509 @@ import (
"fmt" "fmt"
"math" "math"
"math/rand" "math/rand"
"slices"
rl "github.com/gen2brain/raylib-go/raylib" rl "github.com/gen2brain/raylib-go/raylib"
) )
const ( const (
WIDTH = 1100 WIDTH = 1100
HEIGHT = 700 HEIGHT = 700
buildingSpacing = 2.5 buildingSpacing = 2.5
buildingSize = 1.2 buildingSize = 1.2
maxBuildingHeight = 10 maxBuildingHeight = 10
maxColumns = 5 maxColumns = 5
enemyAcc = 0.01 enemyAcc = 0.01
maxSpeed = 0.1 maxSpeed = 0.1
buildingsHealth = 3 buildingsHealth = 3
) )
type enemy struct { type enemy struct {
pos rl.Vector3 pos rl.Vector3
speed float32 speed float32
} }
type remainingFrames int type remainingFrames int
type animationFunc func()remainingFrames type animationFunc func() remainingFrames
type building struct { type building struct {
pos rl.Vector3 pos rl.Vector3
size rl.Vector3 size rl.Vector3
color rl.Color color rl.Color
life int life int
boundingBox rl.BoundingBox boundingBox rl.BoundingBox
animate animationFunc animate animationFunc
} }
type healthBar struct { type healthBar struct {
life int life int
damageTaken float32 damageTaken float32
lastUpdate float64 lastUpdate float64
} }
type character struct { type character struct {
camera rl.Camera camera rl.Camera
damage int damage int
} }
type projectile struct { type projectile struct {
pos rl.Vector3 pos rl.Vector3
speed rl.Vector3 speed rl.Vector3
} }
type scene struct { type scene struct {
buildings []*building buildings []*building
healthBar *healthBar healthBar *healthBar
projectiles []*projectile projectiles []*projectile
character *character character *character
emitters []*emitter emitters []*emitter
} }
type particle struct { type particle struct {
// birth float32 // birth float32
lifetime float64 lifetime float64
pos rl.Vector3 pos rl.Vector3
speed rl.Vector3 speed rl.Vector3
} }
type emitter struct { type emitter struct {
particles []*particle particles []*particle
pos rl.Vector3 pos rl.Vector3
particleAmount int particleAmount int
} }
var city *scene var city *scene
func update_emitters() { func update_emitters() {
for i, e := range city.emitters { for i := 0; i < len(city.emitters); i++ {
if remainingParticles := e.update(); remainingParticles == 0 {
city.emitters[i] = city.emitters[len(city.emitters)-1] e := city.emitters[i]
city.emitters = city.emitters[:len(city.emitters)-1] remainingParticles := e.update()
}
} if remainingParticles == 0 {
city.emitters = slices.Delete(city.emitters, i, i+1)
i--
}
}
} }
func newEmitter(pos rl.Vector3, particleAmount int) *emitter { func newEmitter(pos rl.Vector3, particleAmount int) *emitter {
emitter := emitter{ emitter := emitter{
pos: pos, pos: pos,
particleAmount: particleAmount, particleAmount: particleAmount,
} }
for i := 0; i < particleAmount; i++ { for i := 0; i < particleAmount; i++ {
direction := rl.NewVector3( direction := rl.NewVector3(
rand.Float32()*2 - 1, rand.Float32()*2-1,
1, 1,
rand.Float32()*2 - 1, rand.Float32()*2-1,
) )
direction = rl.Vector3Normalize(direction) direction = rl.Vector3Normalize(direction)
direction = rl.Vector3Scale(direction, 0.3 + rand.Float32()/3) direction = rl.Vector3Scale(direction, 0.3+rand.Float32()/3)
particle := particle{ particle := particle{
lifetime: rl.GetTime() + 2, lifetime: rl.GetTime() + 2,
speed: direction, speed: direction,
pos: pos, pos: pos,
} }
emitter.particles = append(emitter.particles, &particle) emitter.particles = append(emitter.particles, &particle)
} }
return &emitter return &emitter
} }
func (e *emitter) update() int { func (e *emitter) update() int {
gravity := rl.NewVector3(0, -0.02, 0) gravity := rl.NewVector3(0, -0.02, 0)
remainingParticles := 0 remainingParticles := 0
rl.BeginBlendMode(rl.BlendAdditive) rl.BeginBlendMode(rl.BlendAdditive)
{ {
for _, particle := range e.particles { for _, particle := range e.particles {
if rl.GetTime() > particle.lifetime { if rl.GetTime() > particle.lifetime {
continue continue
} }
particle.speed = rl.Vector3Add(particle.speed, gravity) particle.speed = rl.Vector3Add(particle.speed, gravity)
newPos := rl.Vector3Add(particle.pos, particle.speed) newPos := rl.Vector3Add(particle.pos, particle.speed)
if newPos.Y <= 0 { if newPos.Y <= 0 {
particle.pos.Y = 0 particle.pos.Y = 0
} else { } else {
particle.pos = newPos particle.pos = newPos
} }
rl.DrawCubeV(particle.pos, rl.NewVector3(.1, .1, .1), rl.Yellow) rl.DrawCubeV(particle.pos, rl.NewVector3(.1, .1, .1), rl.Yellow)
remainingParticles += 1 remainingParticles += 1
} }
} }
rl.EndBlendMode() rl.EndBlendMode()
return remainingParticles return remainingParticles
} }
// retona true caso projétil precise ser destruido // retona true caso projétil precise ser destruido
func (p *projectile) isHit() bool { func (p *projectile) isHit() bool {
gravity := rl.NewVector3(0, -0.02, 0) gravity := rl.NewVector3(0, -0.02, 0)
p.speed = rl.Vector3Add(p.speed, gravity) p.speed = rl.Vector3Add(p.speed, gravity)
p.pos = rl.Vector3Add(p.pos, p.speed) p.pos = rl.Vector3Add(p.pos, p.speed)
if p.pos.Y < 0 { if p.pos.Y < 0 {
city.emitters = append(city.emitters, newEmitter(p.pos, 500)) city.emitters = append(city.emitters, newEmitter(p.pos, 500))
for _, building := range city.buildings { for _, building := range city.buildings {
if dist := rl.Vector3Distance(p.pos, building.pos); dist < 10 { if dist := rl.Vector3Distance(p.pos, building.pos); dist < 10 {
building.causeDamage(3) building.causeDamage(3)
} }
} }
return true return true
} }
rl.DrawSphere(p.pos, 0.5, rl.Gray) rl.DrawSphere(p.pos, 0.5, rl.Gray)
return false return false
} }
func update_projectiles() { func update_projectiles() {
for i, p := range city.projectiles { for i, p := range city.projectiles {
if hit := p.isHit(); hit { if hit := p.isHit(); hit {
city.projectiles[i] = city.projectiles[len(city.projectiles)-1] city.projectiles[i] = city.projectiles[len(city.projectiles)-1]
city.projectiles = city.projectiles[:len(city.projectiles)-1] city.projectiles = city.projectiles[:len(city.projectiles)-1]
} }
} }
} }
func (c *character) kill_aurea() { func (c *character) kill_aurea() {
const min = 10 const min = 10
for _, b := range city.buildings { for _, b := range city.buildings {
if distance := rl.Vector3Distance(c.camera.Position, b.pos); distance < min { if distance := rl.Vector3Distance(c.camera.Position, b.pos); distance < min {
b.causeDamage(c.damage) b.causeDamage(c.damage)
} }
} }
} }
func (c *character) throw_bomb(){ func (c *character) throw_bomb() {
if !rl.IsMouseButtonPressed(rl.MouseRightButton) { if !rl.IsMouseButtonPressed(rl.MouseRightButton) {
return return
} }
direction := rl.Vector3Subtract(c.camera.Target, c.camera.Position) direction := rl.Vector3Subtract(c.camera.Target, c.camera.Position)
projectile := projectile{ projectile := projectile{
pos: c.camera.Position, pos: c.camera.Position,
speed: rl.Vector3Scale(direction, 0.15), speed: rl.Vector3Scale(direction, 0.15),
} }
city.projectiles = append(city.projectiles, &projectile) city.projectiles = append(city.projectiles, &projectile)
} }
func (c *character) update() { func (c *character) update() {
shake := rl.NewVector3( shake := rl.NewVector3(
randomShake(0.003) * city.healthBar.damageTaken, randomShake(0.003)*city.healthBar.damageTaken,
randomShake(0.003) * city.healthBar.damageTaken, randomShake(0.003)*city.healthBar.damageTaken,
randomShake(0.003) * city.healthBar.damageTaken, randomShake(0.003)*city.healthBar.damageTaken,
) )
c.camera.Target = rl.Vector3Add(c.camera.Target, shake) c.camera.Target = rl.Vector3Add(c.camera.Target, shake)
c.laser_beam() c.laser_beam()
// c.kill_aurea() // c.kill_aurea()
c.throw_bomb() c.throw_bomb()
} }
func newCharacter() *character { func newCharacter() *character {
camera := rl.Camera3D{ camera := rl.Camera3D{
Position: rl.NewVector3(4.0, 2.0, 4.0), Position: rl.NewVector3(4.0, 2.0, 4.0),
Target: rl.NewVector3(0.0, 1.8, 0.0), Target: rl.NewVector3(0.0, 1.8, 0.0),
Up: rl.NewVector3(0.0, 1.0, 0.0), Up: rl.NewVector3(0.0, 1.0, 0.0),
Fovy: 80.0, Fovy: 80.0,
Projection: rl.CameraPerspective, Projection: rl.CameraPerspective,
} }
return &character{ return &character{
camera: camera, camera: camera,
damage: 1, damage: 1,
} }
} }
func draw_plane() { func draw_plane() {
rl.DrawPlane( rl.DrawPlane(
rl.NewVector3(16, 0.0, 16), rl.NewVector3(16, 0.0, 16),
rl.NewVector2(128.0, 128.0), rl.NewVector2(128.0, 128.0),
rl.NewColor(50, 50, 50, 255), rl.NewColor(50, 50, 50, 255),
) )
} }
func randomShake(amount float32) float32 { func randomShake(amount float32) float32 {
return rand.Float32() * amount - amount/2 return rand.Float32()*amount - amount/2
} }
func (hb *healthBar) update() { func (hb *healthBar) update() {
const MARGIN = 20 const MARGIN = 20
const BARWIDTH = (WIDTH - MARGIN*2) const BARWIDTH = (WIDTH - MARGIN*2)
currentLife := 0 currentLife := 0
maxLife := buildingsHealth * len(city.buildings) maxLife := buildingsHealth * len(city.buildings)
for _, b := range city.buildings { for _, b := range city.buildings {
currentLife += b.life currentLife += b.life
} }
position := rl.NewVector2(MARGIN, 10) position := rl.NewVector2(MARGIN, 10)
barWidth := BARWIDTH * currentLife/maxLife barWidth := BARWIDTH * currentLife / maxLife
size := rl.NewVector2(float32(barWidth), 10) size := rl.NewVector2(float32(barWidth), 10)
hb.damageTaken += float32(hb.life - currentLife) hb.damageTaken += float32(hb.life - currentLife)
damageTakenBar := size damageTakenBar := size
damageTakenBar.X = BARWIDTH * damageTakenBar.X = BARWIDTH *
(float32(currentLife) + hb.damageTaken) / float32(maxLife) (float32(currentLife) + hb.damageTaken) / float32(maxLife)
shake := rl.NewVector2( shake := rl.NewVector2(
randomShake(0.4) * hb.damageTaken, randomShake(0.4)*hb.damageTaken,
randomShake(0.4) * hb.damageTaken, randomShake(0.4)*hb.damageTaken,
) )
position = rl.Vector2Add(position, shake) position = rl.Vector2Add(position, shake)
rl.DrawRectangleV(position, damageTakenBar, rl.Orange) rl.DrawRectangleV(position, damageTakenBar, rl.Orange)
rl.DrawRectangleV(position, size, rl.Red) rl.DrawRectangleV(position, size, rl.Red)
hb.lastUpdate = rl.GetTime() hb.lastUpdate = rl.GetTime()
hb.life = currentLife hb.life = currentLife
hb.damageTaken *= 0.95 hb.damageTaken *= 0.95
} }
func newHealthBar(buildings []*building) *healthBar { func newHealthBar(buildings []*building) *healthBar {
return &healthBar{ return &healthBar{
life: buildingsHealth * len(buildings), life: buildingsHealth * len(buildings),
} }
} }
func (b *building) causeDamage(damage int) { func (b *building) causeDamage(damage int) {
if b.animate != nil || b.life <= 0 { if b.animate != nil || b.life <= 0 {
return return
} }
b.animate = shakeBuilding(b) b.animate = shakeBuilding(b)
b.life -= damage b.life -= damage
// fmt.Println("damage:", damage, "life:", b.life) // fmt.Println("damage:", damage, "life:", b.life)
} }
func newBuilding(x, z float32) *building { func newBuilding(x, z float32) *building {
color := rl.NewColor( color := rl.NewColor(
uint8(rl.GetRandomValue(0, 180)), uint8(rl.GetRandomValue(0, 180)),
uint8(rl.GetRandomValue(0, 180)), uint8(rl.GetRandomValue(0, 180)),
uint8(rl.GetRandomValue(0, 180)), uint8(rl.GetRandomValue(0, 180)),
255, 255,
) )
pos := rl.NewVector3(x * buildingSpacing, 0, z * buildingSpacing) pos := rl.NewVector3(x*buildingSpacing, 0, z*buildingSpacing)
size := rl.NewVector3( size := rl.NewVector3(
buildingSize, buildingSize,
float32(rl.GetRandomValue(1, maxBuildingHeight)), float32(rl.GetRandomValue(1, maxBuildingHeight)),
buildingSize, buildingSize,
) )
min := rl.NewVector3( min := rl.NewVector3(
pos.X - buildingSize/2, pos.X-buildingSize/2,
0, 0,
pos.Z - buildingSize/2, pos.Z-buildingSize/2,
) )
max := rl.NewVector3( max := rl.NewVector3(
pos.X + buildingSize/2, pos.X+buildingSize/2,
size.Y/2, size.Y/2,
pos.Z + buildingSize/2, pos.Z+buildingSize/2,
) )
return &building{ return &building{
color: color, color: color,
life: buildingsHealth, life: buildingsHealth,
pos: pos, pos: pos,
size: size, size: size,
boundingBox: rl.NewBoundingBox(min, max), boundingBox: rl.NewBoundingBox(min, max),
} }
} }
func drawWireframe(building building) { func drawWireframe(building building) {
increasedSize := rl.Vector3Scale(building.size, 1.05) increasedSize := rl.Vector3Scale(building.size, 1.05)
invertedColor := building.color invertedColor := building.color
invertedColor.R += 127 invertedColor.R += 127
invertedColor.G += 127 invertedColor.G += 127
invertedColor.B += 127 invertedColor.B += 127
rl.DrawCubeWiresV( rl.DrawCubeWiresV(
building.pos, building.pos,
increasedSize, increasedSize,
invertedColor, invertedColor,
) )
} }
func shakeBuilding(b *building) animationFunc { func shakeBuilding(b *building) animationFunc {
var frame remainingFrames = 60 * 0.7 var frame remainingFrames = 60 * 0.7
return func() remainingFrames { return func() remainingFrames {
building := *b building := *b
if frame % 4 == 0 { if frame%4 == 0 {
if b.life == 0 { if b.life == 0 {
building.color = rl.NewColor(255, 0, 0, 255) building.color = rl.NewColor(255, 0, 0, 255)
} else { } else {
building.color = rl.RayWhite building.color = rl.RayWhite
} }
} }
drawWireframe(building) drawWireframe(building)
shake := rl.NewVector3( shake := rl.NewVector3(
rand.Float32() * .2 - .1, rand.Float32()*.2-.1,
rand.Float32() * .1 - .05, rand.Float32()*.1-.05,
rand.Float32() * .2 - .1, rand.Float32()*.2-.1,
) )
// shake = rl.Vector3Scale(shake, float32(math.Sin(rl.GetTime()) + 1)/3) // shake = rl.Vector3Scale(shake, float32(math.Sin(rl.GetTime()) + 1)/3)
rl.DrawCubeV( rl.DrawCubeV(
rl.Vector3Add(building.pos, shake), rl.Vector3Add(building.pos, shake),
building.size, building.size,
building.color, building.color,
) )
frame -= 1 frame -= 1
return frame return frame
} }
} }
func draw_buildings() { func draw_buildings() {
for _, building := range city.buildings { for _, building := range city.buildings {
hasAnimation := building.animate != nil hasAnimation := building.animate != nil
if building.life <= 0 && !hasAnimation { if building.life <= 0 && !hasAnimation {
continue continue
} }
if hasAnimation { if hasAnimation {
remainingFrames := building.animate() remainingFrames := building.animate()
if remainingFrames == 0 { if remainingFrames == 0 {
building.animate = nil building.animate = nil
} }
continue continue
} }
drawWireframe(*building) drawWireframe(*building)
rl.DrawCubeV(building.pos, building.size, building.color) rl.DrawCubeV(building.pos, building.size, building.color)
} }
} }
func (c *character) laser_beam() { func (c *character) laser_beam() {
if !rl.IsMouseButtonDown(rl.MouseLeftButton) { if !rl.IsMouseButtonDown(rl.MouseLeftButton) {
return return
} }
ray := rl.Ray{ ray := rl.Ray{
Position: c.camera.Position, Position: c.camera.Position,
Direction: rl.Vector3Subtract(c.camera.Target, c.camera.Position), Direction: rl.Vector3Subtract(c.camera.Target, c.camera.Position),
} }
closestDistance := math.Inf(1) closestDistance := math.Inf(1)
var closest *building var closest *building
for _, building := range city.buildings { for _, building := range city.buildings {
if building.life == 0 { if building.life == 0 {
continue continue
} }
playerDistance := rl.Vector3Distance(c.camera.Position, building.pos) playerDistance := rl.Vector3Distance(c.camera.Position, building.pos)
if playerDistance < float32(closestDistance) { if playerDistance < float32(closestDistance) {
collision := rl.GetRayCollisionBox(ray, building.boundingBox) collision := rl.GetRayCollisionBox(ray, building.boundingBox)
if collision.Hit { if collision.Hit {
closestDistance = float64(playerDistance) closestDistance = float64(playerDistance)
closest = building closest = building
} }
} }
} }
if closest != nil { if closest != nil {
closest.causeDamage(c.damage) closest.causeDamage(c.damage)
} }
} }
func newBuildings() []*building { func newBuildings() []*building {
var buildings []*building var buildings []*building
for i := 0; i < 32; i++ { for i := 0; i < 32; i++ {
for j := 0; j < 32; j++ { for j := 0; j < 32; j++ {
buildings = append(buildings, newBuilding(float32(i), float32(j))) buildings = append(buildings, newBuilding(float32(i), float32(j)))
} }
} }
return buildings return buildings
} }
func main() { func main() {
fmt.Println("hello world") fmt.Println("hello world")
rl.SetConfigFlags(rl.FlagMsaa4xHint) rl.SetConfigFlags(rl.FlagMsaa4xHint)
rl.InitWindow(WIDTH, HEIGHT, "raylib [core] example - 3d camera first person") rl.InitWindow(WIDTH, HEIGHT, "raylib [core] example - 3d camera first person")
rl.SetTargetFPS(60) rl.SetTargetFPS(60)
rl.HideCursor() rl.HideCursor()
rl.DisableCursor() rl.DisableCursor()
rl.SetMousePosition(WIDTH/2, HEIGHT/2) rl.SetMousePosition(WIDTH/2, HEIGHT/2)
character := newCharacter() character := newCharacter()
buildings := newBuildings() buildings := newBuildings()
healthBar := newHealthBar(buildings) healthBar := newHealthBar(buildings)
city = &scene{ city = &scene{
buildings: buildings, buildings: buildings,
healthBar: healthBar, healthBar: healthBar,
character: character, character: character,
} }
// direction := rl.Vector3Subtract(character.camera.Target, character.camera.Position) // direction := rl.Vector3Subtract(character.camera.Target, character.camera.Position)
// aim := direction // aim := direction
for !rl.WindowShouldClose() { for !rl.WindowShouldClose() {
rl.UpdateCamera(&character.camera, rl.CameraFirstPerson) rl.UpdateCamera(&character.camera, rl.CameraFirstPerson)
rl.BeginDrawing() rl.BeginDrawing()
rl.ClearBackground(rl.LightGray) rl.ClearBackground(rl.LightGray)
rl.BeginMode3D(character.camera) rl.BeginMode3D(character.camera)
{ {
character.update() character.update()
draw_plane() draw_plane()
update_projectiles() update_projectiles()
draw_buildings() draw_buildings()
update_emitters() update_emitters()
// direction = rl.Vector3Subtract(
// character.camera.Target, character.camera.Position)
// aim = rl.Vector3Lerp(direction, aim, 0.95)
// rl.DrawSphere(rl.Vector3Add(character.camera.Position, aim), 0.1, rl.Red)
}
rl.EndMode3D()
rl.DrawLineV(
rl.NewVector2(WIDTH/2-5, HEIGHT/2-5),
rl.NewVector2(WIDTH/2+5, HEIGHT/2+5),
rl.Red,
)
rl.DrawLineV(
rl.NewVector2(WIDTH/2-5, HEIGHT/2+5),
rl.NewVector2(WIDTH/2+5, HEIGHT/2-5),
rl.Red,
)
// direction = rl.Vector3Subtract( rl.DrawFPS(0, HEIGHT-30)
// character.camera.Target, character.camera.Position)
// aim = rl.Vector3Lerp(direction, aim, 0.95)
// rl.DrawSphere(rl.Vector3Add(character.camera.Position, aim), 0.1, rl.Red)
}
rl.EndMode3D()
rl.DrawLineV( healthBar.update()
rl.NewVector2(WIDTH/2-5, HEIGHT/2-5),
rl.NewVector2(WIDTH/2+5, HEIGHT/2+5),
rl.Red,
)
rl.DrawLineV(
rl.NewVector2(WIDTH/2-5, HEIGHT/2+5),
rl.NewVector2(WIDTH/2+5, HEIGHT/2-5),
rl.Red,
)
rl.DrawFPS(0, HEIGHT-30)
healthBar.update()
rl.EndDrawing() rl.EndDrawing()
} }