mirror of
https://github.com/genxium/DelayNoMore
synced 2025-10-09 08:36:52 +00:00
Fixes for collider polygonal shape drawing.
This commit is contained in:
@@ -1,66 +1,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"math"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||
"github.com/solarlune/resolv"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
var circleBuffer map[resolv.Shape]*ebiten.Image = map[resolv.Shape]*ebiten.Image{}
|
||||
|
||||
func DrawPolygon(screen *ebiten.Image, shape *resolv.ConvexPolygon, color color.Color) {
|
||||
|
||||
verts := shape.Transformed()
|
||||
for i := 0; i < len(verts); i++ {
|
||||
vert := verts[i]
|
||||
next := verts[0]
|
||||
|
||||
if i < len(verts)-1 {
|
||||
next = verts[i+1]
|
||||
}
|
||||
ebitenutil.DrawLine(screen, vert.X(), vert.Y(), next.X(), next.Y(), color)
|
||||
var (
|
||||
PolygonFillerImage = ebiten.NewImage(1, 1)
|
||||
)
|
||||
|
||||
func DrawPolygon(screen *ebiten.Image, shape *resolv.ConvexPolygon, clr color.Color) {
|
||||
PolygonFillerImage.Fill(clr)
|
||||
indices := []uint16{}
|
||||
vs := []ebiten.Vertex{}
|
||||
coors := shape.Transformed()
|
||||
centerX := float64(0)
|
||||
centerY := float64(0)
|
||||
n := uint16(len(coors))
|
||||
for i, coor := range coors {
|
||||
centerX += coor.X()
|
||||
centerY += coor.Y()
|
||||
vs = append(vs, ebiten.Vertex{
|
||||
DstX: float32(coor.X()),
|
||||
DstY: float32(coor.Y()),
|
||||
SrcX: 0,
|
||||
SrcY: 0,
|
||||
ColorR: 1,
|
||||
ColorG: 1,
|
||||
ColorB: 1,
|
||||
ColorA: 1,
|
||||
})
|
||||
indices = append(indices, uint16(i), uint16(i+1)%n, n)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func DrawCircle(screen *ebiten.Image, circle *resolv.Circle, drawColor color.Color) {
|
||||
|
||||
// Actually drawing the circles live is too inefficient, so we will simply draw them to an image and then draw that instead
|
||||
// when necessary.
|
||||
|
||||
if _, exists := circleBuffer[circle]; !exists {
|
||||
newImg := ebiten.NewImage(int(circle.Radius)*2, int(circle.Radius)*2)
|
||||
|
||||
newImg.Set(int(circle.X), int(circle.Y), color.White)
|
||||
|
||||
stepCount := float64(32)
|
||||
|
||||
// Half image width and height.
|
||||
hw := circle.Radius
|
||||
hh := circle.Radius
|
||||
|
||||
for i := 0; i < int(stepCount); i++ {
|
||||
|
||||
x := (math.Sin(math.Pi*2*float64(i)/stepCount) * (circle.Radius - 2)) + hw
|
||||
y := (math.Cos(math.Pi*2*float64(i)/stepCount) * (circle.Radius - 2)) + hh
|
||||
|
||||
x2 := (math.Sin(math.Pi*2*float64(i+1)/stepCount) * (circle.Radius - 2)) + hw
|
||||
y2 := (math.Cos(math.Pi*2*float64(i+1)/stepCount) * (circle.Radius - 2)) + hh
|
||||
|
||||
ebitenutil.DrawLine(newImg, x, y, x2, y2, color.White)
|
||||
|
||||
}
|
||||
circleBuffer[circle] = newImg
|
||||
}
|
||||
|
||||
drawOpt := &ebiten.DrawImageOptions{}
|
||||
r, g, b, _ := drawColor.RGBA()
|
||||
drawOpt.ColorM.Scale(float64(r)/65535, float64(g)/65535, float64(b)/65535, 1)
|
||||
drawOpt.GeoM.Translate(circle.X-circle.Radius, circle.Y-circle.Radius)
|
||||
screen.DrawImage(circleBuffer[circle], drawOpt)
|
||||
|
||||
centerX = centerX / float64(n)
|
||||
centerY = centerY / float64(n)
|
||||
|
||||
vs = append(vs, ebiten.Vertex{
|
||||
DstX: float32(centerX),
|
||||
DstY: float32(centerY),
|
||||
SrcX: 0,
|
||||
SrcY: 0,
|
||||
ColorR: 1,
|
||||
ColorG: 1,
|
||||
ColorB: 1,
|
||||
ColorA: 1,
|
||||
})
|
||||
|
||||
screen.DrawTriangles(vs, indices, PolygonFillerImage, nil)
|
||||
}
|
||||
|
@@ -85,12 +85,13 @@ type Game struct {
|
||||
|
||||
func NewGame() *Game {
|
||||
|
||||
stageName := "simple" // Use this for calibration
|
||||
// stageName := "richsoil"
|
||||
// stageName := "simple" // Use this for calibration
|
||||
stageName := "simple2"
|
||||
stageDiscreteW, stageDiscreteH, stageTileW, stageTileH, playerPosMap, barrierMap, err := parseStage(stageName)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
PolygonFillerImage.Fill(color.RGBA{60, 60, 60, 255}) // Required to init color of the polygons!
|
||||
|
||||
spaceW := stageDiscreteW * stageTileW
|
||||
spaceH := stageDiscreteH * stageTileH
|
||||
|
@@ -1,20 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
. "dnmshared"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"go.uber.org/zap"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||
"github.com/solarlune/resolv"
|
||||
. "dnmshared"
|
||||
"go.uber.org/zap"
|
||||
"image/color"
|
||||
|
||||
"math"
|
||||
"math"
|
||||
)
|
||||
|
||||
type WorldColliderDisplay struct {
|
||||
Game *Game
|
||||
Space *resolv.Space
|
||||
Game *Game
|
||||
Space *resolv.Space
|
||||
}
|
||||
|
||||
func (world *WorldColliderDisplay) Init() {
|
||||
@@ -22,7 +22,7 @@ func (world *WorldColliderDisplay) Init() {
|
||||
|
||||
func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTileW, stageTileH int32, playerPosMap StrToVec2DListMap, barrierMap StrToPolygon2DListMap) *WorldColliderDisplay {
|
||||
|
||||
playerList := *(playerPosMap["PlayerStartingPos"])
|
||||
playerList := *(playerPosMap["PlayerStartingPos"])
|
||||
barrierList := *(barrierMap["Barrier"])
|
||||
|
||||
world := &WorldColliderDisplay{Game: game}
|
||||
@@ -35,53 +35,51 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
|
||||
spaceOffsetX := float64(spaceW) * 0.5
|
||||
spaceOffsetY := float64(spaceH) * 0.5
|
||||
|
||||
// TODO: Move collider y-axis transformation to a "dnmshared"
|
||||
// TODO: Move collider y-axis transformation to a "dnmshared"
|
||||
playerColliderRadius := float64(12) // hardcoded
|
||||
space := resolv.NewSpace(int(spaceW), int(spaceH), int(stageTileW), int(stageTileH))
|
||||
for _, player := range playerList {
|
||||
playerCollider := resolv.NewObject(player.X+spaceOffsetX, -player.Y+spaceOffsetY, playerColliderRadius*2, playerColliderRadius*2, "Player")
|
||||
playerColliderShape := resolv.NewCircle(0, 0, playerColliderRadius*2)
|
||||
playerCollider.SetShape(playerColliderShape)
|
||||
Logger.Info("player shape added:", zap.Any("shape", playerColliderShape))
|
||||
space.Add(playerCollider)
|
||||
}
|
||||
space := resolv.NewSpace(int(spaceW), int(spaceH), 16, 16)
|
||||
for _, player := range playerList {
|
||||
playerCollider := resolv.NewObject(player.X+spaceOffsetX, player.Y+spaceOffsetY, playerColliderRadius*2, playerColliderRadius*2, "Player")
|
||||
playerColliderShape := resolv.NewCircle(0, 0, playerColliderRadius*2)
|
||||
playerCollider.SetShape(playerColliderShape)
|
||||
space.Add(playerCollider)
|
||||
}
|
||||
|
||||
barrierLocalId := 0
|
||||
for _, barrier := range barrierList {
|
||||
var w float64 = 0
|
||||
var h float64 = 0
|
||||
barrierLocalId := 0
|
||||
for _, barrier := range barrierList {
|
||||
var w float64 = 0
|
||||
var h float64 = 0
|
||||
|
||||
for i, pi := range barrier.Points {
|
||||
for j, pj := range barrier.Points {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
if math.Abs(pj.X-pi.X) > w {
|
||||
w = math.Abs(pj.X - pi.X)
|
||||
}
|
||||
if math.Abs(pj.Y-pi.Y) > h {
|
||||
h = math.Abs(pj.Y - pi.Y)
|
||||
}
|
||||
}
|
||||
}
|
||||
for i, pi := range barrier.Points {
|
||||
for j, pj := range barrier.Points {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
if math.Abs(pj.X-pi.X) > w {
|
||||
w = math.Abs(pj.X - pi.X)
|
||||
}
|
||||
if math.Abs(pj.Y-pi.Y) > h {
|
||||
h = math.Abs(pj.Y - pi.Y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
barrierColliderShape := resolv.NewConvexPolygon()
|
||||
for i := 0; i < len(barrier.Points); i++ {
|
||||
p := barrier.Points[i]
|
||||
barrierColliderShape.AddPoints(p.X, p.Y)
|
||||
}
|
||||
barrierColliderShape := resolv.NewConvexPolygon()
|
||||
for i := 0; i < len(barrier.Points); i++ {
|
||||
p := barrier.Points[i]
|
||||
barrierColliderShape.AddPoints(p.X, p.Y)
|
||||
}
|
||||
|
||||
barrierCollider := resolv.NewObject(barrier.Anchor.X+spaceOffsetX, -barrier.Anchor.Y+spaceOffsetY, w, h, "Barrier")
|
||||
barrierCollider.SetShape(barrierColliderShape)
|
||||
barrierCollider := resolv.NewObject(barrier.Anchor.X+spaceOffsetX, barrier.Anchor.Y+spaceOffsetY, w, h, "Barrier")
|
||||
barrierCollider.SetShape(barrierColliderShape)
|
||||
|
||||
Logger.Info("barrier shape added:", zap.Any("barrierLocalId", barrierLocalId), zap.Any("shape", barrierColliderShape))
|
||||
space.Add(barrierCollider)
|
||||
space.Add(barrierCollider)
|
||||
|
||||
barrierLocalId++
|
||||
}
|
||||
barrierLocalId++
|
||||
}
|
||||
|
||||
world.Space = space
|
||||
return world
|
||||
return world
|
||||
}
|
||||
|
||||
func (world *WorldColliderDisplay) Update() {
|
||||
@@ -91,14 +89,17 @@ func (world *WorldColliderDisplay) Update() {
|
||||
func (world *WorldColliderDisplay) Draw(screen *ebiten.Image) {
|
||||
|
||||
for _, o := range world.Space.Objects() {
|
||||
drawColor := color.RGBA{60, 60, 60, 255}
|
||||
if o.HasTags("Player") {
|
||||
drawColor = color.RGBA{0, 255, 0, 255}
|
||||
circle := o.Shape.(*resolv.Circle)
|
||||
drawColor := color.RGBA{0, 255, 0, 255}
|
||||
ebitenutil.DrawCircle(screen, circle.X, circle.Y, circle.Radius, drawColor)
|
||||
} else {
|
||||
drawColor := color.RGBA{60, 60, 60, 255}
|
||||
DrawPolygon(screen, o.Shape.(*resolv.ConvexPolygon), drawColor)
|
||||
}
|
||||
ebitenutil.DrawRect(screen, o.X, o.Y, o.W, o.H, drawColor)
|
||||
}
|
||||
|
||||
// world.Game.DebugDraw(screen, world.Space)
|
||||
// world.Game.DebugDraw(screen, world.Space)
|
||||
|
||||
if world.Game.ShowHelpText {
|
||||
|
||||
|
Reference in New Issue
Block a user