Add networking
This commit is contained in:
parent
842c41fdca
commit
dc854d411f
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
proto/tuneller.pb.go
|
||||
proto/*
|
||||
config.json
|
116
base.go
116
base.go
@ -1,38 +1,44 @@
|
||||
package main
|
||||
|
||||
import "github.com/veandco/go-sdl2/sdl"
|
||||
import (
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
type Base struct {
|
||||
owner *Player
|
||||
ownerID uint32
|
||||
openingWidth int32
|
||||
gameObject *GameObject
|
||||
}
|
||||
|
||||
func (base *Base) tick(players *[]*Player) {
|
||||
for _, player := range *players {
|
||||
func (base *Base) tick(players map[uint32]*Player) {
|
||||
for playerID, player := range players {
|
||||
if player.gameObject.baseRect.HasIntersection(&base.gameObject.baseRect) {
|
||||
if player.rechargeCooldown == 0 && player.energy < MaxEnergy {
|
||||
if MaxEnergy-player.energy < 4 {
|
||||
if player.rechargeCooldown == 0 && player.energy < serverConfig.MaxEnergy {
|
||||
if serverConfig.MaxEnergy-player.energy < 4 {
|
||||
player.energy++
|
||||
} else {
|
||||
player.energy += 4
|
||||
}
|
||||
if player == base.owner {
|
||||
player.rechargeCooldown = RechargeCooldownOwn
|
||||
if playerID == base.ownerID {
|
||||
player.rechargeCooldown = serverConfig.RechargeCooldownOwn
|
||||
} else {
|
||||
player.rechargeCooldown = RechargeCooldownOpponent
|
||||
player.rechargeCooldown = serverConfig.RechargeCooldownOpponent
|
||||
}
|
||||
}
|
||||
if player == base.owner && player.repairCooldown == 0 && player.shields < MaxShields {
|
||||
if playerID == base.ownerID && player.repairCooldown == 0 && player.shields < serverConfig.MaxShields {
|
||||
player.shields++
|
||||
player.repairCooldown = RepairCooldown
|
||||
player.repairCooldown = serverConfig.RepairCooldown
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (base *Base) render(camera *sdl.Rect, surface *sdl.Surface) {
|
||||
func (base *Base) render(camera *sdl.Rect, surface *sdl.Surface, bases map[uint32]*Base) {
|
||||
base.gameObject.render(camera, surface)
|
||||
if !base.gameObject.inView && !config.Server {
|
||||
delete(bases, base.ownerID)
|
||||
}
|
||||
}
|
||||
|
||||
func (base *Base) build(gameMap *GameMap) {
|
||||
@ -44,10 +50,10 @@ func (base *Base) build(gameMap *GameMap) {
|
||||
if base.gameObject.baseRect.H < 9 {
|
||||
panic("Bad border height")
|
||||
}
|
||||
if gameMap.width-base.gameObject.baseRect.X-base.gameObject.baseRect.W <= 0 {
|
||||
if gameMap.width-uint32(base.gameObject.baseRect.X)-uint32(base.gameObject.baseRect.W) <= 0 {
|
||||
panic("Bad base x location")
|
||||
}
|
||||
if gameMap.height-base.gameObject.baseRect.Y-base.gameObject.baseRect.H <= 0 {
|
||||
if gameMap.height-uint32(base.gameObject.baseRect.Y)-uint32(base.gameObject.baseRect.H) <= 0 {
|
||||
panic("Bad base y location")
|
||||
}
|
||||
if base.gameObject.baseRect.X < 0 || base.gameObject.baseRect.Y < 0 {
|
||||
@ -72,41 +78,59 @@ func (base *Base) build(gameMap *GameMap) {
|
||||
}
|
||||
}
|
||||
|
||||
func createBases(players *[]*Player, gameMap *GameMap) *[]*Base {
|
||||
bases := &[]*Base{}
|
||||
func createBase(gameMap *GameMap, baseColor color.Color, posX, posY, ownerID, openingWidth uint32) *Base {
|
||||
gameObject := &GameObject{}
|
||||
gameObject.baseRect = sdl.Rect{
|
||||
X: int32(posX),
|
||||
Y: int32(posY),
|
||||
W: 35,
|
||||
H: 35,
|
||||
}
|
||||
if openingWidth%2 == 0 {
|
||||
openingWidth++
|
||||
}
|
||||
|
||||
for ownerID, player := range *players {
|
||||
gameObject := &GameObject{}
|
||||
gameObject.baseRect = sdl.Rect{
|
||||
X: player.gameObject.baseRect.X - 14,
|
||||
Y: player.gameObject.baseRect.Y - 14,
|
||||
W: 35,
|
||||
H: 35,
|
||||
}
|
||||
openingWidth := int32(float64(player.gameObject.baseRect.W) * 1.5)
|
||||
if openingWidth%2 == 0 {
|
||||
openingWidth++
|
||||
}
|
||||
borderWidth := gameObject.baseRect.W - int32(openingWidth)
|
||||
borderWidthA := borderWidth / 2
|
||||
borderWidthB := borderWidth - borderWidthA + 1
|
||||
if borderWidth < 0 {
|
||||
panic("Bad border width")
|
||||
}
|
||||
gameObject.addColor(baseColor)
|
||||
gameObject.addColoredRect(0, 0, 1, gameObject.baseRect.H, 0)
|
||||
gameObject.addColoredRect(gameObject.baseRect.W, 0, 1, gameObject.baseRect.H, 0)
|
||||
gameObject.addColoredRect(0, 0, borderWidthA, 1, 0)
|
||||
gameObject.addColoredRect(borderWidthA+int32(openingWidth), 0, borderWidthB, 1, 0)
|
||||
gameObject.addColoredRect(0, gameObject.baseRect.H, borderWidthA, 1, 0)
|
||||
gameObject.addColoredRect(borderWidthA+int32(openingWidth), gameObject.baseRect.H, borderWidthB, 1, 0)
|
||||
base := &Base{
|
||||
gameObject: gameObject,
|
||||
ownerID: ownerID,
|
||||
openingWidth: int32(openingWidth),
|
||||
}
|
||||
base.build(gameMap)
|
||||
return base
|
||||
}
|
||||
|
||||
borderWidth := gameObject.baseRect.W - openingWidth
|
||||
borderWidthA := borderWidth / 2
|
||||
borderWidthB := borderWidth - borderWidthA + 1
|
||||
if borderWidth < 0 {
|
||||
panic("Bad border width")
|
||||
func (base *Base) delete(bases map[uint32]*Base) {
|
||||
for x := base.gameObject.baseRect.X; x < base.gameObject.baseRect.X+base.gameObject.baseRect.W+1; x++ {
|
||||
for y := base.gameObject.baseRect.Y; y < base.gameObject.baseRect.Y+base.gameObject.baseRect.H+1; y++ {
|
||||
gameMap.tiles[x][y] = 0
|
||||
}
|
||||
gameObject.addColor((*player).playerColors.body)
|
||||
gameObject.addColoredRect(0, 0, 1, gameObject.baseRect.H, 0)
|
||||
gameObject.addColoredRect(gameObject.baseRect.W, 0, 1, gameObject.baseRect.H, 0)
|
||||
gameObject.addColoredRect(0, 0, borderWidthA, 1, 0)
|
||||
gameObject.addColoredRect(borderWidthA+openingWidth, 0, borderWidthB, 1, 0)
|
||||
gameObject.addColoredRect(0, gameObject.baseRect.H, borderWidthA, 1, 0)
|
||||
gameObject.addColoredRect(borderWidthA+openingWidth, gameObject.baseRect.H, borderWidthB, 1, 0)
|
||||
*bases = append(*bases, &Base{
|
||||
gameObject: gameObject,
|
||||
owner: (*players)[ownerID],
|
||||
openingWidth: openingWidth,
|
||||
})
|
||||
(*bases)[ownerID].build(gameMap)
|
||||
}
|
||||
delete(bases, base.ownerID)
|
||||
}
|
||||
|
||||
func createBases(players map[uint32]*Player, gameMap *GameMap) map[uint32]*Base {
|
||||
bases := map[uint32]*Base{}
|
||||
for ownerID, player := range players {
|
||||
bases[ownerID] = createBase(gameMap,
|
||||
player.playerColors.body,
|
||||
uint32(player.gameObject.baseRect.X-14),
|
||||
uint32(player.gameObject.baseRect.Y-14),
|
||||
ownerID,
|
||||
uint32(float64(player.gameObject.baseRect.W)*1.5),
|
||||
)
|
||||
}
|
||||
return bases
|
||||
}
|
||||
|
60
bullet.go
60
bullet.go
@ -6,47 +6,53 @@ import (
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
var bulletLastID = uint32(0)
|
||||
var bulletParticleLastID = uint32(0)
|
||||
|
||||
type Bullet struct {
|
||||
posX, posY int32
|
||||
direction uint8
|
||||
color color.Color
|
||||
super bool
|
||||
id uint32
|
||||
}
|
||||
|
||||
type BulletParticle struct {
|
||||
posX, posY int32
|
||||
expirationTimer uint8
|
||||
expirationTimer uint32
|
||||
color color.Color
|
||||
id uint32
|
||||
}
|
||||
|
||||
func (bulletParticle *BulletParticle) render(camera *sdl.Rect, surface *sdl.Surface) {
|
||||
func (bulletParticle *BulletParticle) render(camera *sdl.Rect, surface *sdl.Surface, bulletParticles map[uint32]*BulletParticle) {
|
||||
if camera.IntersectLine(&bulletParticle.posX, &bulletParticle.posY, &bulletParticle.posX, &bulletParticle.posY) {
|
||||
relativeBulletX := bulletParticle.posX - camera.X
|
||||
relativeBulletY := bulletParticle.posY - camera.Y
|
||||
surface.Set(int(relativeBulletX), int(relativeBulletY), bulletParticle.color)
|
||||
} else if !config.Server {
|
||||
delete(bulletParticles, bulletParticle.id)
|
||||
}
|
||||
}
|
||||
|
||||
func (bulletParticle *BulletParticle) tick(particles *[]*BulletParticle) {
|
||||
func (bulletParticle *BulletParticle) tick(particles map[uint32]*BulletParticle) {
|
||||
if bulletParticle.expirationTimer <= 0 {
|
||||
for i, particle := range *particles {
|
||||
if particle == bulletParticle {
|
||||
*particles = append((*particles)[:i], (*particles)[i+1:]...)
|
||||
}
|
||||
}
|
||||
delete(particles, bulletParticle.id)
|
||||
} else {
|
||||
bulletParticle.expirationTimer--
|
||||
}
|
||||
bulletParticle.expirationTimer--
|
||||
}
|
||||
|
||||
func (bullet *Bullet) render(camera *sdl.Rect, surface *sdl.Surface) {
|
||||
func (bullet *Bullet) render(camera *sdl.Rect, surface *sdl.Surface, bullets map[uint32]*Bullet) {
|
||||
if camera.IntersectLine(&bullet.posX, &bullet.posY, &bullet.posX, &bullet.posY) {
|
||||
relativeBulletX := bullet.posX - camera.X
|
||||
relativeBulletY := bullet.posY - camera.Y
|
||||
surface.Set(int(relativeBulletX), int(relativeBulletY), bullet.color)
|
||||
} else if !config.Server {
|
||||
delete(bullets, bullet.id)
|
||||
}
|
||||
}
|
||||
|
||||
func (bullet *Bullet) explode(gameMap *GameMap, bulletParticleMap *[]*BulletParticle) {
|
||||
func (bullet *Bullet) explode(gameMap *GameMap, bulletParticleMap map[uint32]*BulletParticle) {
|
||||
// Define the possible directions with their x and y velocity components.
|
||||
directions := [][2]int{
|
||||
{0, -1}, // Up
|
||||
@ -75,13 +81,15 @@ func (bullet *Bullet) explode(gameMap *GameMap, bulletParticleMap *[]*BulletPart
|
||||
|
||||
// Check for collision and bullet behavior (normal or super).
|
||||
if collision == 1 || collision == 0 || (bullet.super && collision == 2) {
|
||||
*bulletParticleMap = append(*bulletParticleMap, &BulletParticle{
|
||||
bulletParticleMap[bulletParticleLastID] = &BulletParticle{
|
||||
posX: xPos,
|
||||
posY: yPos,
|
||||
expirationTimer: uint8(5 + rand.Intn(10)), // Randomize expiration time between 15 and 25.
|
||||
expirationTimer: uint32(5 + rand.Intn(10)), // Randomize expiration time between 15 and 25.
|
||||
color: bullet.color,
|
||||
})
|
||||
if xPos > 0 && yPos > 0 && xPos < MapWidth && yPos < MapHeight {
|
||||
id: bulletParticleLastID,
|
||||
}
|
||||
bulletParticleLastID++
|
||||
if xPos > 0 && yPos > 0 && uint32(xPos) < serverConfig.MapWidth && uint32(yPos) < serverConfig.MapHeight {
|
||||
gameMap.tiles[xPos][yPos] = 0
|
||||
}
|
||||
}
|
||||
@ -93,12 +101,14 @@ func (bullet *Bullet) explode(gameMap *GameMap, bulletParticleMap *[]*BulletPart
|
||||
xPos, yPos := bullet.posX+int32(xOffset), bullet.posY+int32(yOffset)
|
||||
collision := gameMap.checkCollision(xPos, yPos)
|
||||
if collision == 1 || collision == 0 || (bullet.super && collision == 2) {
|
||||
*bulletParticleMap = append(*bulletParticleMap, &BulletParticle{
|
||||
bulletParticleMap[bulletParticleLastID] = &BulletParticle{
|
||||
posX: xPos,
|
||||
posY: yPos,
|
||||
expirationTimer: uint8(15 + rand.Intn(15)),
|
||||
expirationTimer: uint32(15 + rand.Intn(15)),
|
||||
color: bullet.color,
|
||||
})
|
||||
id: bulletParticleLastID,
|
||||
}
|
||||
bulletParticleLastID++
|
||||
gameMap.tiles[xPos][yPos] = 0
|
||||
}
|
||||
}
|
||||
@ -107,7 +117,7 @@ func (bullet *Bullet) explode(gameMap *GameMap, bulletParticleMap *[]*BulletPart
|
||||
}
|
||||
|
||||
func (bullet *Bullet) tick(gameMap *GameMap,
|
||||
bulletParticleMap *[]*BulletParticle, bulletMap *[]*Bullet, players *[]*Player) {
|
||||
bulletParticleMap map[uint32]*BulletParticle, bulletMap map[uint32]*Bullet, players map[uint32]*Player) {
|
||||
var nextX, nextY int32
|
||||
nextX, nextY = bullet.posX, bullet.posY
|
||||
switch bullet.direction {
|
||||
@ -148,13 +158,13 @@ func (bullet *Bullet) tick(gameMap *GameMap,
|
||||
H: 1,
|
||||
}
|
||||
hitPlayer := false
|
||||
for _, player := range *players {
|
||||
for _, player := range players {
|
||||
if hitPlayer {
|
||||
break
|
||||
}
|
||||
for _, coloredRect := range player.gameObject.getCurrentRects() {
|
||||
if coloredRect.rect.HasIntersection(&bulletRect) {
|
||||
hitPlayer = true
|
||||
if player.gameObject.adjustRectWorld(coloredRect.rect).HasIntersection(&bulletRect) {
|
||||
hitPlayer = player.shields <= serverConfig.MaxShields
|
||||
player.shields -= 10
|
||||
break
|
||||
}
|
||||
@ -162,11 +172,7 @@ func (bullet *Bullet) tick(gameMap *GameMap,
|
||||
}
|
||||
if collisionResult != 0 || hitPlayer {
|
||||
bullet.explode(gameMap, bulletParticleMap)
|
||||
for i, bulletInMap := range *bulletMap {
|
||||
if bulletInMap == bullet {
|
||||
*bulletMap = append((*bulletMap)[:i], (*bulletMap)[i+1:]...)
|
||||
}
|
||||
}
|
||||
delete(bulletMap, bullet.id)
|
||||
} else {
|
||||
bullet.posX = nextX
|
||||
bullet.posY = nextY
|
||||
|
@ -6,11 +6,13 @@ import (
|
||||
)
|
||||
|
||||
type GameObject struct {
|
||||
baseRect sdl.Rect
|
||||
borderRect sdl.Rect
|
||||
orientation uint8
|
||||
visualRects [][]*ColoredRect
|
||||
colors []color.Color
|
||||
baseRect sdl.Rect
|
||||
prevBaseRect sdl.Rect
|
||||
borderRect sdl.Rect
|
||||
orientation uint8
|
||||
visualRects [][]*ColoredRect
|
||||
colors []color.Color
|
||||
inView bool
|
||||
}
|
||||
|
||||
type ColoredRect struct {
|
||||
@ -27,6 +29,15 @@ func adjustRectToCamera(object *sdl.Rect, camera *sdl.Rect) *sdl.Rect {
|
||||
}
|
||||
}
|
||||
|
||||
func (gameObject *GameObject) adjustRectWorld(offset *sdl.Rect) *sdl.Rect {
|
||||
return &sdl.Rect{
|
||||
X: gameObject.baseRect.X + offset.X,
|
||||
Y: gameObject.baseRect.Y + offset.Y,
|
||||
W: offset.W,
|
||||
H: offset.H,
|
||||
}
|
||||
}
|
||||
|
||||
func (gameObject *GameObject) adjustRectToCamera(offset *sdl.Rect, camera *sdl.Rect) *sdl.Rect {
|
||||
return &sdl.Rect{
|
||||
X: gameObject.baseRect.X + offset.X - camera.X,
|
||||
@ -38,7 +49,8 @@ func (gameObject *GameObject) adjustRectToCamera(offset *sdl.Rect, camera *sdl.R
|
||||
|
||||
func (gameObject *GameObject) render(camera *sdl.Rect, surface *sdl.Surface) {
|
||||
if camera.HasIntersection(&gameObject.baseRect) {
|
||||
if Debug {
|
||||
gameObject.inView = true
|
||||
if config.Debug {
|
||||
gameObject.borderRect = sdl.Rect{
|
||||
X: gameObject.baseRect.X - 1,
|
||||
Y: gameObject.baseRect.Y - 1,
|
||||
@ -50,13 +62,15 @@ func (gameObject *GameObject) render(camera *sdl.Rect, surface *sdl.Surface) {
|
||||
surface.FillRect(borderRectFinal, sdl.MapRGBA(surface.Format, 20, 192, 128, 64))
|
||||
surface.FillRect(baseRectFinal, sdl.MapRGBA(surface.Format, 255, 20, 10, 64))
|
||||
}
|
||||
if RenderGameObjects {
|
||||
if config.RenderGameObjects {
|
||||
for _, coloredRect := range gameObject.visualRects[gameObject.orientation] {
|
||||
finalRect := gameObject.adjustRectToCamera(coloredRect.rect, camera)
|
||||
r, g, b, a := coloredRect.color.RGBA()
|
||||
surface.FillRect(finalRect, sdl.MapRGBA(surface.Format, uint8(r), uint8(g), uint8(b), uint8(a)))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gameObject.inView = false
|
||||
}
|
||||
}
|
||||
|
||||
|
1
go.mod
1
go.mod
@ -5,4 +5,5 @@ go 1.21
|
||||
require (
|
||||
github.com/aquilax/go-perlin v1.1.0
|
||||
github.com/veandco/go-sdl2 v0.4.40
|
||||
google.golang.org/protobuf v1.34.2
|
||||
)
|
||||
|
6
go.sum
6
go.sum
@ -1,4 +1,10 @@
|
||||
github.com/aquilax/go-perlin v1.1.0 h1:Gg+3jQ24wT4Y5GI7TCRLmYarzUG0k+n/JATFqOimb7s=
|
||||
github.com/aquilax/go-perlin v1.1.0/go.mod h1:z9Rl7EM4BZY0Ikp2fEN1I5mKSOJ26HQpk0O2TBdN2HE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/veandco/go-sdl2 v0.4.40 h1:fZv6wC3zz1Xt167P09gazawnpa0KY5LM7JAvKpX9d/U=
|
||||
github.com/veandco/go-sdl2 v0.4.40/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
|
13
graphics.go
13
graphics.go
@ -27,13 +27,12 @@ func setupWindowAndSurface(playerIndex uint8) (*sdl.Window, *sdl.Surface) {
|
||||
}
|
||||
|
||||
func setupMapWindowAndSurface() (*sdl.Window, *sdl.Surface) {
|
||||
const windowWidth, windowHeight = MapWidth, MapHeight
|
||||
window, err := sdl.CreateWindow("Tunneler map", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, windowWidth, windowHeight, sdl.WINDOW_SHOWN|sdl.WINDOW_RESIZABLE)
|
||||
window, err := sdl.CreateWindow("Tunneler map", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, int32(serverConfig.MapWidth), int32(serverConfig.MapWidth), sdl.WINDOW_SHOWN|sdl.WINDOW_RESIZABLE)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
logicalSurface, err := sdl.CreateRGBSurface(0, windowWidth, windowHeight, 32, 0, 0, 0, 0)
|
||||
logicalSurface, err := sdl.CreateRGBSurface(0, int32(serverConfig.MapWidth), int32(serverConfig.MapWidth), 32, 0, 0, 0, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -42,12 +41,12 @@ func setupMapWindowAndSurface() (*sdl.Window, *sdl.Surface) {
|
||||
}
|
||||
|
||||
func setupPlaySurface() (*sdl.Surface, *sdl.Rect, *sdl.Rect) {
|
||||
playSurface, err := sdl.CreateRGBSurface(0, 76, 76, 32, 0, 0, 0, 0)
|
||||
playSurface, err := sdl.CreateRGBSurface(0, config.CameraW, config.CameraH, 32, 0, 0, 0, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
playSurfaceRect := &sdl.Rect{X: 0, Y: 0, W: 76, H: 76}
|
||||
playSurfaceTargetRect := &sdl.Rect{X: 42, Y: 0, W: 76, H: 76}
|
||||
playSurfaceRect := &sdl.Rect{X: 0, Y: 0, W: config.CameraW, H: config.CameraH}
|
||||
playSurfaceTargetRect := &sdl.Rect{X: 42, Y: 0, W: config.CameraW, H: config.CameraH}
|
||||
|
||||
return playSurface, playSurfaceRect, playSurfaceTargetRect
|
||||
}
|
||||
@ -58,7 +57,7 @@ func setupHUDSurface() (*sdl.Surface, *sdl.Rect, *sdl.Rect) {
|
||||
panic(err)
|
||||
}
|
||||
HUDSurfaceRect := &sdl.Rect{X: 0, Y: 0, W: 112, H: 25}
|
||||
HUDSurfaceTargetRect := &sdl.Rect{X: 24, Y: 76, W: 112, H: 25}
|
||||
HUDSurfaceTargetRect := &sdl.Rect{X: 24, Y: config.CameraH, W: 112, H: 25}
|
||||
|
||||
return HUDSurface, HUDSurfaceRect, HUDSurfaceTargetRect
|
||||
}
|
||||
|
8
hud.go
8
hud.go
@ -11,7 +11,7 @@ var letterOffsets = []int32{
|
||||
var letterColors []uint32
|
||||
|
||||
// Map function to convert value from range [0, 6] to range [0, 88]
|
||||
func mapRange(x, minX, maxX, minY, maxY uint16) int32 {
|
||||
func mapRange(x, minX, maxX, minY, maxY uint32) int32 {
|
||||
// Perform conversion to float64 to ensure proper division
|
||||
return int32((float64(x-minX)/float64(maxX-minX))*float64(maxY-minY) + float64(minY))
|
||||
}
|
||||
@ -66,9 +66,9 @@ func renderHud(player *Player, surface *sdl.Surface) {
|
||||
}
|
||||
|
||||
HUDValues := []int32{
|
||||
mapRange(player.energy, 0, MaxEnergy, 0, 88),
|
||||
mapRange(player.ammunition, 0, MaxAmmunition, 0, 88),
|
||||
mapRange(player.shields, 0, MaxShields, 0, 88),
|
||||
mapRange(player.energy, 0, serverConfig.MaxEnergy, 0, 88),
|
||||
mapRange(player.ammunition, 0, serverConfig.MaxAmmunition, 0, 88),
|
||||
mapRange(player.shields, 0, serverConfig.MaxShields, 0, 88),
|
||||
}
|
||||
|
||||
for HUDValueIndex, HUDValue := range HUDValues {
|
||||
|
341
main.go
341
main.go
@ -1,74 +1,213 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
MapWidth = 1000 // Width of the map
|
||||
MapHeight = 1000 // Height of the map
|
||||
BlastRadius = 5
|
||||
type ServerConfig struct {
|
||||
MapWidth uint32
|
||||
MapHeight uint32
|
||||
BlastRadius uint32
|
||||
|
||||
MaxEnergy = 3520
|
||||
MaxAmmunition = 6
|
||||
MaxShields = 100
|
||||
MaxEnergy uint32
|
||||
MaxAmmunition uint32
|
||||
MaxShields uint32
|
||||
|
||||
NormalShotCost = 7
|
||||
SuperShotCost = 80
|
||||
ReloadCost = 4
|
||||
MovementCost = 1
|
||||
DiggingCost = 3
|
||||
ShootDiggingCostBonus = 1
|
||||
NormalShotCost uint32
|
||||
SuperShotCost uint32
|
||||
ReloadCost uint32
|
||||
MovementCost uint32
|
||||
DiggingCost uint32
|
||||
ShootDiggingCostBonus uint32
|
||||
|
||||
ShootCooldown = 8
|
||||
RechargeCooldownOwn = 0
|
||||
DiggingCooldown = 4
|
||||
RechargeCooldownOpponent = 6
|
||||
RepairCooldown = 4
|
||||
MovementCooldown = 2
|
||||
MovementCooldownNoEnergy = 4
|
||||
DiggingCooldownNoEnergy = 8
|
||||
ReloadCooldown = 16
|
||||
ShootCooldown uint32
|
||||
RechargeCooldownOwn uint32
|
||||
DiggingCooldown uint32
|
||||
RechargeCooldownOpponent uint32
|
||||
RepairCooldown uint32
|
||||
MovementCooldown uint32
|
||||
MovementCooldownNoEnergy uint32
|
||||
DiggingCooldownNoEnergy uint32
|
||||
ReloadCooldown uint32
|
||||
}
|
||||
|
||||
Debug = false
|
||||
MapWindow = false
|
||||
RenderGameObjects = true
|
||||
ProfilerOn = true
|
||||
ProfilerInterval = 100
|
||||
type Config struct {
|
||||
Debug bool `json:"debug"`
|
||||
MapWindow bool `json:"map_window"`
|
||||
RenderGameObjects bool `json:"render_game_objects"`
|
||||
ProfilerOn bool `json:"profiler_on"`
|
||||
ProfilerInterval uint64 `json:"profiler_interval"`
|
||||
Server bool `json:"server"`
|
||||
CameraW int32 `json:"camera_w"`
|
||||
CameraH int32 `json:"camera_h"`
|
||||
Version string `json:"version"`
|
||||
Client bool `json:"client"`
|
||||
Address string `json:"address"`
|
||||
JoyStickDeadZone int16 `json:"joystick_dead_zone"`
|
||||
DoAllKeymapsPlayers bool `json:"do_all_keymaps_players"`
|
||||
DoJoyStickPlayers bool `json:"do_joystick_players"`
|
||||
DoKeymapPlayer bool `json:"do_keymap_player"`
|
||||
}
|
||||
|
||||
JoyStickDeadZone = 8000
|
||||
func loadOrCreateConfig(filename string) (*Config, error) {
|
||||
config := &Config{
|
||||
Debug: false,
|
||||
MapWindow: false,
|
||||
RenderGameObjects: true,
|
||||
ProfilerOn: false,
|
||||
ProfilerInterval: 100,
|
||||
Server: false,
|
||||
CameraW: 76,
|
||||
CameraH: 76,
|
||||
Version: "69420",
|
||||
Client: true,
|
||||
Address: "192.168.1.8:5074",
|
||||
JoyStickDeadZone: 8000,
|
||||
DoAllKeymapsPlayers: false,
|
||||
DoJoyStickPlayers: true,
|
||||
DoKeymapPlayer: true,
|
||||
}
|
||||
|
||||
DoAllKeymapsPlayers = false
|
||||
DoJoyStickPlayers = true
|
||||
DoKeymapPlayer = true
|
||||
)
|
||||
// Check if the file exists
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
// File does not exist, create it with the default config
|
||||
data, err := json.MarshalIndent(config, "", " ")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal config: %v", err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(filename, data, 0644)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to write config file: %v", err)
|
||||
}
|
||||
fmt.Println("Config file created with default values.")
|
||||
} else {
|
||||
// File exists, load the config
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read config file: %v", err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal config: %v", err)
|
||||
}
|
||||
fmt.Println("Config file loaded.")
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
var config *Config
|
||||
|
||||
var gameMap = &GameMap{}
|
||||
|
||||
var serverConfig = ServerConfig{
|
||||
MapWidth: 1000,
|
||||
MapHeight: 1000,
|
||||
BlastRadius: 5,
|
||||
|
||||
MaxEnergy: 3520,
|
||||
MaxAmmunition: 6,
|
||||
MaxShields: 100,
|
||||
|
||||
NormalShotCost: 7,
|
||||
SuperShotCost: 80,
|
||||
ReloadCost: 4,
|
||||
MovementCost: 1,
|
||||
DiggingCost: 3,
|
||||
ShootDiggingCostBonus: 1,
|
||||
|
||||
ShootCooldown: 8,
|
||||
RechargeCooldownOwn: 0,
|
||||
DiggingCooldown: 4,
|
||||
RechargeCooldownOpponent: 6,
|
||||
RepairCooldown: 4,
|
||||
MovementCooldown: 2,
|
||||
MovementCooldownNoEnergy: 4,
|
||||
DiggingCooldownNoEnergy: 8,
|
||||
ReloadCooldown: 16,
|
||||
}
|
||||
|
||||
var mapWindow *sdl.Window
|
||||
var mapSurface *sdl.Surface
|
||||
var mapRendererRect = &sdl.Rect{X: 0, Y: 0, W: MapWidth, H: MapHeight}
|
||||
var mapRendererRect = &sdl.Rect{X: 0, Y: 0, W: int32(serverConfig.MapWidth), H: int32(serverConfig.MapHeight)}
|
||||
|
||||
var netPlayerMapper = map[*net.Conn]*Player{}
|
||||
|
||||
var clientInitialized = false
|
||||
|
||||
var worldLock sync.Mutex
|
||||
|
||||
func main() {
|
||||
initializeSDL()
|
||||
defer sdl.Quit()
|
||||
|
||||
gameMap := &GameMap{}
|
||||
gameMap.createGameMap(MapWidth, MapHeight)
|
||||
|
||||
players := &[]*Player{}
|
||||
configX, err := loadOrCreateConfig("config.json")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
config = configX
|
||||
players := make(map[uint32]*Player)
|
||||
initPlayerColors()
|
||||
createPlayers(getNeededPlayers(), playerColors, keyMaps, joyMaps, gameMap, players)
|
||||
bullets := make(map[uint32]*Bullet)
|
||||
bulletParticles := make(map[uint32]*BulletParticle)
|
||||
bases := make(map[uint32]*Base)
|
||||
|
||||
if config.Client && config.Server {
|
||||
panic("You can' t run client and server in the same instance")
|
||||
}
|
||||
|
||||
if !config.Client {
|
||||
gameMap.createGameMap(true)
|
||||
createPlayers(getNeededPlayers(), playerColors, keyMaps, joyMaps, gameMap, players)
|
||||
bases = createBases(players, gameMap)
|
||||
} else {
|
||||
// Create a connection to the server
|
||||
conn, err := net.Dial("tcp", config.Address)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to connect to server: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
go handleConnectionClient(&conn, players, bases, bullets, bulletParticles)
|
||||
for !clientInitialized {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
defer closeThings(players)
|
||||
|
||||
bases := createBases(players, gameMap)
|
||||
|
||||
bullets := &[]*Bullet{}
|
||||
bulletParticles := &[]*BulletParticle{}
|
||||
|
||||
for playerIndex, player := range *players {
|
||||
for playerIndex, player := range players {
|
||||
initPlayer(uint8(playerIndex), player)
|
||||
}
|
||||
if MapWindow {
|
||||
|
||||
if config.Server {
|
||||
listen, err := net.Listen("tcp", "0.0.0.0:5074")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// close listener
|
||||
defer listen.Close()
|
||||
go func() {
|
||||
for {
|
||||
conn, err := listen.Accept()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
go handleRequest(conn, players, bullets, bases)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if config.MapWindow {
|
||||
mapWindow, mapSurface = setupMapWindowAndSurface()
|
||||
}
|
||||
running := true
|
||||
@ -82,6 +221,7 @@ func main() {
|
||||
currentTime := sdl.GetTicks64()
|
||||
deltaTime := currentTime - prevTime
|
||||
prevTime = currentTime
|
||||
worldLock.Lock()
|
||||
|
||||
// Catch up in case of a large delta time
|
||||
for deltaTime > maxDeltaTime {
|
||||
@ -91,34 +231,34 @@ func main() {
|
||||
runGameLogic(players, gameMap, bases, bullets, bulletParticles)
|
||||
}
|
||||
|
||||
for playerIndex, player := range *players {
|
||||
// Run logic for the remaining delta time
|
||||
runGameLogic(players, gameMap, bases, bullets, bulletParticles)
|
||||
|
||||
for playerIndex, player := range players {
|
||||
if player.local {
|
||||
running := doPlayerFrame(uint8(playerIndex), player, players, gameMap, bases, bullets, bulletParticles)
|
||||
running = doPlayerFrame(uint8(playerIndex), player, players, gameMap, bases, bullets, bulletParticles)
|
||||
if !running {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run logic for the remaining delta time
|
||||
runGameLogic(players, gameMap, bases, bullets, bulletParticles)
|
||||
|
||||
// Render logic
|
||||
if MapWindow {
|
||||
if config.MapWindow {
|
||||
// Profile rendering (aggregate all renderings)
|
||||
totalRenderTime += profileSection(func() {
|
||||
gameMap.render(mapRendererRect, mapSurface)
|
||||
for _, bullet := range *bullets {
|
||||
(*bullet).render(mapRendererRect, mapSurface)
|
||||
for _, bullet := range bullets {
|
||||
(*bullet).render(mapRendererRect, mapSurface, bullets)
|
||||
}
|
||||
for _, base := range *bases {
|
||||
(*base).render(mapRendererRect, mapSurface)
|
||||
for _, base := range bases {
|
||||
(*base).render(mapRendererRect, mapSurface, bases)
|
||||
}
|
||||
for _, playerLoop := range *players {
|
||||
(*playerLoop).render(mapRendererRect, mapSurface)
|
||||
for _, playerLoop := range players {
|
||||
(*playerLoop).render(mapRendererRect, mapSurface, players)
|
||||
}
|
||||
for _, bulletParticle := range *bulletParticles {
|
||||
bulletParticle.render(mapRendererRect, mapSurface)
|
||||
for _, bulletParticle := range bulletParticles {
|
||||
bulletParticle.render(mapRendererRect, mapSurface, bulletParticles)
|
||||
}
|
||||
})
|
||||
totalScalingTime += profileSection(func() {
|
||||
@ -131,30 +271,70 @@ func main() {
|
||||
frameCount++
|
||||
|
||||
// Log profiling information every 1000 frames
|
||||
if frameCount%ProfilerInterval == 0 && ProfilerOn {
|
||||
if frameCount%config.ProfilerInterval == 0 && config.ProfilerOn {
|
||||
logMapProfilingInfo(totalRenderTime, totalScalingTime, totalFrameTime, frameCount)
|
||||
resetMapProfilingCounters(&totalRenderTime, &totalScalingTime, &totalFrameTime, &frameCount)
|
||||
}
|
||||
|
||||
worldLock.Unlock()
|
||||
enforceFrameRate(currentTime, 60)
|
||||
}
|
||||
}
|
||||
|
||||
// Separate function to handle game logic
|
||||
func runGameLogic(players *[]*Player, gameMap *GameMap, bases *[]*Base, bullets *[]*Bullet, bulletParticles *[]*BulletParticle) {
|
||||
func runGameLogic(players map[uint32]*Player, gameMap *GameMap, bases map[uint32]*Base, bullets map[uint32]*Bullet, bulletParticles map[uint32]*BulletParticle) {
|
||||
// Tick world
|
||||
for _, bullet := range *bullets {
|
||||
|
||||
if config.Server {
|
||||
//update remote player maps
|
||||
for _, player := range players {
|
||||
if player.local {
|
||||
continue
|
||||
}
|
||||
go player.updateRemotePlayerMap()
|
||||
go player.updateRemotePlayerBases(bases)
|
||||
go player.updateRemotePlayerBullets(bullets)
|
||||
go player.updateRemotePlayerBulletParticles(bulletParticles)
|
||||
go player.updateRemotePlayerPlayers(players)
|
||||
fail := player.sendInfoToPlayer()
|
||||
if fail {
|
||||
if player.connection != nil {
|
||||
(*player.connection).Close()
|
||||
}
|
||||
delete(players, player.playerID)
|
||||
continue
|
||||
}
|
||||
fail = player.sendUpdatesToPlayer(players)
|
||||
if fail {
|
||||
if player.connection != nil {
|
||||
(*player.connection).Close()
|
||||
}
|
||||
delete(players, player.playerID)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, bullet := range bullets {
|
||||
(*bullet).tick(gameMap, bulletParticles, bullets, players)
|
||||
}
|
||||
for _, base := range *bases {
|
||||
for _, player := range players {
|
||||
if player.local {
|
||||
continue
|
||||
}
|
||||
(*player).tick(bullets)
|
||||
}
|
||||
for _, base := range bases {
|
||||
(*base).tick(players)
|
||||
}
|
||||
for _, bulletParticle := range *bulletParticles {
|
||||
for _, bulletParticle := range bulletParticles {
|
||||
bulletParticle.tick(bulletParticles)
|
||||
}
|
||||
}
|
||||
|
||||
func initPlayer(playerIndex uint8, player *Player) {
|
||||
if !player.local {
|
||||
return
|
||||
}
|
||||
player.window, player.logicalSurface = setupWindowAndSurface(playerIndex)
|
||||
logicalColor := sdl.MapRGBA(player.logicalSurface.Format, 101, 101, 0, 255)
|
||||
player.logicalSurface.FillRect(nil, logicalColor)
|
||||
@ -165,13 +345,13 @@ func initPlayer(playerIndex uint8, player *Player) {
|
||||
|
||||
player.HUDSurface, player.HUDSurfaceRect, player.HUDSurfaceTargetRect = setupHUDSurface()
|
||||
initHud(player.HUDSurface)
|
||||
player.camera = &sdl.Rect{X: 0, Y: 0, W: 76, H: 76}
|
||||
player.camera = &sdl.Rect{X: 0, Y: 0, W: config.CameraW, H: config.CameraH}
|
||||
}
|
||||
|
||||
func doPlayerFrame(playerIndex uint8, player *Player, players *[]*Player, gameMap *GameMap, bases *[]*Base, bullets *[]*Bullet, bulletParticles *[]*BulletParticle) bool {
|
||||
func doPlayerFrame(playerIndex uint8, player *Player, players map[uint32]*Player, gameMap *GameMap, bases map[uint32]*Base, bullets map[uint32]*Bullet, bulletParticles map[uint32]*BulletParticle) bool {
|
||||
running := true
|
||||
var (
|
||||
isShooting, shouldContinue bool
|
||||
shouldContinue bool
|
||||
)
|
||||
frameStart := sdl.GetTicks64()
|
||||
|
||||
@ -179,7 +359,7 @@ func doPlayerFrame(playerIndex uint8, player *Player, players *[]*Player, gameMa
|
||||
player.totalHandleEventsTime += profileSection(func() {
|
||||
running = handleEvents(player.window, player.logicalSurface)
|
||||
keyboard := sdl.GetKeyboardState()
|
||||
shouldContinue, isShooting = handleInput(keyboard, bullets, player, gameMap, players)
|
||||
shouldContinue = handleInput(keyboard, bullets, player, gameMap, players)
|
||||
running = running && shouldContinue
|
||||
})
|
||||
|
||||
@ -188,20 +368,21 @@ func doPlayerFrame(playerIndex uint8, player *Player, players *[]*Player, gameMa
|
||||
player.track(player.camera)
|
||||
gameMap.render(player.camera, player.playSurface)
|
||||
|
||||
for _, bullet := range *bullets {
|
||||
(*bullet).render(player.camera, player.playSurface)
|
||||
for _, bullet := range bullets {
|
||||
(*bullet).render(player.camera, player.playSurface, bullets)
|
||||
}
|
||||
for _, base := range *bases {
|
||||
(*base).render(player.camera, player.playSurface)
|
||||
for _, base := range bases {
|
||||
(*base).render(player.camera, player.playSurface, bases)
|
||||
}
|
||||
for _, playerLoop := range *players {
|
||||
(*playerLoop).render(player.camera, player.playSurface)
|
||||
for _, playerLoop := range players {
|
||||
(*playerLoop).render(player.camera, player.playSurface, players)
|
||||
}
|
||||
for _, bulletParticle := range *bulletParticles {
|
||||
bulletParticle.render(player.camera, player.playSurface)
|
||||
for _, bulletParticle := range bulletParticles {
|
||||
bulletParticle.render(player.camera, player.playSurface, bulletParticles)
|
||||
}
|
||||
|
||||
player.tick(isShooting, bullets, player.playSurface.Format)
|
||||
player.tick(bullets)
|
||||
player.gameObject.prevBaseRect = player.gameObject.baseRect
|
||||
renderHud(player, player.HUDSurface)
|
||||
player.playSurface.BlitScaled(player.playSurfaceRect, player.logicalSurface, player.playSurfaceTargetRect)
|
||||
player.HUDSurface.BlitScaled(player.HUDSurfaceRect, player.logicalSurface, player.HUDSurfaceTargetRect)
|
||||
@ -217,7 +398,7 @@ func doPlayerFrame(playerIndex uint8, player *Player, players *[]*Player, gameMa
|
||||
player.frameCount++
|
||||
|
||||
// Log profiling information every 1000 frames
|
||||
if player.frameCount%ProfilerInterval == 0 && ProfilerOn && playerIndex == 0 {
|
||||
if player.frameCount%config.ProfilerInterval == 0 && config.ProfilerOn && playerIndex == 0 {
|
||||
logProfilingInfo(player.totalHandleEventsTime, player.totalRenderTime, player.totalScalingTime, player.totalFrameTime, player.frameCount)
|
||||
resetProfilingCounters(&player.totalHandleEventsTime, &player.totalRenderTime, &player.totalScalingTime, &player.totalFrameTime, &player.frameCount)
|
||||
}
|
||||
|
59
map.go
59
map.go
@ -16,8 +16,8 @@ type GameMap struct {
|
||||
//tile 3 - soil 2
|
||||
//tile 4 - base
|
||||
//tile 5 - world edge (should not be present in the map object)
|
||||
width int32
|
||||
height int32
|
||||
width uint32
|
||||
height uint32
|
||||
}
|
||||
|
||||
func GetTileColorValue(value uint8) color.Color {
|
||||
@ -40,7 +40,7 @@ func GetTileColorValue(value uint8) color.Color {
|
||||
}
|
||||
|
||||
func (gameMap *GameMap) getTileColor(x int32, y int32) color.Color {
|
||||
if x < 0 || x >= gameMap.width || y < 0 || y >= gameMap.height {
|
||||
if x < 0 || x >= int32(gameMap.width) || y < 0 || y >= int32(gameMap.height) {
|
||||
return GetTileColorValue(5)
|
||||
} else {
|
||||
tileValue := gameMap.tiles[x][y]
|
||||
@ -48,10 +48,9 @@ func (gameMap *GameMap) getTileColor(x int32, y int32) color.Color {
|
||||
}
|
||||
}
|
||||
|
||||
func (gameMap *GameMap) createGameMap(width int32, height int32) {
|
||||
func (gameMap *GameMap) createGameMap(withData bool) {
|
||||
// Initialize the 2D slice for game tiles
|
||||
gameMap.tiles = make([][]uint8, width)
|
||||
|
||||
gameMap.tiles = make([][]uint8, serverConfig.MapWidth)
|
||||
// Create Perlin noise generators
|
||||
perlinNoiseRock := perlin.NewPerlin(2, 4, 8, time.Now().Unix())
|
||||
perlinNoiseSoil := perlin.NewPerlin(2, 8, 4, time.Now().Unix())
|
||||
@ -61,39 +60,45 @@ func (gameMap *GameMap) createGameMap(width int32, height int32) {
|
||||
|
||||
// Loop over the rows
|
||||
for i := range gameMap.tiles {
|
||||
// Increment WaitGroup counter for each goroutine
|
||||
wg.Add(1)
|
||||
|
||||
// Launch a goroutine for each row
|
||||
go func(i int) {
|
||||
defer wg.Done() // Signal that this goroutine is done
|
||||
if withData {
|
||||
// Launch a goroutine for each row
|
||||
// Increment WaitGroup counter for each goroutine
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
defer wg.Done() // Signal that this goroutine is done
|
||||
|
||||
// Initialize the row
|
||||
gameMap.tiles[i] = make([]uint8, height)
|
||||
// Initialize the row
|
||||
gameMap.tiles[i] = make([]uint8, serverConfig.MapHeight)
|
||||
|
||||
// Process each tile in the row
|
||||
for j := range gameMap.tiles[i] {
|
||||
perlinRock := perlinNoiseRock.Noise2D(float64(i)/float64(width)*6, float64(j)/float64(height)*6)
|
||||
if perlinRock > 0.2 {
|
||||
gameMap.tiles[i][j] = 1
|
||||
} else {
|
||||
perlinSoil := perlinNoiseSoil.Noise2D(float64(i)/float64(width)*10, float64(j)/float64(height)*10)
|
||||
if perlinSoil >= 0 {
|
||||
gameMap.tiles[i][j] = 2
|
||||
// Process each tile in the row
|
||||
for j := range gameMap.tiles[i] {
|
||||
perlinRock := perlinNoiseRock.Noise2D(float64(i)/float64(serverConfig.MapWidth)*6, float64(j)/float64(serverConfig.MapHeight)*6)
|
||||
if perlinRock > 0.2 {
|
||||
gameMap.tiles[i][j] = 1
|
||||
} else {
|
||||
gameMap.tiles[i][j] = 3
|
||||
perlinSoil := perlinNoiseSoil.Noise2D(float64(i)/float64(serverConfig.MapWidth)*10, float64(j)/float64(serverConfig.MapHeight)*10)
|
||||
if perlinSoil >= 0 {
|
||||
gameMap.tiles[i][j] = 2
|
||||
} else {
|
||||
gameMap.tiles[i][j] = 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
} else {
|
||||
for x := uint32(0); x < serverConfig.MapWidth; x++ {
|
||||
gameMap.tiles[x] = make([]uint8, serverConfig.MapHeight)
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for all goroutines to finish
|
||||
wg.Wait()
|
||||
|
||||
// Set the dimensions of the game map
|
||||
gameMap.width = width
|
||||
gameMap.height = height
|
||||
gameMap.width = serverConfig.MapWidth
|
||||
gameMap.height = serverConfig.MapHeight
|
||||
}
|
||||
|
||||
func (gameMap *GameMap) render(camera *sdl.Rect, surface *sdl.Surface) {
|
||||
@ -131,7 +136,7 @@ func (gameMap *GameMap) checkCollision(posX, posY int32) uint8 {
|
||||
//1 destructible collision
|
||||
//2 rock collision
|
||||
//3 indestructible collision
|
||||
if posX >= gameMap.width || posX < 0 || posY >= gameMap.height || posY < 0 {
|
||||
if posX >= int32(gameMap.width) || posX < 0 || posY >= int32(gameMap.height) || posY < 0 {
|
||||
return 3
|
||||
}
|
||||
switch gameMap.tiles[posX][posY] {
|
||||
|
@ -74,15 +74,15 @@ type PlayerColors struct {
|
||||
|
||||
func getNeededPlayers() (neededPlayers uint8) {
|
||||
neededPlayers = 0
|
||||
if DoAllKeymapsPlayers {
|
||||
if config.DoAllKeymapsPlayers {
|
||||
neededPlayers += uint8(len(keyMaps))
|
||||
} else if DoKeymapPlayer && len(keyMaps) > 0 {
|
||||
} else if config.DoKeymapPlayer && len(keyMaps) > 0 {
|
||||
neededPlayers++
|
||||
}
|
||||
if DoJoyStickPlayers {
|
||||
if config.DoJoyStickPlayers {
|
||||
neededPlayers += uint8(sdl.NumJoysticks())
|
||||
}
|
||||
if neededPlayers < 2 {
|
||||
if neededPlayers < 2 && !config.Server {
|
||||
neededPlayers = 2
|
||||
}
|
||||
return neededPlayers
|
||||
@ -285,9 +285,9 @@ func initPlayerColors() {
|
||||
}
|
||||
}
|
||||
|
||||
func handleInput(keyboard []uint8, bullets *[]*Bullet, player *Player, gameMap *GameMap, players *[]*Player) (bool, bool) {
|
||||
if !player.local || player.shields <= 0 || player.shields > MaxShields {
|
||||
return true, false
|
||||
func handleInput(keyboard []uint8, bullets map[uint32]*Bullet, player *Player, gameMap *GameMap, players map[uint32]*Player) bool {
|
||||
if !player.local || player.shields <= 0 || player.shields > serverConfig.MaxShields {
|
||||
return true
|
||||
}
|
||||
shoot := false
|
||||
super := false
|
||||
@ -306,7 +306,7 @@ func handleInput(keyboard []uint8, bullets *[]*Bullet, player *Player, gameMap *
|
||||
}
|
||||
|
||||
if key == player.keyMap.exit {
|
||||
return false, shoot
|
||||
return false
|
||||
} else if key == player.keyMap.shoot {
|
||||
shoot = true
|
||||
} else if key == player.keyMap.super {
|
||||
@ -329,10 +329,10 @@ func handleInput(keyboard []uint8, bullets *[]*Bullet, player *Player, gameMap *
|
||||
xAxis := player.joyStick.Axis(player.joyMap.xAxis)
|
||||
yAxis := player.joyStick.Axis(player.joyMap.yAxis)
|
||||
|
||||
moveRight = xAxis > JoyStickDeadZone
|
||||
moveLeft = xAxis < -JoyStickDeadZone
|
||||
moveUp = yAxis > JoyStickDeadZone
|
||||
moveDown = yAxis < -JoyStickDeadZone
|
||||
moveRight = xAxis > config.JoyStickDeadZone
|
||||
moveLeft = xAxis < -config.JoyStickDeadZone
|
||||
moveUp = yAxis > config.JoyStickDeadZone
|
||||
moveDown = yAxis < -config.JoyStickDeadZone
|
||||
|
||||
} else {
|
||||
moveUp = player.joyStick.Button(player.joyMap.upButton) == sdl.PRESSED
|
||||
@ -341,7 +341,7 @@ func handleInput(keyboard []uint8, bullets *[]*Bullet, player *Player, gameMap *
|
||||
moveRight = player.joyStick.Button(player.joyMap.rightButton) == sdl.PRESSED
|
||||
}
|
||||
if player.joyStick.Button(player.joyMap.exitButton) == sdl.PRESSED {
|
||||
return false, shoot
|
||||
return false
|
||||
}
|
||||
if player.joyStick.Button(player.joyMap.shootButton) == sdl.PRESSED {
|
||||
shoot = true
|
||||
@ -379,9 +379,9 @@ func handleInput(keyboard []uint8, bullets *[]*Bullet, player *Player, gameMap *
|
||||
// Handle movement after the loop
|
||||
if moveUp || moveDown || moveLeft || moveRight {
|
||||
if player.tryMove(gameMap, shoot, players) {
|
||||
player.energy -= MovementCost
|
||||
player.energy -= serverConfig.MovementCost
|
||||
}
|
||||
}
|
||||
|
||||
return true, shoot
|
||||
return true
|
||||
}
|
||||
|
133
tuneller.proto
Normal file
133
tuneller.proto
Normal file
@ -0,0 +1,133 @@
|
||||
syntax = "proto3";
|
||||
package goingtunneling;
|
||||
option go_package = "./proto";
|
||||
|
||||
message Position {
|
||||
int32 posX = 1;
|
||||
int32 posY = 2;
|
||||
}
|
||||
|
||||
message Player {
|
||||
uint32 playerID = 1;
|
||||
PlayerLocation location = 2;
|
||||
}
|
||||
|
||||
message PlayerLocation {
|
||||
Position position = 1;
|
||||
uint32 orientation = 2;
|
||||
}
|
||||
|
||||
message Bullet {
|
||||
Position position = 1;
|
||||
uint32 direction = 2;
|
||||
Color color = 3;
|
||||
uint32 id = 4;
|
||||
bool super = 5;
|
||||
}
|
||||
|
||||
message Color {
|
||||
uint32 red = 1;
|
||||
uint32 green = 2;
|
||||
uint32 blue = 3;
|
||||
uint32 alpha = 4;
|
||||
}
|
||||
|
||||
message BulletParticle {
|
||||
Position position = 1;
|
||||
uint32 expirationTimer = 2;
|
||||
Color color = 3;
|
||||
uint32 id = 4;
|
||||
}
|
||||
|
||||
message ServerInfo {
|
||||
uint32 maxEnergy = 1;
|
||||
uint32 maxAmmunition = 2;
|
||||
uint32 maxShields = 3;
|
||||
uint32 mapWidth = 4;
|
||||
uint32 mapHeight = 5;
|
||||
uint32 normalShotCost = 6;
|
||||
uint32 superShotCost = 7;
|
||||
uint32 reloadCost = 8;
|
||||
uint32 movementCost = 9;
|
||||
uint32 diggingCost = 10;
|
||||
uint32 shootDiggingBonus = 11;
|
||||
uint32 shootCooldown = 12;
|
||||
uint32 rechargeCooldown = 13;
|
||||
uint32 rechargeOpponentCooldown = 14;
|
||||
uint32 repairCooldown = 15;
|
||||
uint32 diggingCooldown = 16;
|
||||
uint32 movementCooldown = 17;
|
||||
uint32 movementCooldownNoEnergy = 18;
|
||||
uint32 diggingCooldownNoEnergy = 19;
|
||||
uint32 reloadCooldown = 20;
|
||||
uint32 blastRadius = 21;
|
||||
uint32 playerID = 22;
|
||||
uint32 playerColorID = 23;
|
||||
}
|
||||
|
||||
message PlayerUpdate {
|
||||
uint32 energy = 1;
|
||||
uint32 ammo = 2;
|
||||
uint32 shields = 3;
|
||||
}
|
||||
|
||||
message BaseLocation {
|
||||
Position position = 1;
|
||||
Player owner = 2;
|
||||
Color color = 3;
|
||||
}
|
||||
|
||||
message TileUpdate {
|
||||
Position position = 1;
|
||||
uint32 kind = 2;
|
||||
}
|
||||
|
||||
message WorldUpdate {
|
||||
repeated Player players = 1;
|
||||
repeated BaseLocation base = 2;
|
||||
repeated Bullet bullets = 3;
|
||||
repeated BulletParticle bulletParticles = 4;
|
||||
repeated TileUpdate tileUpdate = 5;
|
||||
}
|
||||
|
||||
message ClientBound {
|
||||
oneof clientBoundMessage {
|
||||
ServerInfo serverInfo = 1;
|
||||
PlayerUpdate playerUpdate = 2;
|
||||
PlayerLocation playerLocationUpdate = 3;
|
||||
WorldUpdate worldUpdate = 4;
|
||||
PlayerStartResponse playerStartResponse = 5;
|
||||
}
|
||||
}
|
||||
|
||||
message DigBlock {
|
||||
Position position = 1;
|
||||
bool isShooting = 2;
|
||||
}
|
||||
|
||||
message Shoot {
|
||||
bool super = 1;
|
||||
}
|
||||
|
||||
message PlayerAction {
|
||||
oneof playerAction {
|
||||
DigBlock digBlock = 1;
|
||||
Shoot shoot = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message PlayerStartRequest {
|
||||
string version = 1;
|
||||
}
|
||||
|
||||
message PlayerStartResponse {
|
||||
string version = 1;
|
||||
}
|
||||
|
||||
message ServerBound {
|
||||
oneof serverBoundMessage {
|
||||
PlayerLocation playerPosition = 1;
|
||||
PlayerAction playerAction = 2;
|
||||
PlayerStartRequest playerStartRequest = 3;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user