Add multi monitor multiplayer
This commit is contained in:
parent
352c7af7ce
commit
696b827a7d
138
base.go
138
base.go
@ -2,28 +2,29 @@ package main
|
|||||||
|
|
||||||
import "github.com/veandco/go-sdl2/sdl"
|
import "github.com/veandco/go-sdl2/sdl"
|
||||||
|
|
||||||
const (
|
|
||||||
openingWidth = 7
|
|
||||||
)
|
|
||||||
|
|
||||||
type Base struct {
|
type Base struct {
|
||||||
rect sdl.Rect
|
|
||||||
owner *Player
|
owner *Player
|
||||||
|
openingWidth int32
|
||||||
|
gameObject *GameObject
|
||||||
}
|
}
|
||||||
|
|
||||||
func (base *Base) tick(players *[]*Player) {
|
func (base *Base) tick(players *[]*Player) {
|
||||||
for _, player := range *players {
|
for _, player := range *players {
|
||||||
if player.cullingRect.HasIntersection(&base.rect) {
|
if player.gameObject.baseRect.HasIntersection(&base.gameObject.baseRect) {
|
||||||
if player.rechargeCooldown == 0 && player.energy < MaxEnergy {
|
if player.rechargeCooldown == 0 && player.energy < MaxEnergy {
|
||||||
|
if MaxEnergy-player.energy < 4 {
|
||||||
player.energy++
|
player.energy++
|
||||||
|
} else {
|
||||||
|
player.energy += 4
|
||||||
|
}
|
||||||
if player == base.owner {
|
if player == base.owner {
|
||||||
player.rechargeCooldown = RechargeCooldownOwn
|
player.rechargeCooldown = RechargeCooldownOwn
|
||||||
} else {
|
} else {
|
||||||
player.rechargeCooldown = RechargeCooldownOpponent
|
player.rechargeCooldown = RechargeCooldownOpponent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if player == base.owner && player.repairCooldown == 0 && player.health < MaxHealth {
|
if player == base.owner && player.repairCooldown == 0 && player.shields < MaxShields {
|
||||||
player.health++
|
player.shields++
|
||||||
player.repairCooldown = RepairCooldown
|
player.repairCooldown = RepairCooldown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,112 +32,79 @@ func (base *Base) tick(players *[]*Player) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (base *Base) render(camera *sdl.Rect, surface *sdl.Surface) {
|
func (base *Base) render(camera *sdl.Rect, surface *sdl.Surface) {
|
||||||
borderWidth := base.rect.W - openingWidth
|
base.gameObject.render(camera, surface)
|
||||||
borderWidthA := borderWidth / 2
|
|
||||||
borderWidthB := borderWidth - borderWidthA + 1
|
|
||||||
if borderWidth < 0 {
|
|
||||||
panic("Bad border width")
|
|
||||||
}
|
|
||||||
rects := []sdl.Rect{
|
|
||||||
{
|
|
||||||
X: base.rect.X,
|
|
||||||
Y: base.rect.Y,
|
|
||||||
W: 1,
|
|
||||||
H: base.rect.H,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
X: base.rect.X + base.rect.W,
|
|
||||||
Y: base.rect.Y,
|
|
||||||
W: 1,
|
|
||||||
H: base.rect.H,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
X: base.rect.X,
|
|
||||||
Y: base.rect.Y,
|
|
||||||
W: borderWidthA,
|
|
||||||
H: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
X: base.rect.X + borderWidthA + openingWidth,
|
|
||||||
Y: base.rect.Y,
|
|
||||||
W: borderWidthB,
|
|
||||||
H: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
X: base.rect.X,
|
|
||||||
Y: base.rect.Y + base.rect.H,
|
|
||||||
W: borderWidthA,
|
|
||||||
H: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
X: base.rect.X + borderWidthA + openingWidth,
|
|
||||||
Y: base.rect.Y + base.rect.H,
|
|
||||||
W: borderWidthB,
|
|
||||||
H: 1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rect := range rects {
|
|
||||||
if camera.HasIntersection(&rect) {
|
|
||||||
cameraCompensatedRect := sdl.Rect{
|
|
||||||
X: rect.X - camera.X,
|
|
||||||
Y: rect.Y - camera.Y,
|
|
||||||
W: rect.W,
|
|
||||||
H: rect.H,
|
|
||||||
}
|
|
||||||
surface.FillRect(&cameraCompensatedRect, (*base.owner).color2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (base *Base) build(gameMap *GameMap) {
|
func (base *Base) build(gameMap *GameMap) {
|
||||||
borderWidth := base.rect.W - openingWidth
|
borderWidth := base.gameObject.baseRect.W - base.openingWidth
|
||||||
borderWidthA := borderWidth / 2
|
borderWidthA := borderWidth / 2
|
||||||
if borderWidth < 0 {
|
if borderWidth < 0 {
|
||||||
panic("Bad border width")
|
panic("Bad border width")
|
||||||
}
|
}
|
||||||
if base.rect.H < 9 {
|
if base.gameObject.baseRect.H < 9 {
|
||||||
panic("Bad border height")
|
panic("Bad border height")
|
||||||
}
|
}
|
||||||
if gameMap.width-base.rect.X-base.rect.W <= 0 {
|
if gameMap.width-base.gameObject.baseRect.X-base.gameObject.baseRect.W <= 0 {
|
||||||
panic("Bad base x location")
|
panic("Bad base x location")
|
||||||
}
|
}
|
||||||
if gameMap.height-base.rect.Y-base.rect.H <= 0 {
|
if gameMap.height-base.gameObject.baseRect.Y-base.gameObject.baseRect.H <= 0 {
|
||||||
panic("Bad base y location")
|
panic("Bad base y location")
|
||||||
}
|
}
|
||||||
if base.rect.X < 0 || base.rect.Y < 0 {
|
if base.gameObject.baseRect.X < 0 || base.gameObject.baseRect.Y < 0 {
|
||||||
panic("Bad base negative location")
|
panic("Bad base negative location")
|
||||||
}
|
}
|
||||||
for x := base.rect.X; x < base.rect.X+base.rect.W+1; x++ {
|
for x := base.gameObject.baseRect.X; x < base.gameObject.baseRect.X+base.gameObject.baseRect.W+1; x++ {
|
||||||
for y := base.rect.Y; y < base.rect.Y+base.rect.H+1; y++ {
|
for y := base.gameObject.baseRect.Y; y < base.gameObject.baseRect.Y+base.gameObject.baseRect.H+1; y++ {
|
||||||
gameMap.tiles[x][y] = 0
|
gameMap.tiles[x][y] = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for y := base.rect.Y; y < base.rect.Y+base.rect.H; y++ {
|
for y := base.gameObject.baseRect.Y; y < base.gameObject.baseRect.Y+base.gameObject.baseRect.H; y++ {
|
||||||
gameMap.tiles[base.rect.X][y] = 4
|
gameMap.tiles[base.gameObject.baseRect.X][y] = 4
|
||||||
gameMap.tiles[base.rect.X+base.rect.W][y] = 4
|
gameMap.tiles[base.gameObject.baseRect.X+base.gameObject.baseRect.W][y] = 4
|
||||||
}
|
}
|
||||||
for x := base.rect.X; x < base.rect.X+borderWidthA; x++ {
|
for x := base.gameObject.baseRect.X; x < base.gameObject.baseRect.X+borderWidthA; x++ {
|
||||||
gameMap.tiles[x][base.rect.Y] = 4
|
gameMap.tiles[x][base.gameObject.baseRect.Y] = 4
|
||||||
gameMap.tiles[x][base.rect.Y+base.rect.H] = 4
|
gameMap.tiles[x][base.gameObject.baseRect.Y+base.gameObject.baseRect.H] = 4
|
||||||
}
|
}
|
||||||
for x := base.rect.X + borderWidthA + openingWidth; x < base.rect.X+base.rect.W+1; x++ {
|
for x := base.gameObject.baseRect.X + borderWidthA + base.openingWidth; x < base.gameObject.baseRect.X+base.gameObject.baseRect.W+1; x++ {
|
||||||
gameMap.tiles[x][base.rect.Y] = 4
|
gameMap.tiles[x][base.gameObject.baseRect.Y] = 4
|
||||||
gameMap.tiles[x][base.rect.Y+base.rect.H] = 4
|
gameMap.tiles[x][base.gameObject.baseRect.Y+base.gameObject.baseRect.H] = 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createBases(players *[]*Player, gameMap *GameMap) *[]*Base {
|
func createBases(players *[]*Player, gameMap *GameMap) *[]*Base {
|
||||||
bases := &[]*Base{}
|
bases := &[]*Base{}
|
||||||
|
|
||||||
for ownerID, player := range *players {
|
for ownerID, player := range *players {
|
||||||
*bases = append(*bases, &Base{
|
gameObject := &GameObject{}
|
||||||
rect: sdl.Rect{
|
gameObject.baseRect = sdl.Rect{
|
||||||
X: player.posX - 14,
|
X: player.gameObject.baseRect.X - 14,
|
||||||
Y: player.posY - 14,
|
Y: player.gameObject.baseRect.Y - 14,
|
||||||
W: 35,
|
W: 35,
|
||||||
H: 35,
|
H: 35,
|
||||||
},
|
}
|
||||||
|
openingWidth := int32(float64(player.gameObject.baseRect.W) * 1.5)
|
||||||
|
if openingWidth%2 == 0 {
|
||||||
|
openingWidth++
|
||||||
|
}
|
||||||
|
|
||||||
|
borderWidth := gameObject.baseRect.W - openingWidth
|
||||||
|
borderWidthA := borderWidth / 2
|
||||||
|
borderWidthB := borderWidth - borderWidthA + 1
|
||||||
|
if borderWidth < 0 {
|
||||||
|
panic("Bad border width")
|
||||||
|
}
|
||||||
|
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],
|
owner: (*players)[ownerID],
|
||||||
|
openingWidth: openingWidth,
|
||||||
})
|
})
|
||||||
(*bases)[ownerID].build(gameMap)
|
(*bases)[ownerID].build(gameMap)
|
||||||
}
|
}
|
||||||
|
14
bullet.go
14
bullet.go
@ -149,14 +149,16 @@ func (bullet *Bullet) tick(gameMap *GameMap,
|
|||||||
}
|
}
|
||||||
hitPlayer := false
|
hitPlayer := false
|
||||||
for _, player := range *players {
|
for _, player := range *players {
|
||||||
if player.rect1.HasIntersection(&bulletRect) ||
|
if hitPlayer {
|
||||||
player.rect2.HasIntersection(&bulletRect) ||
|
|
||||||
player.rect3.HasIntersection(&bulletRect) ||
|
|
||||||
player.rect4.HasIntersection(&bulletRect) {
|
|
||||||
hitPlayer = true
|
|
||||||
player.health -= 20
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
for _, coloredRect := range player.gameObject.getCurrentRects() {
|
||||||
|
if coloredRect.rect.HasIntersection(&bulletRect) {
|
||||||
|
hitPlayer = true
|
||||||
|
player.shields -= 10
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if collisionResult != 0 || hitPlayer {
|
if collisionResult != 0 || hitPlayer {
|
||||||
bullet.explode(gameMap, bulletParticleMap)
|
bullet.explode(gameMap, bulletParticleMap)
|
||||||
|
87
gameobject.go
Normal file
87
gameobject.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
|
"image/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GameObject struct {
|
||||||
|
baseRect sdl.Rect
|
||||||
|
borderRect sdl.Rect
|
||||||
|
orientation uint8
|
||||||
|
visualRects [][]*ColoredRect
|
||||||
|
colors []color.Color
|
||||||
|
}
|
||||||
|
|
||||||
|
type ColoredRect struct {
|
||||||
|
color color.Color
|
||||||
|
rect *sdl.Rect
|
||||||
|
}
|
||||||
|
|
||||||
|
func adjustRectToCamera(object *sdl.Rect, camera *sdl.Rect) *sdl.Rect {
|
||||||
|
return &sdl.Rect{
|
||||||
|
X: object.X - camera.X,
|
||||||
|
Y: object.Y - camera.Y,
|
||||||
|
W: object.W,
|
||||||
|
H: object.H,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gameObject *GameObject) adjustRectToCamera(offset *sdl.Rect, camera *sdl.Rect) *sdl.Rect {
|
||||||
|
return &sdl.Rect{
|
||||||
|
X: gameObject.baseRect.X + offset.X - camera.X,
|
||||||
|
Y: gameObject.baseRect.Y + offset.Y - camera.Y,
|
||||||
|
W: offset.W,
|
||||||
|
H: offset.H,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gameObject *GameObject) render(camera *sdl.Rect, surface *sdl.Surface) {
|
||||||
|
if camera.HasIntersection(&gameObject.baseRect) {
|
||||||
|
if Debug {
|
||||||
|
gameObject.borderRect = sdl.Rect{
|
||||||
|
X: gameObject.baseRect.X - 1,
|
||||||
|
Y: gameObject.baseRect.Y - 1,
|
||||||
|
W: gameObject.baseRect.W + 2,
|
||||||
|
H: gameObject.baseRect.H + 2,
|
||||||
|
}
|
||||||
|
borderRectFinal := adjustRectToCamera(&gameObject.borderRect, camera)
|
||||||
|
baseRectFinal := adjustRectToCamera(&gameObject.baseRect, camera)
|
||||||
|
surface.FillRect(borderRectFinal, sdl.MapRGBA(surface.Format, 20, 192, 128, 64))
|
||||||
|
surface.FillRect(baseRectFinal, sdl.MapRGBA(surface.Format, 255, 20, 10, 64))
|
||||||
|
}
|
||||||
|
if 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)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gameObject *GameObject) addColoredRect(x, y, w, h int32, color uint8) {
|
||||||
|
if gameObject.visualRects == nil {
|
||||||
|
gameObject.visualRects = make([][]*ColoredRect, 0)
|
||||||
|
}
|
||||||
|
if uint8(len(gameObject.visualRects)) <= gameObject.orientation {
|
||||||
|
gameObject.visualRects = append(gameObject.visualRects, make([]*ColoredRect, 0))
|
||||||
|
}
|
||||||
|
if uint8(len(gameObject.colors)) > color {
|
||||||
|
gameObject.visualRects[gameObject.orientation] = append(gameObject.visualRects[gameObject.orientation],
|
||||||
|
&ColoredRect{
|
||||||
|
color: gameObject.colors[color],
|
||||||
|
rect: &sdl.Rect{
|
||||||
|
X: x, Y: y, W: w, H: h,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gameObject *GameObject) getCurrentRects() []*ColoredRect {
|
||||||
|
return gameObject.visualRects[gameObject.orientation]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gameObject *GameObject) addColor(color color.Color) {
|
||||||
|
gameObject.colors = append(gameObject.colors, color)
|
||||||
|
}
|
90
graphics.go
90
graphics.go
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -10,9 +11,24 @@ func initializeSDL() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupWindowAndSurface() (*sdl.Window, *sdl.Surface) {
|
func setupWindowAndSurface(playerIndex uint8) (*sdl.Window, *sdl.Surface) {
|
||||||
const windowWidth, windowHeight = 160, 100
|
const windowWidth, windowHeight = 160, 100
|
||||||
window, err := sdl.CreateWindow("test", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, windowWidth, windowHeight, sdl.WINDOW_SHOWN|sdl.WINDOW_RESIZABLE)
|
window, err := sdl.CreateWindow(fmt.Sprintf("Tunneler - player %d", playerIndex), sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, windowWidth, windowHeight, sdl.WINDOW_SHOWN|sdl.WINDOW_RESIZABLE)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logicalSurface, err := sdl.CreateRGBSurface(0, windowWidth, windowHeight, 32, 0, 0, 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return window, logicalSurface
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -81,7 +97,6 @@ func handleWindowResize(window *sdl.Window, logicalSurface *sdl.Surface) {
|
|||||||
letterboxX := (windowWidth - newWidth) / 2
|
letterboxX := (windowWidth - newWidth) / 2
|
||||||
letterboxY := (windowHeight - newHeight) / 2
|
letterboxY := (windowHeight - newHeight) / 2
|
||||||
|
|
||||||
windowSurface.FillRect(nil, 0)
|
|
||||||
srcRect := &sdl.Rect{X: 0, Y: 0, W: logicalSurface.W, H: logicalSurface.H}
|
srcRect := &sdl.Rect{X: 0, Y: 0, W: logicalSurface.W, H: logicalSurface.H}
|
||||||
dstRect := &sdl.Rect{X: letterboxX, Y: letterboxY, W: newWidth, H: newHeight}
|
dstRect := &sdl.Rect{X: letterboxX, Y: letterboxY, W: newWidth, H: newHeight}
|
||||||
|
|
||||||
@ -89,68 +104,45 @@ func handleWindowResize(window *sdl.Window, logicalSurface *sdl.Surface) {
|
|||||||
window.UpdateSurface()
|
window.UpdateSurface()
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderScene(logicalSurface, playSurface, HUDSurface *sdl.Surface, gameMap *GameMap, players *[]*Player, bases *[]*Base, bullets *[]*Bullet, bulletParticles *[]*BulletParticle, camera *sdl.Rect, playSurfaceRect, playSurfaceTargetRect, HUDSurfaceRect, HUDSurfaceTargetRect *sdl.Rect) {
|
func adjustWindow(window *sdl.Window, logicalSurface *sdl.Surface) {
|
||||||
HUDColor := sdl.MapRGBA(HUDSurface.Format, 101, 101, 101, 255)
|
// Get window surface and handle any errors
|
||||||
logicalColor := sdl.MapRGBA(HUDSurface.Format, 101, 101, 0, 255)
|
|
||||||
playColor := sdl.MapRGBA(HUDSurface.Format, 101, 0, 101, 255)
|
|
||||||
|
|
||||||
logicalSurface.FillRect(nil, logicalColor)
|
|
||||||
playSurface.FillRect(nil, playColor)
|
|
||||||
HUDSurface.FillRect(nil, HUDColor)
|
|
||||||
|
|
||||||
(*players)[0].track(camera)
|
|
||||||
|
|
||||||
gameMap.render(camera, playSurface)
|
|
||||||
|
|
||||||
for _, bullet := range *bullets {
|
|
||||||
(*bullet).render(camera, playSurface)
|
|
||||||
(*bullet).tick(gameMap, bulletParticles, bullets, players)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, base := range *bases {
|
|
||||||
(*base).render(camera, playSurface)
|
|
||||||
(*base).tick(players)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, player := range *players {
|
|
||||||
(*player).render(camera, playSurface)
|
|
||||||
(*player).tick()
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, bulletParticle := range *bulletParticles {
|
|
||||||
bulletParticle.render(camera, playSurface)
|
|
||||||
bulletParticle.tick(bulletParticles)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderHud((*players)[0], HUDSurface)
|
|
||||||
|
|
||||||
playSurface.BlitScaled(playSurfaceRect, logicalSurface, playSurfaceTargetRect)
|
|
||||||
HUDSurface.BlitScaled(HUDSurfaceRect, logicalSurface, HUDSurfaceTargetRect)
|
|
||||||
}
|
|
||||||
|
|
||||||
func adjustWindow(window *sdl.Window, logicalSurface *sdl.Surface, pixelBG uint32) {
|
|
||||||
windowSurface, err := window.GetSurface()
|
windowSurface, err := window.GetSurface()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retrieve window dimensions
|
||||||
windowWidth, windowHeight := windowSurface.W, windowSurface.H
|
windowWidth, windowHeight := windowSurface.W, windowSurface.H
|
||||||
aspectRatio := float64(logicalSurface.W) / float64(logicalSurface.H)
|
|
||||||
newWidth := windowWidth
|
|
||||||
newHeight := int32(float64(windowWidth) / aspectRatio)
|
|
||||||
|
|
||||||
if newHeight > windowHeight {
|
// Calculate aspect ratio
|
||||||
|
logicalAspectRatio := float64(logicalSurface.W) / float64(logicalSurface.H)
|
||||||
|
windowAspectRatio := float64(windowWidth) / float64(windowHeight)
|
||||||
|
|
||||||
|
var newWidth, newHeight int32
|
||||||
|
if windowAspectRatio > logicalAspectRatio {
|
||||||
|
// Window is wider than logical surface
|
||||||
newHeight = windowHeight
|
newHeight = windowHeight
|
||||||
newWidth = int32(float64(windowHeight) * aspectRatio)
|
newWidth = int32(float64(windowHeight) * logicalAspectRatio)
|
||||||
|
} else {
|
||||||
|
// Window is taller or equal in aspect ratio
|
||||||
|
newWidth = windowWidth
|
||||||
|
newHeight = int32(float64(windowWidth) / logicalAspectRatio)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate letterbox positions
|
||||||
letterboxX := (windowWidth - newWidth) / 2
|
letterboxX := (windowWidth - newWidth) / 2
|
||||||
letterboxY := (windowHeight - newHeight) / 2
|
letterboxY := (windowHeight - newHeight) / 2
|
||||||
|
|
||||||
windowSurface.FillRect(nil, pixelBG)
|
// Fill background
|
||||||
|
windowSurface.FillRect(nil, sdl.MapRGBA(logicalSurface.Format, 80, 20, 10, 255))
|
||||||
|
|
||||||
|
// Set source and destination rectangles
|
||||||
srcRect := &sdl.Rect{X: 0, Y: 0, W: logicalSurface.W, H: logicalSurface.H}
|
srcRect := &sdl.Rect{X: 0, Y: 0, W: logicalSurface.W, H: logicalSurface.H}
|
||||||
dstRect := &sdl.Rect{X: letterboxX, Y: letterboxY, W: newWidth, H: newHeight}
|
dstRect := &sdl.Rect{X: letterboxX, Y: letterboxY, W: newWidth, H: newHeight}
|
||||||
|
|
||||||
|
// Perform the scaled blit
|
||||||
logicalSurface.BlitScaled(srcRect, windowSurface, dstRect)
|
logicalSurface.BlitScaled(srcRect, windowSurface, dstRect)
|
||||||
|
|
||||||
|
// Update the window surface
|
||||||
window.UpdateSurface()
|
window.UpdateSurface()
|
||||||
}
|
}
|
||||||
|
139
hud.go
139
hud.go
@ -2,77 +2,82 @@ package main
|
|||||||
|
|
||||||
import "github.com/veandco/go-sdl2/sdl"
|
import "github.com/veandco/go-sdl2/sdl"
|
||||||
|
|
||||||
|
var letterOffsets = []int32{
|
||||||
|
2,
|
||||||
|
10,
|
||||||
|
18,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
// Perform conversion to float64 to ensure proper division
|
||||||
|
return int32((float64(x-minX)/float64(maxX-minX))*float64(maxY-minY) + float64(minY))
|
||||||
|
}
|
||||||
|
|
||||||
|
var rects = [][]sdl.Rect{
|
||||||
|
// Define the rects with modified Y-values
|
||||||
|
{
|
||||||
|
{X: 5, Y: 0, W: 6, H: 1},
|
||||||
|
{X: 5, Y: 0, W: 1, H: 5},
|
||||||
|
{X: 5, Y: 2, W: 6, H: 1},
|
||||||
|
{X: 5, Y: 4, W: 6, H: 1},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
{X: 6, Y: 0, W: 4, H: 1}, // Top bar of "A"
|
||||||
|
{X: 5, Y: 1, W: 1, H: 4}, // Left vertical line of "A"
|
||||||
|
{X: 10, Y: 1, W: 1, H: 4}, // Right vertical line of "A"
|
||||||
|
{X: 6, Y: 3, W: 4, H: 1}, // Middle bar of "A"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
{X: 5, Y: 0, W: 6, H: 1},
|
||||||
|
{X: 5, Y: 0, W: 1, H: 3},
|
||||||
|
{X: 5, Y: 2, W: 6, H: 1},
|
||||||
|
{X: 10, Y: 2, W: 1, H: 3},
|
||||||
|
{X: 5, Y: 4, W: 6, H: 1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func initHud(surface *sdl.Surface) {
|
||||||
|
letterColors = []uint32{
|
||||||
|
sdl.MapRGBA(surface.Format, 243, 235, 28, 255),
|
||||||
|
sdl.MapRGBA(surface.Format, 255, 80, 40, 255),
|
||||||
|
sdl.MapRGBA(surface.Format, 40, 243, 243, 255),
|
||||||
|
}
|
||||||
|
HUDColor := sdl.MapRGBA(surface.Format, 101, 101, 101, 255)
|
||||||
|
surface.FillRect(nil, HUDColor)
|
||||||
|
|
||||||
|
for letterIndex, letter := range rects {
|
||||||
|
for _, letterRect := range letter {
|
||||||
|
offsetRect := letterRect
|
||||||
|
offsetRect.Y += letterOffsets[letterIndex]
|
||||||
|
surface.FillRect(&offsetRect, letterColors[letterIndex])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func renderHud(player *Player, surface *sdl.Surface) {
|
func renderHud(player *Player, surface *sdl.Surface) {
|
||||||
eRects := []sdl.Rect{
|
|
||||||
{
|
for _, letterOffset := range letterOffsets {
|
||||||
X: 5,
|
surface.FillRect(&sdl.Rect{X: 16, Y: letterOffset - 1, W: 90, H: 7}, 0)
|
||||||
Y: 4,
|
|
||||||
W: 6,
|
|
||||||
H: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
X: 5,
|
|
||||||
Y: 4,
|
|
||||||
W: 1,
|
|
||||||
H: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
X: 5,
|
|
||||||
Y: 6,
|
|
||||||
W: 6,
|
|
||||||
H: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
X: 5,
|
|
||||||
Y: 8,
|
|
||||||
W: 6,
|
|
||||||
H: 1,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sRects := []sdl.Rect{
|
HUDValues := []int32{
|
||||||
{
|
mapRange(player.energy, 0, MaxEnergy, 0, 88),
|
||||||
X: 5,
|
mapRange(player.ammunition, 0, MaxAmmunition, 0, 88),
|
||||||
Y: 18,
|
mapRange(player.shields, 0, MaxShields, 0, 88),
|
||||||
W: 6,
|
|
||||||
H: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
X: 5,
|
|
||||||
Y: 18,
|
|
||||||
W: 1,
|
|
||||||
H: 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
X: 5,
|
|
||||||
Y: 20,
|
|
||||||
W: 6,
|
|
||||||
H: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
X: 10,
|
|
||||||
Y: 20,
|
|
||||||
W: 1,
|
|
||||||
H: 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
X: 5,
|
|
||||||
Y: 22,
|
|
||||||
W: 6,
|
|
||||||
H: 1,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rect := range eRects {
|
for HUDValueIndex, HUDValue := range HUDValues {
|
||||||
surface.FillRect(&rect, sdl.MapRGBA(surface.Format, 243, 235, 28, 255))
|
surface.FillRect(
|
||||||
|
&sdl.Rect{
|
||||||
|
X: 17,
|
||||||
|
Y: letterOffsets[HUDValueIndex],
|
||||||
|
W: HUDValue,
|
||||||
|
H: 5},
|
||||||
|
letterColors[HUDValueIndex])
|
||||||
}
|
}
|
||||||
for _, rect := range sRects {
|
|
||||||
surface.FillRect(&rect, sdl.MapRGBA(surface.Format, 40, 243, 243, 255))
|
|
||||||
}
|
|
||||||
|
|
||||||
surface.FillRect(&sdl.Rect{X: 16, Y: 3, W: 90, H: 7}, sdl.MapRGBA(surface.Format, 0, 0, 0, 255))
|
|
||||||
surface.FillRect(&sdl.Rect{X: 16, Y: 17, W: 90, H: 7}, sdl.MapRGBA(surface.Format, 0, 0, 0, 255))
|
|
||||||
|
|
||||||
surface.FillRect(&sdl.Rect{X: 17, Y: 4, W: int32(player.energy / 20), H: 5}, sdl.MapRGBA(surface.Format, 243, 235, 28, 255))
|
|
||||||
surface.FillRect(&sdl.Rect{X: 17, Y: 18, W: int32(player.health), H: 5}, sdl.MapRGBA(surface.Format, 40, 243, 243, 255))
|
|
||||||
}
|
}
|
||||||
|
248
main.go
248
main.go
@ -7,13 +7,19 @@ import (
|
|||||||
const (
|
const (
|
||||||
MapWidth = 1000 // Width of the map
|
MapWidth = 1000 // Width of the map
|
||||||
MapHeight = 1000 // Height of the map
|
MapHeight = 1000 // Height of the map
|
||||||
MaxEnergy = 1760
|
BlastRadius = 5
|
||||||
MaxHealth = 88
|
|
||||||
NormalShotCost = 3
|
MaxEnergy = 3520
|
||||||
SuperShotCost = 20
|
MaxAmmunition = 6
|
||||||
|
MaxShields = 100
|
||||||
|
|
||||||
|
NormalShotCost = 7
|
||||||
|
SuperShotCost = 80
|
||||||
|
ReloadCost = 4
|
||||||
MovementCost = 1
|
MovementCost = 1
|
||||||
DiggingCost = 2
|
DiggingCost = 3
|
||||||
ShootDiggingCostBonus = 1
|
ShootDiggingCostBonus = 1
|
||||||
|
|
||||||
ShootCooldown = 8
|
ShootCooldown = 8
|
||||||
RechargeCooldownOwn = 0
|
RechargeCooldownOwn = 0
|
||||||
DiggingCooldown = 4
|
DiggingCooldown = 4
|
||||||
@ -22,137 +28,159 @@ const (
|
|||||||
MovementCooldown = 2
|
MovementCooldown = 2
|
||||||
MovementCooldownNoEnergy = 4
|
MovementCooldownNoEnergy = 4
|
||||||
DiggingCooldownNoEnergy = 8
|
DiggingCooldownNoEnergy = 8
|
||||||
|
ReloadCooldown = 16
|
||||||
|
|
||||||
|
Debug = false
|
||||||
|
MapWindow = true
|
||||||
|
RenderGameObjects = true
|
||||||
|
ProfilerOn = true
|
||||||
|
|
||||||
|
JoyStickDeadZone = 8000
|
||||||
|
|
||||||
|
DoAllKeymapsPlayers = true
|
||||||
|
DoJoyStickPlayers = true
|
||||||
|
DoKeymapPlayer = true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var mapWindow *sdl.Window
|
||||||
|
var mapSurface *sdl.Surface
|
||||||
|
var mapRendererRect = &sdl.Rect{X: 0, Y: 0, W: MapWidth, H: MapHeight}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
initializeSDL()
|
initializeSDL()
|
||||||
defer sdl.Quit()
|
defer sdl.Quit()
|
||||||
|
|
||||||
window, logicalSurface := setupWindowAndSurface()
|
gameMap := &GameMap{}
|
||||||
window.SetTitle("GOing to tunnel")
|
|
||||||
defer window.Destroy()
|
|
||||||
defer logicalSurface.Free()
|
|
||||||
|
|
||||||
playSurface, playSurfaceRect, playSurfaceTargetRect := setupPlaySurface()
|
|
||||||
defer playSurface.Free()
|
|
||||||
|
|
||||||
HUDSurface, HUDSurfaceRect, HUDSurfaceTargetRect := setupHUDSurface()
|
|
||||||
defer HUDSurface.Free()
|
|
||||||
|
|
||||||
pixelBG := sdl.MapRGBA(logicalSurface.Format, 80, 20, 10, 255)
|
|
||||||
|
|
||||||
gameMap := GameMap{}
|
|
||||||
gameMap.createGameMap(MapWidth, MapHeight)
|
gameMap.createGameMap(MapWidth, MapHeight)
|
||||||
|
|
||||||
players := &[]*Player{}
|
players := &[]*Player{}
|
||||||
|
initPlayerColors()
|
||||||
|
createPlayers(getNeededPlayers(), playerColors, keyMaps, joyMaps, gameMap, players)
|
||||||
|
|
||||||
createPlayer(
|
defer closeThings(players)
|
||||||
sdl.MapRGBA(playSurface.Format, 0, 0, 182, 255),
|
|
||||||
sdl.MapRGBA(playSurface.Format, 44, 44, 255, 255),
|
|
||||||
sdl.MapRGBA(playSurface.Format, 243, 235, 28, 255),
|
|
||||||
&gameMap,
|
|
||||||
players)
|
|
||||||
|
|
||||||
createPlayer(
|
bases := createBases(players, gameMap)
|
||||||
sdl.MapRGBA(playSurface.Format, 44, 184, 44, 255),
|
|
||||||
sdl.MapRGBA(playSurface.Format, 0, 249, 0, 255),
|
|
||||||
sdl.MapRGBA(playSurface.Format, 243, 235, 28, 255),
|
|
||||||
&gameMap,
|
|
||||||
players)
|
|
||||||
|
|
||||||
bases := createBases(players, &gameMap)
|
bullets := &[]*Bullet{}
|
||||||
|
bulletParticles := &[]*BulletParticle{}
|
||||||
bulletMap := &[]*Bullet{}
|
|
||||||
bulletParticleMap := &[]*BulletParticle{}
|
|
||||||
|
|
||||||
camera := sdl.Rect{X: 0, Y: 0, W: 76, H: 76}
|
|
||||||
|
|
||||||
|
for playerIndex, player := range *players {
|
||||||
|
initPlayer(uint8(playerIndex), player)
|
||||||
|
}
|
||||||
|
if MapWindow {
|
||||||
|
mapWindow, mapSurface = setupMapWindowAndSurface()
|
||||||
|
}
|
||||||
running := true
|
running := true
|
||||||
for running {
|
for running {
|
||||||
currentTime := sdl.GetTicks64()
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
running = handleEvents(window, logicalSurface)
|
enforceFrameRate(frameStart, 60)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
player.playSurface, player.playSurfaceRect, player.playSurfaceTargetRect = setupPlaySurface()
|
||||||
|
playColor := sdl.MapRGBA(player.playSurface.Format, 101, 0, 101, 255)
|
||||||
|
player.playSurface.FillRect(nil, playColor)
|
||||||
|
|
||||||
|
player.HUDSurface, player.HUDSurfaceRect, player.HUDSurfaceTargetRect = setupHUDSurface()
|
||||||
|
initHud(player.HUDSurface)
|
||||||
|
player.camera = &sdl.Rect{X: 0, Y: 0, W: 76, H: 76}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
keyboard := sdl.GetKeyboardState()
|
||||||
|
shouldContinue, isShooting = handleInput(keyboard, bullets, player, gameMap, player.playSurface.Format, players)
|
||||||
|
running = running && shouldContinue
|
||||||
|
})
|
||||||
|
|
||||||
running = running && handleInput(keyboard, bulletMap, (*players)[0], &gameMap, playSurface.Format, players)
|
// Profile rendering (aggregate all renderings)
|
||||||
|
totalRenderTime += profileSection(func() {
|
||||||
|
player.track(player.camera)
|
||||||
|
gameMap.render(player.camera, player.playSurface)
|
||||||
|
|
||||||
renderScene(logicalSurface, playSurface, HUDSurface, &gameMap, players, bases, bulletMap, bulletParticleMap, &camera, playSurfaceRect, playSurfaceTargetRect, HUDSurfaceRect, HUDSurfaceTargetRect)
|
for _, bullet := range *bullets {
|
||||||
|
(*bullet).render(player.camera, player.playSurface)
|
||||||
adjustWindow(window, logicalSurface, pixelBG)
|
|
||||||
|
|
||||||
// Calculate delay to achieve roughly 60 FPS
|
|
||||||
frameDuration := 1000 / 60
|
|
||||||
elapsed := sdl.GetTicks64() - currentTime
|
|
||||||
if delay := frameDuration - int(elapsed); delay > 0 {
|
|
||||||
sdl.Delay(uint32(delay))
|
|
||||||
}
|
}
|
||||||
|
for _, base := range *bases {
|
||||||
|
(*base).render(player.camera, player.playSurface)
|
||||||
}
|
}
|
||||||
|
for _, playerLoop := range *players {
|
||||||
|
(*playerLoop).render(player.camera, player.playSurface)
|
||||||
|
}
|
||||||
|
for _, bulletParticle := range *bulletParticles {
|
||||||
|
bulletParticle.render(player.camera, player.playSurface)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleInput(keyboard []uint8, bullets *[]*Bullet, player *Player, gameMap *GameMap, format *sdl.PixelFormat, players *[]*Player) bool {
|
player.tick(isShooting, bullets, player.playSurface.Format)
|
||||||
shoot := false
|
renderHud(player, player.HUDSurface)
|
||||||
super := false
|
player.playSurface.BlitScaled(player.playSurfaceRect, player.logicalSurface, player.playSurfaceTargetRect)
|
||||||
|
player.HUDSurface.BlitScaled(player.HUDSurfaceRect, player.logicalSurface, player.HUDSurfaceTargetRect)
|
||||||
|
})
|
||||||
|
|
||||||
// Flags to track movement in each direction
|
// Profile window adjustments
|
||||||
moveUp := false
|
totalScalingTime += profileSection(func() {
|
||||||
moveDown := false
|
adjustWindow(player.window, player.logicalSurface)
|
||||||
moveLeft := false
|
})
|
||||||
moveRight := false
|
|
||||||
|
|
||||||
// Process keyboard input
|
frameEnd := sdl.GetTicks64()
|
||||||
for key, value := range keyboard {
|
totalFrameTime += frameEnd - frameStart
|
||||||
if value == 0 {
|
frameCount++
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if key == sdl.SCANCODE_ESCAPE {
|
// Log profiling information every 1000 frames
|
||||||
return false
|
if frameCount%1000 == 0 && ProfilerOn && playerIndex == 0 {
|
||||||
} else if key == sdl.SCANCODE_SPACE {
|
logProfilingInfo(totalHandleEventsTime, totalRenderTime, totalScalingTime, totalFrameTime, frameCount)
|
||||||
shoot = true
|
resetProfilingCounters(&totalHandleEventsTime, &totalRenderTime, &totalScalingTime, &totalFrameTime, &frameCount)
|
||||||
} else if key == sdl.SCANCODE_LCTRL {
|
|
||||||
super = true
|
|
||||||
} else if key == sdl.SCANCODE_W {
|
|
||||||
moveUp = true
|
|
||||||
} else if key == sdl.SCANCODE_S {
|
|
||||||
moveDown = true
|
|
||||||
} else if key == sdl.SCANCODE_A {
|
|
||||||
moveLeft = true
|
|
||||||
} else if key == sdl.SCANCODE_D {
|
|
||||||
moveRight = true
|
|
||||||
}
|
}
|
||||||
}
|
return running
|
||||||
|
|
||||||
// Handle shooting after the loop
|
|
||||||
if shoot {
|
|
||||||
player.shoot(super, bullets, format)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine player orientation for diagonal movement
|
|
||||||
if moveUp && moveRight {
|
|
||||||
player.orientation = 4 // Up-Right
|
|
||||||
} else if moveUp && moveLeft {
|
|
||||||
player.orientation = 5 // Up-Left
|
|
||||||
} else if moveDown && moveRight {
|
|
||||||
player.orientation = 6 // Down-Right
|
|
||||||
} else if moveDown && moveLeft {
|
|
||||||
player.orientation = 7 // Down-Left
|
|
||||||
} else if moveUp {
|
|
||||||
player.orientation = 0 // Up
|
|
||||||
} else if moveRight {
|
|
||||||
player.orientation = 1 // Right
|
|
||||||
} else if moveDown {
|
|
||||||
player.orientation = 2 // Down
|
|
||||||
} else if moveLeft {
|
|
||||||
player.orientation = 3 // Left
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle movement after the loop
|
|
||||||
if moveUp || moveDown || moveLeft || moveRight {
|
|
||||||
if player.tryMove(gameMap, shoot, players) {
|
|
||||||
player.energy -= MovementCost
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
4
map.go
4
map.go
@ -49,12 +49,12 @@ func (gameMap *GameMap) getTileColor(x int32, y int32) color.Color {
|
|||||||
|
|
||||||
func (gameMap *GameMap) createGameMap(width int32, height int32) {
|
func (gameMap *GameMap) createGameMap(width int32, height int32) {
|
||||||
gameMap.tiles = make([][]uint8, width)
|
gameMap.tiles = make([][]uint8, width)
|
||||||
perlinNoiseRock := perlin.NewPerlin(2, 2, 4, time.Now().Unix())
|
perlinNoiseRock := perlin.NewPerlin(2, 4, 8, time.Now().Unix())
|
||||||
perlinNoiseSoil := perlin.NewPerlin(2, 8, 4, time.Now().Unix())
|
perlinNoiseSoil := perlin.NewPerlin(2, 8, 4, time.Now().Unix())
|
||||||
for i := range gameMap.tiles {
|
for i := range gameMap.tiles {
|
||||||
gameMap.tiles[i] = make([]uint8, height)
|
gameMap.tiles[i] = make([]uint8, height)
|
||||||
for j := range gameMap.tiles[i] {
|
for j := range gameMap.tiles[i] {
|
||||||
perlinRock := perlinNoiseRock.Noise2D(float64(i)/float64(width)*3, float64(j)/float64(height)*3)
|
perlinRock := perlinNoiseRock.Noise2D(float64(i)/float64(width)*6, float64(j)/float64(height)*6)
|
||||||
if perlinRock > 0.2 {
|
if perlinRock > 0.2 {
|
||||||
gameMap.tiles[i][j] = 1
|
gameMap.tiles[i][j] = 1
|
||||||
} else {
|
} else {
|
||||||
|
538
player.go
538
player.go
@ -7,107 +7,50 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Player struct {
|
type Player struct {
|
||||||
posX int32
|
local bool
|
||||||
posY int32
|
playerColors PlayerColors
|
||||||
orientation uint8
|
keyMap KeyMap
|
||||||
color1 uint32
|
joyMap JoyMap
|
||||||
color2 uint32
|
joyStick *sdl.Joystick
|
||||||
color3 uint32
|
camera *sdl.Rect
|
||||||
energy uint16
|
energy uint16
|
||||||
health uint16
|
ammunition uint16
|
||||||
|
shields uint16
|
||||||
digCooldown uint8
|
digCooldown uint8
|
||||||
shootCooldown uint8
|
shootCooldown uint8
|
||||||
repairCooldown uint8
|
repairCooldown uint8
|
||||||
rechargeCooldown uint8
|
rechargeCooldown uint8
|
||||||
movementCooldown uint8
|
movementCooldown uint8
|
||||||
rect1 sdl.Rect
|
reloadCooldown uint8
|
||||||
rect2 sdl.Rect
|
gameObject *GameObject
|
||||||
rect3 sdl.Rect
|
|
||||||
rect4 sdl.Rect
|
window *sdl.Window
|
||||||
cullingRect sdl.Rect
|
|
||||||
|
logicalSurface *sdl.Surface
|
||||||
|
playSurface *sdl.Surface
|
||||||
|
HUDSurface *sdl.Surface
|
||||||
|
|
||||||
|
playSurfaceRect *sdl.Rect
|
||||||
|
HUDSurfaceRect *sdl.Rect
|
||||||
|
|
||||||
|
playSurfaceTargetRect *sdl.Rect
|
||||||
|
HUDSurfaceTargetRect *sdl.Rect
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *Player) track(camera *sdl.Rect) {
|
func (player *Player) track(camera *sdl.Rect) {
|
||||||
camera.X = player.posX - 37
|
camera.X = player.gameObject.baseRect.X - 37
|
||||||
camera.Y = player.posY - 38
|
camera.Y = player.gameObject.baseRect.Y - 38
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *Player) render(camera *sdl.Rect, surface *sdl.Surface) {
|
func (player *Player) render(camera *sdl.Rect, surface *sdl.Surface) {
|
||||||
relativePlayerX := player.posX - camera.X
|
|
||||||
relativePlayerY := player.posY - camera.Y
|
|
||||||
|
|
||||||
switch player.orientation {
|
|
||||||
case 0: // Up
|
|
||||||
player.rect1 = sdl.Rect{X: relativePlayerX, Y: relativePlayerY + 1, W: 1, H: 6}
|
|
||||||
player.rect2 = sdl.Rect{X: relativePlayerX + 4, Y: relativePlayerY + 1, W: 1, H: 6}
|
|
||||||
player.rect3 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 2, W: 3, H: 4}
|
|
||||||
player.rect4 = sdl.Rect{X: relativePlayerX + 2, Y: relativePlayerY, W: 1, H: 4}
|
|
||||||
|
|
||||||
case 1: // Right
|
|
||||||
player.rect1 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 1, W: 6, H: 1}
|
|
||||||
player.rect2 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 5, W: 6, H: 1}
|
|
||||||
player.rect3 = sdl.Rect{X: relativePlayerX + 2, Y: relativePlayerY + 2, W: 4, H: 3}
|
|
||||||
player.rect4 = sdl.Rect{X: relativePlayerX + 4, Y: relativePlayerY + 3, W: 4, H: 1}
|
|
||||||
|
|
||||||
case 2: // Down
|
|
||||||
player.rect1 = sdl.Rect{X: relativePlayerX, Y: relativePlayerY + 1, W: 1, H: 6}
|
|
||||||
player.rect2 = sdl.Rect{X: relativePlayerX + 4, Y: relativePlayerY + 1, W: 1, H: 6}
|
|
||||||
player.rect3 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 2, W: 3, H: 4}
|
|
||||||
player.rect4 = sdl.Rect{X: relativePlayerX + 2, Y: relativePlayerY + 4, W: 1, H: 4}
|
|
||||||
|
|
||||||
case 3: // Left
|
|
||||||
player.rect1 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 1, W: 6, H: 1}
|
|
||||||
player.rect2 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 5, W: 6, H: 1}
|
|
||||||
player.rect3 = sdl.Rect{X: relativePlayerX + 2, Y: relativePlayerY + 2, W: 4, H: 3}
|
|
||||||
player.rect4 = sdl.Rect{X: relativePlayerX, Y: relativePlayerY + 3, W: 4, H: 1}
|
|
||||||
|
|
||||||
case 4: // Up-Right
|
|
||||||
player.rect1 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 6, W: 5, H: 1}
|
|
||||||
player.rect2 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 2, W: 1, H: 4}
|
|
||||||
player.rect3 = sdl.Rect{X: relativePlayerX + 2, Y: relativePlayerY + 2, W: 4, H: 4}
|
|
||||||
player.rect4 = sdl.Rect{X: relativePlayerX + 4, Y: relativePlayerY + 2, W: 2, H: 2}
|
|
||||||
|
|
||||||
case 5: // Up-Left
|
|
||||||
player.rect1 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 6, W: 5, H: 1}
|
|
||||||
player.rect2 = sdl.Rect{X: relativePlayerX + 5, Y: relativePlayerY + 2, W: 1, H: 5}
|
|
||||||
player.rect3 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 2, W: 4, H: 4}
|
|
||||||
player.rect4 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 2, W: 2, H: 2}
|
|
||||||
|
|
||||||
case 6: // Down-Right
|
|
||||||
player.rect1 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 1, W: 5, H: 1}
|
|
||||||
player.rect2 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 1, W: 1, H: 5}
|
|
||||||
player.rect3 = sdl.Rect{X: relativePlayerX + 2, Y: relativePlayerY + 2, W: 4, H: 4}
|
|
||||||
player.rect4 = sdl.Rect{X: relativePlayerX + 4, Y: relativePlayerY + 4, W: 2, H: 2}
|
|
||||||
|
|
||||||
case 7: // Down-Left
|
|
||||||
player.rect1 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 1, W: 4, H: 1}
|
|
||||||
player.rect2 = sdl.Rect{X: relativePlayerX + 5, Y: relativePlayerY + 1, W: 1, H: 5}
|
|
||||||
player.rect3 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 2, W: 4, H: 4}
|
|
||||||
player.rect4 = sdl.Rect{X: relativePlayerX + 1, Y: relativePlayerY + 4, W: 2, H: 2}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Common part: Rendering player
|
// Common part: Rendering player
|
||||||
player.cullingRect = sdl.Rect{X: player.posX, Y: player.posY, W: 7, H: 7}
|
player.gameObject.baseRect = sdl.Rect{X: player.gameObject.baseRect.X, Y: player.gameObject.baseRect.Y, W: 7, H: 7}
|
||||||
cameraAdjustedCullingRect := sdl.Rect{
|
|
||||||
X: player.cullingRect.X - camera.X,
|
if player.shields > 0 && player.shields <= MaxShields {
|
||||||
Y: player.cullingRect.Y - camera.Y,
|
player.gameObject.render(camera, surface)
|
||||||
W: player.cullingRect.W,
|
|
||||||
H: player.cullingRect.H,
|
|
||||||
}
|
|
||||||
cameraAdjustedCullingRectBorder := sdl.Rect{
|
|
||||||
X: player.cullingRect.X - camera.X - 1,
|
|
||||||
Y: player.cullingRect.Y - camera.Y - 1,
|
|
||||||
W: player.cullingRect.W + 2,
|
|
||||||
H: player.cullingRect.H + 2,
|
|
||||||
}
|
|
||||||
if camera.HasIntersection(&player.cullingRect) {
|
|
||||||
surface.FillRect(&cameraAdjustedCullingRectBorder, sdl.MapRGBA(surface.Format, 10, 255, 255, 64))
|
|
||||||
surface.FillRect(&cameraAdjustedCullingRect, sdl.MapRGBA(surface.Format, 255, 20, 10, 64))
|
|
||||||
surface.FillRect(&player.rect1, player.color1)
|
|
||||||
surface.FillRect(&player.rect2, player.color1)
|
|
||||||
surface.FillRect(&player.rect3, player.color2)
|
|
||||||
surface.FillRect(&player.rect4, player.color3)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *Player) digBlock(posX, posY int32, gameMap *GameMap, isShooting bool) uint8 {
|
func (player *Player) digBlock(posX, posY int32, gameMap *GameMap, isShooting bool) uint8 {
|
||||||
@ -122,7 +65,7 @@ func (player *Player) digBlock(posX, posY int32, gameMap *GameMap, isShooting bo
|
|||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *Player) tick() {
|
func (player *Player) tick(isShooting bool, bullets *[]*Bullet, format *sdl.PixelFormat) {
|
||||||
if player.digCooldown > 0 {
|
if player.digCooldown > 0 {
|
||||||
player.digCooldown--
|
player.digCooldown--
|
||||||
}
|
}
|
||||||
@ -138,6 +81,17 @@ func (player *Player) tick() {
|
|||||||
if player.movementCooldown > 0 {
|
if player.movementCooldown > 0 {
|
||||||
player.movementCooldown--
|
player.movementCooldown--
|
||||||
}
|
}
|
||||||
|
if player.reloadCooldown > 0 {
|
||||||
|
player.reloadCooldown--
|
||||||
|
} else if player.ammunition < MaxAmmunition && !isShooting && player.energy > ReloadCost {
|
||||||
|
player.ammunition++
|
||||||
|
player.reloadCooldown = ReloadCooldown
|
||||||
|
player.energy -= ReloadCost
|
||||||
|
}
|
||||||
|
if player.shields <= 0 {
|
||||||
|
player.shields = MaxShields + 1
|
||||||
|
player.explode(bullets)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *Player) tryMove(gameMap *GameMap, isShooting bool, players *[]*Player) (moved bool) {
|
func (player *Player) tryMove(gameMap *GameMap, isShooting bool, players *[]*Player) (moved bool) {
|
||||||
@ -151,21 +105,21 @@ func (player *Player) tryMove(gameMap *GameMap, isShooting bool, players *[]*Pla
|
|||||||
shouldPenalizeDigging := false
|
shouldPenalizeDigging := false
|
||||||
stopped := false
|
stopped := false
|
||||||
|
|
||||||
switch player.orientation {
|
switch player.gameObject.orientation {
|
||||||
case 0: // Up
|
case 0: // Up
|
||||||
collisionRect := sdl.Rect{
|
collisionRect := sdl.Rect{
|
||||||
X: player.posX,
|
X: player.gameObject.baseRect.X,
|
||||||
Y: player.posY - 1,
|
Y: player.gameObject.baseRect.Y - 1,
|
||||||
W: 5,
|
W: 5,
|
||||||
H: 7,
|
H: 7,
|
||||||
}
|
}
|
||||||
for _, opponent := range *players {
|
for _, opponent := range *players {
|
||||||
if opponent != player && opponent.cullingRect.HasIntersection(&collisionRect) {
|
if opponent != player && opponent.gameObject.baseRect.HasIntersection(&collisionRect) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for x := player.posX; x < player.posX+5 && !stopped; x++ {
|
for x := player.gameObject.baseRect.X; x < player.gameObject.baseRect.X+5 && !stopped; x++ {
|
||||||
for y := player.posY - 1; y < player.posY+7; y++ {
|
for y := player.gameObject.baseRect.Y - 1; y < player.gameObject.baseRect.Y+7; y++ {
|
||||||
digResult := player.digBlock(x, y, gameMap, isShooting)
|
digResult := player.digBlock(x, y, gameMap, isShooting)
|
||||||
if digResult == 1 {
|
if digResult == 1 {
|
||||||
shouldPenalizeDigging = true
|
shouldPenalizeDigging = true
|
||||||
@ -181,23 +135,23 @@ func (player *Player) tryMove(gameMap *GameMap, isShooting bool, players *[]*Pla
|
|||||||
}
|
}
|
||||||
if !stopped {
|
if !stopped {
|
||||||
moved = true
|
moved = true
|
||||||
player.posY--
|
player.gameObject.baseRect.Y--
|
||||||
}
|
}
|
||||||
|
|
||||||
case 1: // Right
|
case 1: // Right
|
||||||
collisionRect := sdl.Rect{
|
collisionRect := sdl.Rect{
|
||||||
X: player.posX + 1,
|
X: player.gameObject.baseRect.X + 1,
|
||||||
Y: player.posY,
|
Y: player.gameObject.baseRect.Y,
|
||||||
W: 7,
|
W: 7,
|
||||||
H: 5,
|
H: 5,
|
||||||
}
|
}
|
||||||
for _, opponent := range *players {
|
for _, opponent := range *players {
|
||||||
if opponent != player && opponent.cullingRect.HasIntersection(&collisionRect) {
|
if opponent != player && opponent.gameObject.baseRect.HasIntersection(&collisionRect) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for y := player.posY; y < player.posY+7 && !stopped; y++ {
|
for y := player.gameObject.baseRect.Y + 1; y < player.gameObject.baseRect.Y+6 && !stopped; y++ {
|
||||||
for x := player.posX + 1; x < player.posX+8; x++ {
|
for x := player.gameObject.baseRect.X + 1; x < player.gameObject.baseRect.X+8; x++ {
|
||||||
digResult := player.digBlock(x, y, gameMap, isShooting)
|
digResult := player.digBlock(x, y, gameMap, isShooting)
|
||||||
if digResult == 1 {
|
if digResult == 1 {
|
||||||
shouldPenalizeDigging = true
|
shouldPenalizeDigging = true
|
||||||
@ -213,23 +167,23 @@ func (player *Player) tryMove(gameMap *GameMap, isShooting bool, players *[]*Pla
|
|||||||
}
|
}
|
||||||
if !stopped {
|
if !stopped {
|
||||||
moved = true
|
moved = true
|
||||||
player.posX++
|
player.gameObject.baseRect.X++
|
||||||
}
|
}
|
||||||
|
|
||||||
case 2: // Down
|
case 2: // Down
|
||||||
collisionRect := sdl.Rect{
|
collisionRect := sdl.Rect{
|
||||||
X: player.posX,
|
X: player.gameObject.baseRect.X,
|
||||||
Y: player.posY + 1,
|
Y: player.gameObject.baseRect.Y + 1,
|
||||||
W: 5,
|
W: 5,
|
||||||
H: 7,
|
H: 7,
|
||||||
}
|
}
|
||||||
for _, opponent := range *players {
|
for _, opponent := range *players {
|
||||||
if opponent != player && opponent.cullingRect.HasIntersection(&collisionRect) {
|
if opponent != player && opponent.gameObject.baseRect.HasIntersection(&collisionRect) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for x := player.posX; x < player.posX+5 && !stopped; x++ {
|
for x := player.gameObject.baseRect.X; x < player.gameObject.baseRect.X+5 && !stopped; x++ {
|
||||||
for y := player.posY + 1; y < player.posY+8; y++ {
|
for y := player.gameObject.baseRect.Y + 1; y < player.gameObject.baseRect.Y+8; y++ {
|
||||||
digResult := player.digBlock(x, y, gameMap, isShooting)
|
digResult := player.digBlock(x, y, gameMap, isShooting)
|
||||||
if digResult == 1 {
|
if digResult == 1 {
|
||||||
shouldPenalizeDigging = true
|
shouldPenalizeDigging = true
|
||||||
@ -245,23 +199,23 @@ func (player *Player) tryMove(gameMap *GameMap, isShooting bool, players *[]*Pla
|
|||||||
}
|
}
|
||||||
if !stopped {
|
if !stopped {
|
||||||
moved = true
|
moved = true
|
||||||
player.posY++
|
player.gameObject.baseRect.Y++
|
||||||
}
|
}
|
||||||
|
|
||||||
case 3: // Left
|
case 3: // Left
|
||||||
collisionRect := sdl.Rect{
|
collisionRect := sdl.Rect{
|
||||||
X: player.posX - 1,
|
X: player.gameObject.baseRect.X - 1,
|
||||||
Y: player.posY,
|
Y: player.gameObject.baseRect.Y,
|
||||||
W: 7,
|
W: 7,
|
||||||
H: 5,
|
H: 5,
|
||||||
}
|
}
|
||||||
for _, opponent := range *players {
|
for _, opponent := range *players {
|
||||||
if opponent != player && opponent.cullingRect.HasIntersection(&collisionRect) {
|
if opponent != player && opponent.gameObject.baseRect.HasIntersection(&collisionRect) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for y := player.posY; y < player.posY+6 && !stopped; y++ {
|
for y := player.gameObject.baseRect.Y + 1; y < player.gameObject.baseRect.Y+6 && !stopped; y++ {
|
||||||
for x := player.posX - 1; x < player.posX+6; x++ {
|
for x := player.gameObject.baseRect.X - 1; x < player.gameObject.baseRect.X+6; x++ {
|
||||||
digResult := player.digBlock(x, y, gameMap, isShooting)
|
digResult := player.digBlock(x, y, gameMap, isShooting)
|
||||||
if digResult == 1 {
|
if digResult == 1 {
|
||||||
shouldPenalizeDigging = true
|
shouldPenalizeDigging = true
|
||||||
@ -277,23 +231,23 @@ func (player *Player) tryMove(gameMap *GameMap, isShooting bool, players *[]*Pla
|
|||||||
}
|
}
|
||||||
if !stopped {
|
if !stopped {
|
||||||
moved = true
|
moved = true
|
||||||
player.posX--
|
player.gameObject.baseRect.X--
|
||||||
}
|
}
|
||||||
|
|
||||||
case 4: // Up-Right
|
case 4: // Up-Right
|
||||||
collisionRect := sdl.Rect{
|
collisionRect := sdl.Rect{
|
||||||
X: player.posX + 1,
|
X: player.gameObject.baseRect.X + 1,
|
||||||
Y: player.posY - 1,
|
Y: player.gameObject.baseRect.Y - 1,
|
||||||
W: 7,
|
W: 7,
|
||||||
H: 7,
|
H: 7,
|
||||||
}
|
}
|
||||||
for _, opponent := range *players {
|
for _, opponent := range *players {
|
||||||
if opponent != player && opponent.cullingRect.HasIntersection(&collisionRect) {
|
if opponent != player && opponent.gameObject.baseRect.HasIntersection(&collisionRect) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for x := player.posX + 1; x < player.posX+8 && !stopped; x++ {
|
for x := player.gameObject.baseRect.X + 1; x < player.gameObject.baseRect.X+8 && !stopped; x++ {
|
||||||
for y := player.posY - 1; y < player.posY+7; y++ {
|
for y := player.gameObject.baseRect.Y - 1; y < player.gameObject.baseRect.Y+6; y++ {
|
||||||
digResult := player.digBlock(x, y, gameMap, isShooting)
|
digResult := player.digBlock(x, y, gameMap, isShooting)
|
||||||
if digResult == 1 {
|
if digResult == 1 {
|
||||||
shouldPenalizeDigging = true
|
shouldPenalizeDigging = true
|
||||||
@ -309,24 +263,24 @@ func (player *Player) tryMove(gameMap *GameMap, isShooting bool, players *[]*Pla
|
|||||||
}
|
}
|
||||||
if !stopped {
|
if !stopped {
|
||||||
moved = true
|
moved = true
|
||||||
player.posX++
|
player.gameObject.baseRect.X++
|
||||||
player.posY--
|
player.gameObject.baseRect.Y--
|
||||||
}
|
}
|
||||||
|
|
||||||
case 5: // Up-Left
|
case 5: // Up-Left
|
||||||
collisionRect := sdl.Rect{
|
collisionRect := sdl.Rect{
|
||||||
X: player.posX - 1,
|
X: player.gameObject.baseRect.X - 1,
|
||||||
Y: player.posY - 1,
|
Y: player.gameObject.baseRect.Y - 1,
|
||||||
W: 7,
|
W: 7,
|
||||||
H: 7,
|
H: 7,
|
||||||
}
|
}
|
||||||
for _, opponent := range *players {
|
for _, opponent := range *players {
|
||||||
if opponent != player && opponent.cullingRect.HasIntersection(&collisionRect) {
|
if opponent != player && opponent.gameObject.baseRect.HasIntersection(&collisionRect) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for x := player.posX - 1; x < player.posX+6 && !stopped; x++ {
|
for x := player.gameObject.baseRect.X - 1; x < player.gameObject.baseRect.X+6 && !stopped; x++ {
|
||||||
for y := player.posY - 1; y < player.posY+7; y++ {
|
for y := player.gameObject.baseRect.Y - 1; y < player.gameObject.baseRect.Y+6; y++ {
|
||||||
digResult := player.digBlock(x, y, gameMap, isShooting)
|
digResult := player.digBlock(x, y, gameMap, isShooting)
|
||||||
if digResult == 1 {
|
if digResult == 1 {
|
||||||
shouldPenalizeDigging = true
|
shouldPenalizeDigging = true
|
||||||
@ -342,24 +296,24 @@ func (player *Player) tryMove(gameMap *GameMap, isShooting bool, players *[]*Pla
|
|||||||
}
|
}
|
||||||
if !stopped {
|
if !stopped {
|
||||||
moved = true
|
moved = true
|
||||||
player.posX--
|
player.gameObject.baseRect.X--
|
||||||
player.posY--
|
player.gameObject.baseRect.Y--
|
||||||
}
|
}
|
||||||
|
|
||||||
case 6: // Down-Right
|
case 6: // Down-Right
|
||||||
collisionRect := sdl.Rect{
|
collisionRect := sdl.Rect{
|
||||||
X: player.posX + 1,
|
X: player.gameObject.baseRect.X + 1,
|
||||||
Y: player.posY + 1,
|
Y: player.gameObject.baseRect.Y + 1,
|
||||||
W: 7,
|
W: 7,
|
||||||
H: 7,
|
H: 7,
|
||||||
}
|
}
|
||||||
for _, opponent := range *players {
|
for _, opponent := range *players {
|
||||||
if opponent != player && opponent.cullingRect.HasIntersection(&collisionRect) {
|
if opponent != player && opponent.gameObject.baseRect.HasIntersection(&collisionRect) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for x := player.posX + 1; x < player.posX+8 && !stopped; x++ {
|
for x := player.gameObject.baseRect.X + 1; x < player.gameObject.baseRect.X+8 && !stopped; x++ {
|
||||||
for y := player.posY + 1; y < player.posY+8; y++ {
|
for y := player.gameObject.baseRect.Y + 1; y < player.gameObject.baseRect.Y+8; y++ {
|
||||||
digResult := player.digBlock(x, y, gameMap, isShooting)
|
digResult := player.digBlock(x, y, gameMap, isShooting)
|
||||||
if digResult == 1 {
|
if digResult == 1 {
|
||||||
shouldPenalizeDigging = true
|
shouldPenalizeDigging = true
|
||||||
@ -375,24 +329,24 @@ func (player *Player) tryMove(gameMap *GameMap, isShooting bool, players *[]*Pla
|
|||||||
}
|
}
|
||||||
if !stopped {
|
if !stopped {
|
||||||
moved = true
|
moved = true
|
||||||
player.posX++
|
player.gameObject.baseRect.X++
|
||||||
player.posY++
|
player.gameObject.baseRect.Y++
|
||||||
}
|
}
|
||||||
|
|
||||||
case 7: // Down-Left
|
case 7: // Down-Left
|
||||||
collisionRect := sdl.Rect{
|
collisionRect := sdl.Rect{
|
||||||
X: player.posX - 1,
|
X: player.gameObject.baseRect.X - 1,
|
||||||
Y: player.posY + 1,
|
Y: player.gameObject.baseRect.Y + 1,
|
||||||
W: 7,
|
W: 7,
|
||||||
H: 7,
|
H: 7,
|
||||||
}
|
}
|
||||||
for _, opponent := range *players {
|
for _, opponent := range *players {
|
||||||
if opponent != player && opponent.cullingRect.HasIntersection(&collisionRect) {
|
if opponent != player && opponent.gameObject.baseRect.HasIntersection(&collisionRect) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for x := player.posX - 1; x < player.posX+6 && !stopped; x++ {
|
for x := player.gameObject.baseRect.X - 1; x < player.gameObject.baseRect.X+6 && !stopped; x++ {
|
||||||
for y := player.posY + 1; y < player.posY+8; y++ {
|
for y := player.gameObject.baseRect.Y + 1; y < player.gameObject.baseRect.Y+8; y++ {
|
||||||
digResult := player.digBlock(x, y, gameMap, isShooting)
|
digResult := player.digBlock(x, y, gameMap, isShooting)
|
||||||
if digResult == 1 {
|
if digResult == 1 {
|
||||||
shouldPenalizeDigging = true
|
shouldPenalizeDigging = true
|
||||||
@ -408,13 +362,16 @@ func (player *Player) tryMove(gameMap *GameMap, isShooting bool, players *[]*Pla
|
|||||||
}
|
}
|
||||||
if !stopped {
|
if !stopped {
|
||||||
moved = true
|
moved = true
|
||||||
player.posX--
|
player.gameObject.baseRect.X--
|
||||||
player.posY++
|
player.gameObject.baseRect.Y++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Penalties and cooldown handling
|
// Penalties and cooldown handling
|
||||||
if shouldPenalizeDigging {
|
if shouldPenalizeDigging {
|
||||||
|
if isShooting && player.ammunition < MaxAmmunition && rand.Intn(2) == 0 {
|
||||||
|
player.ammunition++
|
||||||
|
}
|
||||||
if ranOutOfEnergy {
|
if ranOutOfEnergy {
|
||||||
player.digCooldown = DiggingCooldownNoEnergy
|
player.digCooldown = DiggingCooldownNoEnergy
|
||||||
}
|
}
|
||||||
@ -433,96 +390,327 @@ func (player *Player) tryMove(gameMap *GameMap, isShooting bool, players *[]*Pla
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *Player) shoot(super bool, bullets *[]*Bullet, format *sdl.PixelFormat) {
|
func (player *Player) getRGBAColor(colorIndex uint8, format *sdl.PixelFormat) uint32 {
|
||||||
if (super && player.energy <= SuperShotCost) || (!super && player.energy <= NormalShotCost) {
|
var selectedColor color.Color
|
||||||
|
switch colorIndex {
|
||||||
|
case 0:
|
||||||
|
selectedColor = player.playerColors.tracks
|
||||||
|
case 1:
|
||||||
|
selectedColor = player.playerColors.body
|
||||||
|
case 2:
|
||||||
|
selectedColor = player.playerColors.cannon
|
||||||
|
}
|
||||||
|
var r, g, b, a uint8
|
||||||
|
if selectedColor != nil {
|
||||||
|
rt, gt, bt, at := selectedColor.RGBA()
|
||||||
|
r, g, b, a = uint8(rt), uint8(gt), uint8(bt), uint8(at)
|
||||||
|
}
|
||||||
|
return sdl.MapRGBA(format, r, g, b, a)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (player *Player) shoot(super bool, bullets *[]*Bullet) {
|
||||||
|
if (super && (player.energy <= SuperShotCost || player.ammunition < MaxAmmunition)) || (!super && (player.energy <= NormalShotCost || player.ammunition < 1)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if player.shootCooldown == 0 {
|
if player.shootCooldown == 0 {
|
||||||
var shootX, shootY int32
|
var shootX, shootY int32
|
||||||
|
|
||||||
switch player.orientation {
|
switch player.gameObject.orientation {
|
||||||
case 0: // Up
|
case 0: // Up
|
||||||
shootY = player.posY - 1
|
shootY = player.gameObject.baseRect.Y - 1
|
||||||
shootX = player.posX + 2
|
shootX = player.gameObject.baseRect.X + 2
|
||||||
break
|
break
|
||||||
case 1: // Right
|
case 1: // Right
|
||||||
shootY = player.posY + 3
|
shootY = player.gameObject.baseRect.Y + 3
|
||||||
shootX = player.posX + 8
|
shootX = player.gameObject.baseRect.X + 8
|
||||||
break
|
break
|
||||||
case 2: // Down
|
case 2: // Down
|
||||||
shootX = player.posX + 2
|
shootX = player.gameObject.baseRect.X + 2
|
||||||
shootY = player.posY + 8
|
shootY = player.gameObject.baseRect.Y + 8
|
||||||
break
|
break
|
||||||
case 3: // Left
|
case 3: // Left
|
||||||
shootY = player.posY + 3
|
shootY = player.gameObject.baseRect.Y + 3
|
||||||
shootX = player.posX - 2
|
shootX = player.gameObject.baseRect.X - 2
|
||||||
break
|
break
|
||||||
case 4: // Up-Right
|
case 4: // Up-Right
|
||||||
shootY = player.posY - 1
|
shootY = player.gameObject.baseRect.Y
|
||||||
shootX = player.posX + 5
|
shootX = player.gameObject.baseRect.X + 5
|
||||||
break
|
break
|
||||||
case 5: // Up-Left
|
case 5: // Up-Left
|
||||||
shootY = player.posY - 1
|
shootY = player.gameObject.baseRect.Y
|
||||||
shootX = player.posX - 1
|
shootX = player.gameObject.baseRect.X - 1
|
||||||
break
|
break
|
||||||
case 6: // Down-Right
|
case 6: // Down-Right
|
||||||
shootY = player.posY + 5
|
shootY = player.gameObject.baseRect.Y + 5
|
||||||
shootX = player.posX + 5
|
shootX = player.gameObject.baseRect.X + 5
|
||||||
break
|
break
|
||||||
case 7: // Down-Left
|
case 7: // Down-Left
|
||||||
shootY = player.posY + 5
|
shootY = player.gameObject.baseRect.Y + 5
|
||||||
shootX = player.posX - 1
|
shootX = player.gameObject.baseRect.X - 1
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set bullet color
|
// Set bullet color
|
||||||
r, g, b, a := sdl.GetRGBA(player.color2, format)
|
bulletColor := player.playerColors.body
|
||||||
bulletColor := color.RGBA{R: r, G: g, B: b, A: a}
|
|
||||||
|
|
||||||
// Create and add the bullet
|
// Create and add the bullet
|
||||||
*bullets = append(*bullets, &Bullet{
|
*bullets = append(*bullets, &Bullet{
|
||||||
posX: shootX,
|
posX: shootX,
|
||||||
posY: shootY,
|
posY: shootY,
|
||||||
direction: player.orientation,
|
direction: player.gameObject.orientation,
|
||||||
color: bulletColor,
|
color: bulletColor,
|
||||||
super: super,
|
super: super,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Set cooldown and decrease energy
|
// Set cooldown and decrease energy
|
||||||
player.shootCooldown = ShootCooldown
|
player.shootCooldown = ShootCooldown
|
||||||
if super {
|
if super {
|
||||||
player.energy -= SuperShotCost
|
player.energy -= SuperShotCost
|
||||||
|
player.ammunition = 0
|
||||||
} else {
|
} else {
|
||||||
player.energy -= NormalShotCost
|
player.energy -= NormalShotCost
|
||||||
|
player.ammunition--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createPlayer(color1 uint32, color2 uint32, color3 uint32, gameMap *GameMap, players *[]*Player) {
|
func (player *Player) explode(bullets *[]*Bullet) {
|
||||||
|
// Set bullet color
|
||||||
|
bulletColor := player.playerColors.body
|
||||||
|
|
||||||
|
for x := player.gameObject.baseRect.X - BlastRadius; x < BlastRadius*2+1; x++ {
|
||||||
|
for y := player.gameObject.baseRect.Y - BlastRadius; y < BlastRadius*2+1; y++ {
|
||||||
|
// Create and add the bullet
|
||||||
|
*bullets = append(*bullets, &Bullet{
|
||||||
|
posX: x,
|
||||||
|
posY: y,
|
||||||
|
direction: uint8(rand.Intn(8)),
|
||||||
|
color: bulletColor,
|
||||||
|
super: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createPlayers(amount uint8, playerColors []PlayerColors, keyMaps []KeyMap, joyMaps []JoyMap, gameMap *GameMap, players *[]*Player) {
|
||||||
|
joyStickCount := sdl.NumJoysticks()
|
||||||
|
if amount > uint8(len(keyMaps)+len(joyMaps)) || amount > uint8(len(keyMaps)+joyStickCount) {
|
||||||
|
panic("Too many players, not enough inputs")
|
||||||
|
}
|
||||||
|
if amount >= uint8(len(playerColors)) {
|
||||||
|
panic("Too many players, not enough colors")
|
||||||
|
}
|
||||||
|
addedKeyboardPlayers := 0
|
||||||
|
for i := uint8(0); i < amount; i++ {
|
||||||
|
var keyMap KeyMap
|
||||||
|
var joyMap JoyMap
|
||||||
|
var joyStick *sdl.Joystick
|
||||||
|
|
||||||
|
if (DoAllKeymapsPlayers && i <= uint8(len(keyMaps))) || (DoKeymapPlayer && i == 0) || (uint8(joyStickCount) <= i) {
|
||||||
|
keyMap = keyMaps[addedKeyboardPlayers]
|
||||||
|
addedKeyboardPlayers++
|
||||||
|
} else {
|
||||||
|
joyStickIndex := i - uint8(addedKeyboardPlayers)
|
||||||
|
joyMap = joyMaps[joyStickIndex]
|
||||||
|
joyStick = sdl.JoystickOpen(int(joyStickIndex))
|
||||||
|
}
|
||||||
|
createPlayer(
|
||||||
|
playerColors[i],
|
||||||
|
keyMap,
|
||||||
|
joyMap,
|
||||||
|
joyStick,
|
||||||
|
gameMap,
|
||||||
|
players,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeThings(players *[]*Player) {
|
||||||
|
for _, player := range *players {
|
||||||
|
if player.joyStick != nil {
|
||||||
|
player.joyStick.Close()
|
||||||
|
}
|
||||||
|
if player.window != nil {
|
||||||
|
player.window.Destroy()
|
||||||
|
}
|
||||||
|
if player.logicalSurface != nil {
|
||||||
|
player.logicalSurface.Free()
|
||||||
|
}
|
||||||
|
if player.playSurface != nil {
|
||||||
|
player.playSurface.Free()
|
||||||
|
}
|
||||||
|
if player.HUDSurface != nil {
|
||||||
|
player.HUDSurface.Free()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createPlayer(playerColors PlayerColors, keyMap KeyMap, joyMap JoyMap, joyStick *sdl.Joystick, gameMap *GameMap, players *[]*Player) {
|
||||||
coordsAreValid := false
|
coordsAreValid := false
|
||||||
var posX, posY int32
|
var posX, posY int32
|
||||||
for !coordsAreValid {
|
maxTries := 1000
|
||||||
posX = int32(16 + rand.Intn(int(gameMap.width-36)))
|
for !coordsAreValid && maxTries >= 0 {
|
||||||
posY = int32(16 + rand.Intn(int(gameMap.height-36)))
|
maxTries--
|
||||||
|
posX = int32(16 + rand.Intn(int(gameMap.width-43)))
|
||||||
|
posY = int32(16 + rand.Intn(int(gameMap.height-43)))
|
||||||
|
|
||||||
coordsAreValid = true
|
coordsAreValid = true
|
||||||
for _, player := range *players {
|
for _, player := range *players {
|
||||||
distance := (player.posX-posX)*(player.posX-posX) + (player.posY-posY)*(player.posY-posY)
|
distance := (player.gameObject.baseRect.X-posX)*(player.gameObject.baseRect.X-posX) +
|
||||||
|
(player.gameObject.baseRect.Y-posY)*(player.gameObject.baseRect.Y-posY)
|
||||||
if distance < 300*300 { // Check if distance is less than 300 units
|
if distance < 300*300 { // Check if distance is less than 300 units
|
||||||
coordsAreValid = false
|
coordsAreValid = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if posX < 16 || posX > gameMap.width-36-7 || posY < 16 || posY > gameMap.height-36-7 {
|
||||||
|
coordsAreValid = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if maxTries < 0 {
|
||||||
|
panic("Could not place all players, increase map size")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gameObject := &GameObject{}
|
||||||
|
|
||||||
|
gameObject.baseRect = sdl.Rect{
|
||||||
|
X: posX,
|
||||||
|
Y: posY,
|
||||||
|
W: 7,
|
||||||
|
H: 7,
|
||||||
|
}
|
||||||
|
|
||||||
|
gameObject.addColor(playerColors.tracks)
|
||||||
|
gameObject.addColor(playerColors.body)
|
||||||
|
gameObject.addColor(playerColors.cannon)
|
||||||
|
|
||||||
|
gameObject.orientation = 0 // Up
|
||||||
|
gameObject.addColoredRect(0, 1, 1, 6, 0)
|
||||||
|
gameObject.addColoredRect(4, 1, 1, 6, 0)
|
||||||
|
gameObject.addColoredRect(1, 2, 3, 4, 1)
|
||||||
|
gameObject.addColoredRect(2, 0, 1, 4, 2)
|
||||||
|
|
||||||
|
gameObject.orientation = 1 // Right
|
||||||
|
gameObject.addColoredRect(1, 1, 6, 1, 0)
|
||||||
|
gameObject.addColoredRect(1, 5, 6, 1, 0)
|
||||||
|
gameObject.addColoredRect(2, 2, 4, 3, 1)
|
||||||
|
gameObject.addColoredRect(4, 3, 4, 1, 2)
|
||||||
|
|
||||||
|
gameObject.orientation = 2 // Down
|
||||||
|
gameObject.addColoredRect(0, 1, 1, 6, 0)
|
||||||
|
gameObject.addColoredRect(4, 1, 1, 6, 0)
|
||||||
|
gameObject.addColoredRect(1, 2, 3, 4, 1)
|
||||||
|
gameObject.addColoredRect(2, 4, 1, 4, 2)
|
||||||
|
|
||||||
|
gameObject.orientation = 3 // Left
|
||||||
|
gameObject.addColoredRect(1, 1, 6, 1, 0)
|
||||||
|
gameObject.addColoredRect(1, 5, 6, 1, 0)
|
||||||
|
gameObject.addColoredRect(2, 2, 4, 3, 1)
|
||||||
|
gameObject.addColoredRect(0, 3, 4, 1, 2)
|
||||||
|
|
||||||
|
gameObject.orientation = 4 // Up-Right
|
||||||
|
gameObject.addColoredRect(3, 0, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(2, 1, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(1, 2, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(0, 3, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(6, 3, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(5, 4, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(4, 5, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(3, 6, 1, 1, 0)
|
||||||
|
|
||||||
|
gameObject.addColoredRect(3, 1, 1, 1, 1)
|
||||||
|
gameObject.addColoredRect(2, 2, 2, 1, 1)
|
||||||
|
gameObject.addColoredRect(1, 3, 2, 1, 1)
|
||||||
|
|
||||||
|
gameObject.addColoredRect(4, 3, 2, 1, 1)
|
||||||
|
gameObject.addColoredRect(2, 4, 3, 1, 1)
|
||||||
|
gameObject.addColoredRect(3, 5, 1, 1, 1)
|
||||||
|
|
||||||
|
gameObject.addColoredRect(5, 1, 1, 1, 2)
|
||||||
|
gameObject.addColoredRect(4, 2, 1, 1, 2)
|
||||||
|
gameObject.addColoredRect(3, 3, 1, 1, 2)
|
||||||
|
|
||||||
|
// Up-Left orientation (Y-axis reflection)
|
||||||
|
gameObject.orientation = 5 // Up-Left
|
||||||
|
gameObject.addColoredRect(3, 0, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(4, 1, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(5, 2, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(6, 3, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(0, 3, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(1, 4, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(2, 5, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(3, 6, 1, 1, 0)
|
||||||
|
|
||||||
|
gameObject.addColoredRect(3, 1, 1, 1, 1)
|
||||||
|
gameObject.addColoredRect(3, 2, 2, 1, 1)
|
||||||
|
gameObject.addColoredRect(4, 3, 2, 1, 1)
|
||||||
|
|
||||||
|
gameObject.addColoredRect(1, 3, 2, 1, 1)
|
||||||
|
gameObject.addColoredRect(2, 4, 3, 1, 1)
|
||||||
|
gameObject.addColoredRect(3, 5, 1, 1, 1)
|
||||||
|
|
||||||
|
gameObject.addColoredRect(1, 1, 1, 1, 2)
|
||||||
|
gameObject.addColoredRect(2, 2, 1, 1, 2)
|
||||||
|
gameObject.addColoredRect(3, 3, 1, 1, 2)
|
||||||
|
|
||||||
|
// Down-Right orientation (X-axis reflection)
|
||||||
|
gameObject.orientation = 6 // Down-Right
|
||||||
|
gameObject.addColoredRect(3, 6, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(2, 5, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(1, 4, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(0, 3, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(6, 3, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(5, 2, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(4, 1, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(3, 0, 1, 1, 0)
|
||||||
|
|
||||||
|
gameObject.addColoredRect(3, 5, 1, 1, 1)
|
||||||
|
gameObject.addColoredRect(2, 4, 2, 1, 1)
|
||||||
|
gameObject.addColoredRect(1, 3, 2, 1, 1)
|
||||||
|
|
||||||
|
gameObject.addColoredRect(4, 3, 2, 1, 1)
|
||||||
|
gameObject.addColoredRect(2, 2, 3, 1, 1)
|
||||||
|
gameObject.addColoredRect(3, 1, 1, 1, 1)
|
||||||
|
|
||||||
|
gameObject.addColoredRect(5, 5, 1, 1, 2)
|
||||||
|
gameObject.addColoredRect(4, 4, 1, 1, 2)
|
||||||
|
gameObject.addColoredRect(3, 3, 1, 1, 2)
|
||||||
|
|
||||||
|
// Down-Left orientation (XY reflection)
|
||||||
|
gameObject.orientation = 7 // Down-Left
|
||||||
|
gameObject.addColoredRect(3, 6, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(4, 5, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(5, 4, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(6, 3, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(0, 3, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(1, 2, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(2, 1, 1, 1, 0)
|
||||||
|
gameObject.addColoredRect(3, 0, 1, 1, 0)
|
||||||
|
|
||||||
|
gameObject.addColoredRect(3, 1, 1, 1, 1)
|
||||||
|
gameObject.addColoredRect(2, 2, 3, 1, 1)
|
||||||
|
gameObject.addColoredRect(1, 3, 2, 1, 1)
|
||||||
|
|
||||||
|
gameObject.addColoredRect(4, 3, 2, 1, 1)
|
||||||
|
gameObject.addColoredRect(3, 4, 2, 1, 1)
|
||||||
|
gameObject.addColoredRect(3, 5, 1, 1, 1)
|
||||||
|
|
||||||
|
gameObject.addColoredRect(1, 5, 1, 1, 2)
|
||||||
|
gameObject.addColoredRect(2, 4, 1, 1, 2)
|
||||||
|
gameObject.addColoredRect(3, 3, 1, 1, 2)
|
||||||
|
|
||||||
|
gameObject.orientation = 0
|
||||||
|
|
||||||
*players = append(*players, &Player{
|
*players = append(*players, &Player{
|
||||||
posX: posX,
|
playerColors: playerColors,
|
||||||
posY: posY,
|
keyMap: keyMap,
|
||||||
orientation: 3,
|
joyMap: joyMap,
|
||||||
color1: color1,
|
joyStick: joyStick,
|
||||||
color2: color2,
|
shields: MaxShields,
|
||||||
color3: color3,
|
|
||||||
health: MaxHealth,
|
|
||||||
energy: MaxEnergy,
|
energy: MaxEnergy,
|
||||||
|
gameObject: gameObject,
|
||||||
|
local: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
387
playerData.go
Normal file
387
playerData.go
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
|
"image/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
type KeyMap struct {
|
||||||
|
exit int
|
||||||
|
shoot int
|
||||||
|
super int
|
||||||
|
up int
|
||||||
|
down int
|
||||||
|
left int
|
||||||
|
right int
|
||||||
|
}
|
||||||
|
|
||||||
|
var keyMaps = []KeyMap{
|
||||||
|
{
|
||||||
|
exit: sdl.SCANCODE_ESCAPE,
|
||||||
|
shoot: sdl.SCANCODE_SPACE,
|
||||||
|
super: sdl.SCANCODE_LCTRL,
|
||||||
|
up: sdl.SCANCODE_W,
|
||||||
|
down: sdl.SCANCODE_S,
|
||||||
|
left: sdl.SCANCODE_A,
|
||||||
|
right: sdl.SCANCODE_D,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
exit: sdl.SCANCODE_END,
|
||||||
|
shoot: sdl.SCANCODE_RETURN,
|
||||||
|
super: sdl.SCANCODE_RCTRL,
|
||||||
|
up: sdl.SCANCODE_UP,
|
||||||
|
down: sdl.SCANCODE_DOWN,
|
||||||
|
left: sdl.SCANCODE_LEFT,
|
||||||
|
right: sdl.SCANCODE_RIGHT,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type JoyMap struct {
|
||||||
|
xAxis int
|
||||||
|
yAxis int
|
||||||
|
|
||||||
|
exitButton int
|
||||||
|
shootButton int
|
||||||
|
superButton int
|
||||||
|
|
||||||
|
upButton int
|
||||||
|
downButton int
|
||||||
|
leftButton int
|
||||||
|
rightButton int
|
||||||
|
}
|
||||||
|
|
||||||
|
var joyMaps = []JoyMap{
|
||||||
|
{
|
||||||
|
xAxis: 0,
|
||||||
|
yAxis: 1,
|
||||||
|
|
||||||
|
exitButton: 0,
|
||||||
|
shootButton: 1,
|
||||||
|
superButton: 2,
|
||||||
|
|
||||||
|
upButton: 3,
|
||||||
|
downButton: 4,
|
||||||
|
leftButton: 5,
|
||||||
|
rightButton: 6,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type PlayerColors struct {
|
||||||
|
tracks color.Color
|
||||||
|
body color.Color
|
||||||
|
cannon color.Color
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNeededPlayers() (neededPlayers uint8) {
|
||||||
|
neededPlayers = 0
|
||||||
|
if DoAllKeymapsPlayers {
|
||||||
|
neededPlayers += uint8(len(keyMaps))
|
||||||
|
} else if DoKeymapPlayer && len(keyMaps) > 0 {
|
||||||
|
neededPlayers++
|
||||||
|
}
|
||||||
|
if DoJoyStickPlayers {
|
||||||
|
neededPlayers += uint8(sdl.NumJoysticks())
|
||||||
|
}
|
||||||
|
if neededPlayers < 2 {
|
||||||
|
neededPlayers = 2
|
||||||
|
}
|
||||||
|
return neededPlayers
|
||||||
|
}
|
||||||
|
|
||||||
|
var playerColors []PlayerColors
|
||||||
|
|
||||||
|
func initPlayerColors() {
|
||||||
|
playerColors = []PlayerColors{
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{B: 182, A: 255},
|
||||||
|
body: color.RGBA{R: 44, G: 44, B: 255, A: 255},
|
||||||
|
cannon: color.RGBA{R: 243, G: 235, B: 28, A: 255},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 44, G: 184, B: 44, A: 255},
|
||||||
|
body: color.RGBA{G: 249, A: 255},
|
||||||
|
cannon: color.RGBA{R: 243, G: 235, B: 28, A: 255},
|
||||||
|
},
|
||||||
|
// Set 3
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 255, A: 255}, // Bright Red
|
||||||
|
body: color.RGBA{G: 255, B: 255, A: 255}, // Cyan
|
||||||
|
cannon: color.RGBA{R: 255, G: 165, A: 255}, // Orange
|
||||||
|
},
|
||||||
|
// Set 4
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 75, B: 130, A: 255}, // Indigo
|
||||||
|
body: color.RGBA{R: 255, G: 20, B: 147, A: 255}, // Deep Pink
|
||||||
|
cannon: color.RGBA{G: 128, B: 128, A: 255}, // Teal
|
||||||
|
},
|
||||||
|
// Set 5
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 255, G: 105, B: 180, A: 255}, // Hot Pink
|
||||||
|
body: color.RGBA{R: 34, G: 139, B: 34, A: 255}, // Forest Green
|
||||||
|
cannon: color.RGBA{A: 255}, // Black
|
||||||
|
},
|
||||||
|
// Set 6
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 128, A: 255}, // Maroon
|
||||||
|
body: color.RGBA{R: 255, G: 255, A: 255}, // Yellow
|
||||||
|
cannon: color.RGBA{B: 128, A: 255}, // Navy Blue
|
||||||
|
},
|
||||||
|
// Set 7
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 255, G: 69, A: 255}, // Red-Orange
|
||||||
|
body: color.RGBA{G: 206, B: 209, A: 255}, // Dark Turquoise
|
||||||
|
cannon: color.RGBA{R: 50, G: 205, B: 50, A: 255}, // Lime Green
|
||||||
|
},
|
||||||
|
// Set 8
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 128, G: 128, A: 255}, // Olive
|
||||||
|
body: color.RGBA{R: 255, G: 105, B: 180, A: 255}, // Hot Pink
|
||||||
|
cannon: color.RGBA{G: 191, B: 255, A: 255}, // Deep Sky Blue
|
||||||
|
},
|
||||||
|
// Set 9
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 255, G: 20, B: 20, A: 255}, // Bright Red
|
||||||
|
body: color.RGBA{G: 255, B: 127, A: 255}, // Spring Green
|
||||||
|
cannon: color.RGBA{R: 186, G: 85, B: 211, A: 255}, // Medium Orchid
|
||||||
|
},
|
||||||
|
// Set 10
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 255, G: 215, A: 255}, // Gold
|
||||||
|
body: color.RGBA{B: 139, A: 255}, // Dark Blue
|
||||||
|
cannon: color.RGBA{R: 238, G: 130, B: 238, A: 255}, // Violet
|
||||||
|
},
|
||||||
|
// Set 11
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 210, G: 105, B: 30, A: 255}, // Chocolate
|
||||||
|
body: color.RGBA{R: 72, G: 61, B: 139, A: 255}, // Dark Slate Blue
|
||||||
|
cannon: color.RGBA{R: 152, G: 251, B: 152, A: 255}, // Pale Green
|
||||||
|
},
|
||||||
|
// Set 12
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 220, G: 20, B: 60, A: 255}, // Crimson
|
||||||
|
body: color.RGBA{R: 255, G: 250, B: 205, A: 255}, // Lemon Chiffon
|
||||||
|
cannon: color.RGBA{G: 128, A: 255}, // Green
|
||||||
|
},
|
||||||
|
// Set 13
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 139, B: 139, A: 255}, // Dark Magenta
|
||||||
|
body: color.RGBA{R: 144, G: 238, B: 144, A: 255}, // Light Green
|
||||||
|
cannon: color.RGBA{R: 255, G: 69, A: 255}, // Orange Red
|
||||||
|
},
|
||||||
|
// Set 14
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{B: 255, A: 255}, // Blue
|
||||||
|
body: color.RGBA{R: 240, G: 128, B: 128, A: 255}, // Light Coral
|
||||||
|
cannon: color.RGBA{R: 218, G: 165, B: 32, A: 255}, // Goldenrod
|
||||||
|
},
|
||||||
|
// Set 15
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 65, G: 105, B: 225, A: 255}, // Royal Blue
|
||||||
|
body: color.RGBA{R: 255, G: 222, B: 173, A: 255}, // Navajo White
|
||||||
|
cannon: color.RGBA{R: 255, B: 255, A: 255}, // Magenta
|
||||||
|
},
|
||||||
|
// Set 16
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 147, G: 112, B: 219, A: 255}, // Medium Purple
|
||||||
|
body: color.RGBA{G: 255, B: 127, A: 255}, // Spring Green
|
||||||
|
cannon: color.RGBA{R: 255, G: 255, A: 255}, // Yellow
|
||||||
|
},
|
||||||
|
// Set 17
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 255, G: 140, A: 255}, // Dark Orange
|
||||||
|
body: color.RGBA{R: 127, G: 255, A: 255}, // Chartreuse
|
||||||
|
cannon: color.RGBA{R: 25, G: 25, B: 112, A: 255}, // Midnight Blue
|
||||||
|
},
|
||||||
|
// Set 18
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 240, G: 230, B: 140, A: 255}, // Khaki
|
||||||
|
body: color.RGBA{R: 173, G: 216, B: 230, A: 255}, // Light Blue
|
||||||
|
cannon: color.RGBA{R: 128, B: 128, A: 255}, // Purple
|
||||||
|
},
|
||||||
|
// Set 19
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 70, G: 130, B: 180, A: 255}, // Steel Blue
|
||||||
|
body: color.RGBA{R: 255, G: 99, B: 71, A: 255}, // Tomato
|
||||||
|
cannon: color.RGBA{R: 154, G: 205, B: 50, A: 255}, // Yellow Green
|
||||||
|
},
|
||||||
|
// Set 20
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 106, G: 90, B: 205, A: 255}, // Slate Blue
|
||||||
|
body: color.RGBA{R: 255, G: 182, B: 193, A: 255}, // Light Pink
|
||||||
|
cannon: color.RGBA{R: 46, G: 139, B: 87, A: 255}, // Sea Green
|
||||||
|
},
|
||||||
|
// Set 21
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 199, G: 21, B: 133, A: 255}, // Medium Violet Red
|
||||||
|
body: color.RGBA{G: 255, B: 255, A: 255}, // Aqua
|
||||||
|
cannon: color.RGBA{R: 255, G: 160, B: 122, A: 255}, // Light Salmon
|
||||||
|
},
|
||||||
|
// Set 22
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{B: 139, A: 255}, // Dark Blue
|
||||||
|
body: color.RGBA{R: 173, G: 255, B: 47, A: 255}, // Green Yellow
|
||||||
|
cannon: color.RGBA{R: 255, G: 228, B: 181, A: 255},
|
||||||
|
},
|
||||||
|
// Set 23
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 205, G: 92, B: 92, A: 255}, // Indian Red
|
||||||
|
body: color.RGBA{G: 191, B: 255, A: 255}, // Deep Sky Blue
|
||||||
|
cannon: color.RGBA{R: 255, G: 255, B: 224, A: 255}, // Light Yellow
|
||||||
|
},
|
||||||
|
// Set 24
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 139, G: 69, B: 19, A: 255}, // Saddle Brown
|
||||||
|
body: color.RGBA{R: 255, G: 99, B: 71, A: 255}, // Tomato
|
||||||
|
cannon: color.RGBA{R: 70, G: 130, B: 180, A: 255}, // Steel Blue
|
||||||
|
},
|
||||||
|
// Set 25
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 135, G: 206, B: 250, A: 255}, // Light Sky Blue
|
||||||
|
body: color.RGBA{R: 255, G: 105, B: 180, A: 255}, // Hot Pink
|
||||||
|
cannon: color.RGBA{R: 184, G: 134, B: 11, A: 255}, // Dark Goldenrod
|
||||||
|
},
|
||||||
|
// Set 26
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{G: 255, A: 255}, // Lime
|
||||||
|
body: color.RGBA{R: 255, G: 228, B: 225, A: 255}, // Misty Rose
|
||||||
|
cannon: color.RGBA{R: 128, A: 255}, // Maroon
|
||||||
|
},
|
||||||
|
// Set 27
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 255, B: 255, A: 255}, // Magenta
|
||||||
|
body: color.RGBA{G: 100, A: 255}, // Dark Green
|
||||||
|
cannon: color.RGBA{R: 255, G: 222, B: 173, A: 255}, // Navajo White
|
||||||
|
},
|
||||||
|
// Set 28
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 138, G: 43, B: 226, A: 255}, // Blue Violet
|
||||||
|
body: color.RGBA{R: 255, G: 228, B: 181, A: 255}, // Moccasin
|
||||||
|
cannon: color.RGBA{R: 47, G: 79, B: 79, A: 255}, // Dark Slate Gray
|
||||||
|
},
|
||||||
|
// Set 29
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 255, G: 182, B: 193, A: 255}, // Light Pink
|
||||||
|
body: color.RGBA{G: 128, B: 128, A: 255}, // Teal
|
||||||
|
cannon: color.RGBA{R: 255, G: 255, B: 240, A: 255}, // Ivory
|
||||||
|
},
|
||||||
|
// Set 30
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 255, G: 127, B: 80, A: 255}, // Coral
|
||||||
|
body: color.RGBA{R: 25, G: 25, B: 112, A: 255}, // Midnight Blue
|
||||||
|
cannon: color.RGBA{R: 173, G: 255, B: 47, A: 255}, // Green Yellow
|
||||||
|
},
|
||||||
|
// Set 31
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{R: 218, G: 112, B: 214, A: 255}, // Orchid
|
||||||
|
body: color.RGBA{R: 244, G: 164, B: 96, A: 255}, // Sandy Brown
|
||||||
|
cannon: color.RGBA{R: 255, G: 239, B: 213, A: 255}, // Papaya Whip
|
||||||
|
},
|
||||||
|
// Set 32
|
||||||
|
{
|
||||||
|
tracks: color.RGBA{G: 250, B: 154, A: 255}, // Medium Spring Green
|
||||||
|
body: color.RGBA{R: 138, G: 43, B: 226, A: 255}, // Blue Violet
|
||||||
|
cannon: color.RGBA{R: 255, G: 69, A: 255}, // Orange Red
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleInput(keyboard []uint8, bullets *[]*Bullet, player *Player, gameMap *GameMap, format *sdl.PixelFormat, players *[]*Player) (bool, bool) {
|
||||||
|
if !player.local || player.shields <= 0 || player.shields > MaxShields {
|
||||||
|
return true, false
|
||||||
|
}
|
||||||
|
shoot := false
|
||||||
|
super := false
|
||||||
|
|
||||||
|
// Flags to track movement in each direction
|
||||||
|
moveUp := false
|
||||||
|
moveDown := false
|
||||||
|
moveLeft := false
|
||||||
|
moveRight := false
|
||||||
|
|
||||||
|
if player.keyMap.exit != player.keyMap.shoot {
|
||||||
|
// Process keyboard input
|
||||||
|
for key, value := range keyboard {
|
||||||
|
if value == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if key == player.keyMap.exit {
|
||||||
|
return false, shoot
|
||||||
|
} else if key == player.keyMap.shoot {
|
||||||
|
shoot = true
|
||||||
|
} else if key == player.keyMap.super {
|
||||||
|
super = true
|
||||||
|
} else if key == player.keyMap.up {
|
||||||
|
moveUp = true
|
||||||
|
} else if key == player.keyMap.down {
|
||||||
|
moveDown = true
|
||||||
|
} else if key == player.keyMap.left {
|
||||||
|
moveLeft = true
|
||||||
|
} else if key == player.keyMap.right {
|
||||||
|
moveRight = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if player.joyStick != nil {
|
||||||
|
if player.joyStick.NumAxes() > player.joyMap.xAxis+1 &&
|
||||||
|
player.joyStick.NumAxes() > player.joyMap.yAxis+1 &&
|
||||||
|
player.joyMap.exitButton != player.joyMap.shootButton {
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
} else {
|
||||||
|
moveUp = player.joyStick.Button(player.joyMap.upButton) == sdl.PRESSED
|
||||||
|
moveDown = player.joyStick.Button(player.joyMap.downButton) == sdl.PRESSED
|
||||||
|
moveLeft = player.joyStick.Button(player.joyMap.leftButton) == sdl.PRESSED
|
||||||
|
moveRight = player.joyStick.Button(player.joyMap.rightButton) == sdl.PRESSED
|
||||||
|
}
|
||||||
|
if player.joyStick.Button(player.joyMap.exitButton) == sdl.PRESSED {
|
||||||
|
return false, shoot
|
||||||
|
}
|
||||||
|
if player.joyStick.Button(player.joyMap.shootButton) == sdl.PRESSED {
|
||||||
|
shoot = true
|
||||||
|
}
|
||||||
|
if player.joyStick.Button(player.joyMap.superButton) == sdl.PRESSED {
|
||||||
|
super = true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle shooting after the loop
|
||||||
|
if shoot {
|
||||||
|
player.shoot(super, bullets)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine player orientation for diagonal movement
|
||||||
|
if moveUp && moveRight {
|
||||||
|
player.gameObject.orientation = 4 // Up-Right
|
||||||
|
} else if moveUp && moveLeft {
|
||||||
|
player.gameObject.orientation = 5 // Up-Left
|
||||||
|
} else if moveDown && moveRight {
|
||||||
|
player.gameObject.orientation = 6 // Down-Right
|
||||||
|
} else if moveDown && moveLeft {
|
||||||
|
player.gameObject.orientation = 7 // Down-Left
|
||||||
|
} else if moveUp {
|
||||||
|
player.gameObject.orientation = 0 // Up
|
||||||
|
} else if moveRight {
|
||||||
|
player.gameObject.orientation = 1 // Right
|
||||||
|
} else if moveDown {
|
||||||
|
player.gameObject.orientation = 2 // Down
|
||||||
|
} else if moveLeft {
|
||||||
|
player.gameObject.orientation = 3 // Left
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle movement after the loop
|
||||||
|
if moveUp || moveDown || moveLeft || moveRight {
|
||||||
|
if player.tryMove(gameMap, shoot, players) {
|
||||||
|
player.energy -= MovementCost
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, shoot
|
||||||
|
}
|
38
profiler.go
Normal file
38
profiler.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
|
)
|
||||||
|
|
||||||
|
func profileSection(section func()) uint64 {
|
||||||
|
start := sdl.GetTicks64()
|
||||||
|
section()
|
||||||
|
end := sdl.GetTicks64()
|
||||||
|
return end - start
|
||||||
|
}
|
||||||
|
|
||||||
|
func logProfilingInfo(handleEventsTime, renderTime, scaleTime, frameTime, frameCount uint64) {
|
||||||
|
floatFrame := float64(frameCount)
|
||||||
|
fmt.Printf("Average handleEvents time: %f ms\n", float64(handleEventsTime)/floatFrame)
|
||||||
|
fmt.Printf("Average render time: %f ms\n", float64(renderTime)/floatFrame)
|
||||||
|
fmt.Printf("Average scaling time: %f ms\n", float64(scaleTime)/floatFrame)
|
||||||
|
fmt.Printf("Average frame time: %f ms\n", float64(frameTime)/floatFrame)
|
||||||
|
fmt.Print("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetProfilingCounters(handleEventsTime, renderTime, scaleTime, frameTime *uint64, frameCount *uint64) {
|
||||||
|
*handleEventsTime = 0
|
||||||
|
*renderTime = 0
|
||||||
|
*scaleTime = 0
|
||||||
|
*frameTime = 0
|
||||||
|
*frameCount = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func enforceFrameRate(frameStart uint64, targetFPS int) {
|
||||||
|
frameDuration := 1000 / targetFPS
|
||||||
|
elapsed := sdl.GetTicks64() - frameStart
|
||||||
|
if delay := frameDuration - int(elapsed); delay > 0 {
|
||||||
|
sdl.Delay(uint32(delay))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user