Apply physics calculations using map rects

This commit is contained in:
Trevor Slocum 2023-01-24 22:22:10 -08:00
parent 843c254cec
commit 383cfdc182
4 changed files with 70 additions and 16 deletions

View File

@ -40,6 +40,12 @@ const (
PlayerWidth = 16
)
func RectTouches(r1 image.Rectangle, r2 image.Rectangle) bool {
return !r1.Empty() && !r2.Empty() &&
r1.Min.X <= r2.Max.X && r2.Min.X <= r1.Max.X &&
r1.Min.Y <= r2.Max.Y && r2.Min.Y <= r1.Max.Y
}
// stdHit returns FrameData using a standard hitbox and the provided sprite.
func stdHit(sprite *ebiten.Image) FrameData {
return FrameData{

View File

@ -2,6 +2,7 @@ package game
import (
"crypto/sha1"
"image"
"image/color"
"log"
"math"
@ -204,6 +205,10 @@ func (g *Game) ReadInputs() InputBits {
return in
}
var physicsRects = []image.Rectangle{
image.Rect(-world.GroundWidth/2, 0, world.GroundWidth/2, -world.GroundHeight),
}
func (g *Game) applyPhysics() {
for i := 0; i < 2; i++ {
opp := 0
@ -213,21 +218,68 @@ func (g *Game) applyPhysics() {
p := &g.Players[i]
o := &g.Players[opp]
// Apply gravity.
if p.VY > -world.Gravity {
playerRect := world.FloatRect(g.Players[i].X, g.Players[i].Y, g.Players[i].X+float64(component.PlayerSize), g.Players[i].Y+float64(component.PlayerSize))
oppRect := world.FloatRect(g.Players[opp].X, g.Players[opp].Y, g.Players[opp].X+float64(component.PlayerSize), g.Players[opp].Y+float64(component.PlayerSize))
isGrounded := func() (r image.Rectangle, ok bool) {
for _, physRect := range physicsRects {
if component.RectTouches(playerRect, physRect) {
return physRect, true
}
}
return image.Rectangle{}, false
}
// Apply velocity.
p.X, p.Y = p.X+p.VX, p.Y+p.VY
// Apply ground collision.
groundRect, grounded := isGrounded()
if grounded {
// Min is left, Max is right
collideX := p.X+component.PlayerWidth >= float64(groundRect.Min.X) && p.X <= float64(groundRect.Max.X)
// Min is bottom, Max is top
collideY := p.Y-component.PlayerHeight >= float64(groundRect.Min.Y) && p.Y <= float64(groundRect.Max.Y)
log.Println(world.CurrentPlayer, collideX, collideY)
if collideY {
/*if collideX {
if p.X+component.PlayerWidth >= float64(groundRect.Min.X) {
p.X = float64(groundRect.Min.X) - component.PlayerWidth
} else {
p.X = float64(groundRect.Max.X)
}
}*/
if collideY {
topDist := p.Y - float64(groundRect.Max.Y)
bottomDist := p.Y - component.PlayerHeight - float64(groundRect.Min.Y)
if math.Abs(topDist) < math.Abs(bottomDist) { // Closer to top.
p.Y = float64(groundRect.Max.Y)
} else { // Closer to bottom.
p.Y = float64(groundRect.Min.Y) + component.PlayerHeight
}
p.VY = 0
}
}
} else if p.VY > -world.Gravity { // Apply gravity.
p.VY -= math.Max(math.Abs(p.VY/2.5), 0.1)
if p.VY < -world.Gravity {
p.VY = -world.Gravity
}
}
// Apply velocity.
p.X, p.Y = p.X+p.VX, p.Y+p.VY
if p.VY != 0 {
log.Println("VY", world.CurrentPlayer, p.VY)
}
/*if grounded {
log.Println("grounded")
p.VY = 0 // TODO
}*/
// Apply player collision.
playerRect := world.FloatRect(g.Players[i].X, g.Players[i].Y, g.Players[i].X+float64(component.PlayerSize), g.Players[i].Y+float64(component.PlayerSize))
oppRect := world.FloatRect(g.Players[opp].X, g.Players[opp].Y, g.Players[opp].X+float64(component.PlayerSize), g.Players[opp].Y+float64(component.PlayerSize))
if playerRect.Overlaps(oppRect) {
if playerRect.Min.X < oppRect.Min.X {
p.X = o.X - component.PlayerSize
@ -235,11 +287,6 @@ func (g *Game) applyPhysics() {
p.X = o.X + component.PlayerSize
}
}
// Apply ground collision.
if p.Y < 0 {
p.Y = 0
}
}
}

View File

@ -41,13 +41,13 @@ func (s *MapSystem) Draw(e gohan.Entity, screen *ebiten.Image) error {
groundColor := color.RGBA{50, 50, 50, 255}
r := image.Rect(-world.ScreenWidth*2, -world.ScreenHeight, world.ScreenWidth*2, 0)
r := image.Rect(-world.GroundWidth/2, -world.ScreenHeight, world.GroundWidth/2, 0)
screen.SubImage(world.GameRectToScreen(r)).(*ebiten.Image).Fill(groundColor)
const groundTopHeight = 10
groundTopColor := color.RGBA{100, 100, 100, 255}
r = image.Rect(-world.ScreenWidth*2, -groundTopHeight, world.ScreenWidth*2, 0)
r = image.Rect(-world.GroundWidth/2, -groundTopHeight, world.GroundWidth/2, 0)
screen.SubImage(world.GameRectToScreen(r)).(*ebiten.Image).Fill(groundTopColor)
return nil

View File

@ -19,11 +19,12 @@ const (
JumpVelocity = 30
GroundHeight = 100
MaxDebug = 2
FloatValueThreshold = 0.00000001
GroundWidth = 600
GroundHeight = 100
)
var (