2024-08-29 00:05:28 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/veandco/go-sdl2/sdl"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2024-08-29 18:48:27 +02:00
|
|
|
MapWidth = 1000 // Width of the map
|
|
|
|
MapHeight = 1000 // Height of the map
|
|
|
|
BlastRadius = 5
|
|
|
|
|
|
|
|
MaxEnergy = 3520
|
|
|
|
MaxAmmunition = 6
|
|
|
|
MaxShields = 100
|
|
|
|
|
|
|
|
NormalShotCost = 7
|
|
|
|
SuperShotCost = 80
|
|
|
|
ReloadCost = 4
|
|
|
|
MovementCost = 1
|
|
|
|
DiggingCost = 3
|
|
|
|
ShootDiggingCostBonus = 1
|
|
|
|
|
2024-08-29 00:05:28 +02:00
|
|
|
ShootCooldown = 8
|
|
|
|
RechargeCooldownOwn = 0
|
|
|
|
DiggingCooldown = 4
|
|
|
|
RechargeCooldownOpponent = 6
|
|
|
|
RepairCooldown = 4
|
|
|
|
MovementCooldown = 2
|
|
|
|
MovementCooldownNoEnergy = 4
|
|
|
|
DiggingCooldownNoEnergy = 8
|
2024-08-29 18:48:27 +02:00
|
|
|
ReloadCooldown = 16
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
Debug = false
|
|
|
|
MapWindow = true
|
|
|
|
RenderGameObjects = true
|
|
|
|
ProfilerOn = true
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
JoyStickDeadZone = 8000
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
DoAllKeymapsPlayers = true
|
|
|
|
DoJoyStickPlayers = true
|
|
|
|
DoKeymapPlayer = true
|
|
|
|
)
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
var mapWindow *sdl.Window
|
|
|
|
var mapSurface *sdl.Surface
|
|
|
|
var mapRendererRect = &sdl.Rect{X: 0, Y: 0, W: MapWidth, H: MapHeight}
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
func main() {
|
|
|
|
initializeSDL()
|
|
|
|
defer sdl.Quit()
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
gameMap := &GameMap{}
|
2024-08-29 00:05:28 +02:00
|
|
|
gameMap.createGameMap(MapWidth, MapHeight)
|
|
|
|
|
|
|
|
players := &[]*Player{}
|
2024-08-29 18:48:27 +02:00
|
|
|
initPlayerColors()
|
|
|
|
createPlayers(getNeededPlayers(), playerColors, keyMaps, joyMaps, gameMap, players)
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
defer closeThings(players)
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
bases := createBases(players, gameMap)
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
bullets := &[]*Bullet{}
|
|
|
|
bulletParticles := &[]*BulletParticle{}
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
for playerIndex, player := range *players {
|
|
|
|
initPlayer(uint8(playerIndex), player)
|
|
|
|
}
|
|
|
|
if MapWindow {
|
|
|
|
mapWindow, mapSurface = setupMapWindowAndSurface()
|
|
|
|
}
|
2024-08-29 00:05:28 +02:00
|
|
|
running := true
|
|
|
|
for running {
|
2024-08-29 18:48:27 +02:00
|
|
|
frameStart := sdl.GetTicks64()
|
|
|
|
for playerIndex, player := range *players {
|
|
|
|
// Delay to achieve roughly 60 FPS
|
|
|
|
if player.local {
|
|
|
|
running = doPlayerFrame(uint8(playerIndex), player, players, gameMap, bases, bullets, bulletParticles)
|
|
|
|
if !running {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if MapWindow {
|
|
|
|
gameMap.render(mapRendererRect, mapSurface)
|
|
|
|
for _, bullet := range *bullets {
|
|
|
|
(*bullet).render(mapRendererRect, mapSurface)
|
|
|
|
}
|
|
|
|
for _, base := range *bases {
|
|
|
|
(*base).render(mapRendererRect, mapSurface)
|
|
|
|
}
|
|
|
|
for _, playerLoop := range *players {
|
|
|
|
(*playerLoop).render(mapRendererRect, mapSurface)
|
|
|
|
}
|
|
|
|
for _, bulletParticle := range *bulletParticles {
|
|
|
|
bulletParticle.render(mapRendererRect, mapSurface)
|
|
|
|
}
|
|
|
|
adjustWindow(mapWindow, mapSurface)
|
|
|
|
}
|
|
|
|
//now tick world
|
|
|
|
for _, bullet := range *bullets {
|
|
|
|
(*bullet).tick(gameMap, bulletParticles, bullets, players)
|
|
|
|
}
|
|
|
|
for _, base := range *bases {
|
|
|
|
(*base).tick(players)
|
|
|
|
}
|
|
|
|
for _, bulletParticle := range *bulletParticles {
|
|
|
|
bulletParticle.tick(bulletParticles)
|
|
|
|
}
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
enforceFrameRate(frameStart, 60)
|
|
|
|
}
|
|
|
|
}
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
func initPlayer(playerIndex uint8, player *Player) {
|
|
|
|
player.window, player.logicalSurface = setupWindowAndSurface(playerIndex)
|
|
|
|
logicalColor := sdl.MapRGBA(player.logicalSurface.Format, 101, 101, 0, 255)
|
|
|
|
player.logicalSurface.FillRect(nil, logicalColor)
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
player.playSurface, player.playSurfaceRect, player.playSurfaceTargetRect = setupPlaySurface()
|
|
|
|
playColor := sdl.MapRGBA(player.playSurface.Format, 101, 0, 101, 255)
|
|
|
|
player.playSurface.FillRect(nil, playColor)
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
player.HUDSurface, player.HUDSurfaceRect, player.HUDSurfaceTargetRect = setupHUDSurface()
|
|
|
|
initHud(player.HUDSurface)
|
|
|
|
player.camera = &sdl.Rect{X: 0, Y: 0, W: 76, H: 76}
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
func doPlayerFrame(playerIndex uint8, player *Player, players *[]*Player, gameMap *GameMap, bases *[]*Base, bullets *[]*Bullet, bulletParticles *[]*BulletParticle) bool {
|
|
|
|
running := true
|
|
|
|
var (
|
|
|
|
totalHandleEventsTime, totalRenderTime, totalFrameTime uint64
|
|
|
|
totalScalingTime, frameCount uint64
|
|
|
|
isShooting, shouldContinue bool
|
|
|
|
)
|
|
|
|
frameStart := sdl.GetTicks64()
|
|
|
|
|
|
|
|
// Profile handleEvents
|
|
|
|
totalHandleEventsTime += profileSection(func() {
|
|
|
|
running = handleEvents(player.window, player.logicalSurface)
|
|
|
|
keyboard := sdl.GetKeyboardState()
|
|
|
|
shouldContinue, isShooting = handleInput(keyboard, bullets, player, gameMap, player.playSurface.Format, players)
|
|
|
|
running = running && shouldContinue
|
|
|
|
})
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
// Profile rendering (aggregate all renderings)
|
|
|
|
totalRenderTime += profileSection(func() {
|
|
|
|
player.track(player.camera)
|
|
|
|
gameMap.render(player.camera, player.playSurface)
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
for _, bullet := range *bullets {
|
|
|
|
(*bullet).render(player.camera, player.playSurface)
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
2024-08-29 18:48:27 +02:00
|
|
|
for _, base := range *bases {
|
|
|
|
(*base).render(player.camera, player.playSurface)
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
2024-08-29 18:48:27 +02:00
|
|
|
for _, playerLoop := range *players {
|
|
|
|
(*playerLoop).render(player.camera, player.playSurface)
|
|
|
|
}
|
|
|
|
for _, bulletParticle := range *bulletParticles {
|
|
|
|
bulletParticle.render(player.camera, player.playSurface)
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
player.tick(isShooting, bullets, player.playSurface.Format)
|
|
|
|
renderHud(player, player.HUDSurface)
|
|
|
|
player.playSurface.BlitScaled(player.playSurfaceRect, player.logicalSurface, player.playSurfaceTargetRect)
|
|
|
|
player.HUDSurface.BlitScaled(player.HUDSurfaceRect, player.logicalSurface, player.HUDSurfaceTargetRect)
|
|
|
|
})
|
|
|
|
|
|
|
|
// Profile window adjustments
|
|
|
|
totalScalingTime += profileSection(func() {
|
|
|
|
adjustWindow(player.window, player.logicalSurface)
|
|
|
|
})
|
|
|
|
|
|
|
|
frameEnd := sdl.GetTicks64()
|
|
|
|
totalFrameTime += frameEnd - frameStart
|
|
|
|
frameCount++
|
|
|
|
|
|
|
|
// Log profiling information every 1000 frames
|
|
|
|
if frameCount%1000 == 0 && ProfilerOn && playerIndex == 0 {
|
|
|
|
logProfilingInfo(totalHandleEventsTime, totalRenderTime, totalScalingTime, totalFrameTime, frameCount)
|
|
|
|
resetProfilingCounters(&totalHandleEventsTime, &totalRenderTime, &totalScalingTime, &totalFrameTime, &frameCount)
|
|
|
|
}
|
|
|
|
return running
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|