mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-06 00:26:40 -05:00
entity debug rendering (#609)
* entity debug rendering, with command needed to add getter method to MapEntity interface, so that's the reasoning for changing objects/npcs/player/etc this currently brings allocs/s up to 10 (you can check by running `fps` command, se we need to look into d2debugutils and how it handles drawing text * reverting velocity copy, broke the map entity tests. debug display wont show velocity currently. * adding velocity debug
This commit is contained in:
parent
d0c6cd61dd
commit
362147848d
@ -1,10 +1,13 @@
|
||||
package d2interface
|
||||
|
||||
import "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
|
||||
// MapEntity is something that can be positioned on and rendered on the game map
|
||||
type MapEntity interface {
|
||||
Render(target Surface)
|
||||
Advance(tickTime float64)
|
||||
GetPosition() (float64, float64)
|
||||
GetPosition() d2vector.Position
|
||||
GetVelocity() d2vector.Vector
|
||||
GetLayer() int
|
||||
GetPositionF() (float64, float64)
|
||||
Name() string
|
||||
|
@ -26,6 +26,7 @@ func newMapEntity(x, y int) mapEntity {
|
||||
return mapEntity{
|
||||
Position: pos,
|
||||
Target: pos,
|
||||
velocity: d2vector.NewVector(0, 0),
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,22 +66,23 @@ func (m *mapEntity) Step(tickTime float64) {
|
||||
m.done = nil
|
||||
}
|
||||
|
||||
m.velocity.SetLength(0)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Set velocity (speed and direction)
|
||||
m.setVelocity(tickTime * m.Speed)
|
||||
|
||||
// This loop handles the situation where the velocity exceeds the distance to the current target. Each repitition applies
|
||||
// the remaining velocity in the direction of the next path target.
|
||||
v := m.velocity.Clone() // Create a new vector
|
||||
|
||||
for {
|
||||
applyVelocity(&m.Position.Vector, &m.velocity, &m.Target.Vector)
|
||||
applyVelocity(&m.Position.Vector, &v, &m.Target.Vector) // Pass the new vector to the function which alters it
|
||||
|
||||
if m.atTarget() {
|
||||
m.nextPath()
|
||||
}
|
||||
|
||||
if m.velocity.IsZero() {
|
||||
if v.IsZero() { // Check if the new vector is zero (keeping this as m.velocity.IsZero() would break the test (infinite loop)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,14 @@ type Missile struct {
|
||||
record *d2datadict.MissileRecord
|
||||
}
|
||||
|
||||
func (m *Missile) GetPosition() d2vector.Position {
|
||||
return m.AnimatedEntity.Position
|
||||
}
|
||||
|
||||
func (m *Missile) GetVelocity() d2vector.Vector {
|
||||
return m.AnimatedEntity.velocity
|
||||
}
|
||||
|
||||
// CreateMissile creates a new Missile and initializes it's animation.
|
||||
func CreateMissile(x, y int, record *d2datadict.MissileRecord) (*Missile, error) {
|
||||
animation, err := d2asset.LoadAnimation(
|
||||
|
@ -1,6 +1,7 @@
|
||||
package d2mapentity
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
"math/rand"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
@ -206,3 +207,13 @@ func (v *NPC) Selectable() bool {
|
||||
func (v *NPC) Name() string {
|
||||
return v.name
|
||||
}
|
||||
|
||||
// GetPosition returns the NPC's position
|
||||
func (v *NPC) GetPosition() d2vector.Position {
|
||||
return v.mapEntity.Position
|
||||
}
|
||||
|
||||
// GetVelocity returns the NPC's velocity vector
|
||||
func (v *NPC) GetVelocity() d2vector.Vector {
|
||||
return v.mapEntity.velocity
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package d2mapentity
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
|
||||
@ -223,3 +223,13 @@ func (v *Player) Selectable() bool {
|
||||
// Players are selectable when in town
|
||||
return v.IsInTown()
|
||||
}
|
||||
|
||||
// GetPosition returns the entity's position
|
||||
func (p *Player) GetPosition() d2vector.Position {
|
||||
return p.mapEntity.Position
|
||||
}
|
||||
|
||||
// GetVelocity returns the entity's velocity vector
|
||||
func (p *Player) GetVelocity() d2vector.Vector {
|
||||
return p.mapEntity.velocity
|
||||
}
|
||||
|
@ -22,7 +22,9 @@ type MapRenderer struct {
|
||||
palette d2interface.Palette // The palette used for this map
|
||||
viewport *Viewport // Used for rendering offsets
|
||||
Camera Camera // Used to determine where on the map we are rendering
|
||||
debugVisLevel int // Debug visibility index (0=none, 1=tiles, 2=sub-tiles)
|
||||
mapDebugVisLevel int // Map debug visibility index (0=none, 1=tiles,
|
||||
// 2=sub-tiles)
|
||||
entityDebugVisLevel int // Entity Debug visibility index (0=none, 1=vectors)
|
||||
lastFrameTime float64 // The last time the map was rendered
|
||||
currentFrame int // Current render frame (for animations)
|
||||
}
|
||||
@ -36,12 +38,16 @@ func CreateMapRenderer(renderer d2interface.Renderer, mapEngine *d2mapengine.Map
|
||||
}
|
||||
|
||||
result.Camera = Camera{}
|
||||
startPosition := d2vector.NewPosition(0,0)
|
||||
startPosition := d2vector.NewPosition(0, 0)
|
||||
result.Camera.position = &startPosition
|
||||
result.viewport.SetCamera(&result.Camera)
|
||||
|
||||
term.BindAction("mapdebugvis", "set map debug visualization level", func(level int) {
|
||||
result.debugVisLevel = level
|
||||
result.mapDebugVisLevel = level
|
||||
})
|
||||
|
||||
term.BindAction("entitydebugvis", "set entity debug visualization level", func(level int) {
|
||||
result.entityDebugVisLevel = level
|
||||
})
|
||||
|
||||
if mapEngine.LevelType().ID != 0 {
|
||||
@ -87,12 +93,16 @@ func (mr *MapRenderer) Render(target d2interface.Surface) {
|
||||
mr.renderPass1(target, startX, startY, endX, endY)
|
||||
mr.renderPass2(target, startX, startY, endX, endY)
|
||||
|
||||
if mr.debugVisLevel > 0 {
|
||||
mr.renderDebug(mr.debugVisLevel, target, startX, startY, endX, endY)
|
||||
if mr.mapDebugVisLevel > 0 {
|
||||
mr.renderMapDebug(mr.mapDebugVisLevel, target, startX, startY, endX, endY)
|
||||
}
|
||||
|
||||
mr.renderPass3(target, startX, startY, endX, endY)
|
||||
mr.renderPass4(target, startX, startY, endX, endY)
|
||||
|
||||
if mr.entityDebugVisLevel > 0 {
|
||||
mr.renderEntityDebug(target)
|
||||
}
|
||||
}
|
||||
|
||||
// MoveCameraTo sets the position of the Camera to the given x and y coordinates.
|
||||
@ -146,7 +156,9 @@ func (mr *MapRenderer) renderPass2(target d2interface.Surface, startX, startY, e
|
||||
|
||||
// TODO: Do not loop over every entity every frame
|
||||
for _, mapEntity := range *mr.mapEngine.Entities() {
|
||||
entityX, entityY := mapEntity.GetPosition()
|
||||
pos := mapEntity.GetPosition()
|
||||
vec := pos.World()
|
||||
entityX, entityY := vec.X(), vec.Y()
|
||||
|
||||
if mapEntity.GetLayer() != 1 {
|
||||
continue
|
||||
@ -176,7 +188,9 @@ func (mr *MapRenderer) renderPass3(target d2interface.Surface, startX, startY, e
|
||||
|
||||
// TODO: Do not loop over every entity every frame
|
||||
for _, mapEntity := range *mr.mapEngine.Entities() {
|
||||
entityX, entityY := mapEntity.GetPosition()
|
||||
pos := mapEntity.GetPosition()
|
||||
vec := pos.World()
|
||||
entityX, entityY := vec.X(), vec.Y()
|
||||
|
||||
if mapEntity.GetLayer() == 1 {
|
||||
continue
|
||||
@ -299,16 +313,46 @@ func (mr *MapRenderer) renderShadow(tile d2ds1.FloorShadowRecord, target d2inter
|
||||
target.Render(img)
|
||||
}
|
||||
|
||||
func (mr *MapRenderer) renderDebug(debugVisLevel int, target d2interface.Surface, startX, startY, endX, endY int) {
|
||||
func (mr *MapRenderer) renderMapDebug(mapDebugVisLevel int, target d2interface.Surface, startX, startY, endX, endY int) {
|
||||
for tileY := startY; tileY < endY; tileY++ {
|
||||
for tileX := startX; tileX < endX; tileX++ {
|
||||
mr.viewport.PushTranslationWorld(float64(tileX), float64(tileY))
|
||||
mr.renderTileDebug(tileX, tileY, debugVisLevel, target)
|
||||
mr.renderTileDebug(tileX, tileY, mapDebugVisLevel, target)
|
||||
mr.viewport.PopTranslation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (mr *MapRenderer) renderEntityDebug(target d2interface.Surface) {
|
||||
entities := *mr.mapEngine.Entities()
|
||||
for idx := range entities {
|
||||
e := entities[idx]
|
||||
pos := e.GetPosition()
|
||||
world := pos
|
||||
x, y := world.X()/5, world.Y()/5
|
||||
velocity := e.GetVelocity()
|
||||
velocity = velocity.Clone()
|
||||
// velocity.Scale(60) // arbitrary scale value, just to make it easy to see
|
||||
vx, vy := mr.viewport.WorldToOrtho(velocity.X(), velocity.Y())
|
||||
screenX, screenY := mr.viewport.WorldToScreen(x, y)
|
||||
|
||||
offX, offY := 40, -40
|
||||
|
||||
mr.viewport.PushTranslationWorld(x, y)
|
||||
target.PushTranslation(screenX, screenY)
|
||||
target.DrawLine(offX, offY, color.RGBA{255, 255, 255, 128})
|
||||
target.PushTranslation(offX+10, offY-20)
|
||||
target.PushTranslation(-10, -10)
|
||||
target.DrawRect(200, 50, color.RGBA{0, 0, 0, 64})
|
||||
target.Pop()
|
||||
target.DrawTextf("World (%.2f, %.2f)\nVelocity (%.2f, %.2f)", x, y, vx, vy)
|
||||
target.Pop()
|
||||
target.DrawLine(int(vx), int(vy), color.RGBA{64, 255, 0, 255})
|
||||
target.Pop()
|
||||
mr.viewport.PopTranslation()
|
||||
}
|
||||
}
|
||||
|
||||
// WorldToScreen returns the screen (pixel) position for the given isometric world position as two ints.
|
||||
func (mr *MapRenderer) WorldToScreen(x, y float64) (int, int) {
|
||||
return mr.viewport.WorldToScreen(x, y)
|
||||
|
@ -122,12 +122,6 @@ func (ob *Object) GetLayer() int {
|
||||
return ob.drawLayer
|
||||
}
|
||||
|
||||
// GetPosition of the object
|
||||
func (ob *Object) GetPosition() (x, y float64) {
|
||||
w := ob.Position.Tile()
|
||||
return w.X(), w.Y()
|
||||
}
|
||||
|
||||
// GetPositionF of the object but differently
|
||||
func (ob *Object) GetPositionF() (x, y float64) {
|
||||
w := ob.Position.World()
|
||||
@ -138,3 +132,13 @@ func (ob *Object) GetPositionF() (x, y float64) {
|
||||
func (ob *Object) Name() string {
|
||||
return ob.name
|
||||
}
|
||||
|
||||
// GetPosition returns the object's position
|
||||
func (ob *Object) GetPosition() d2vector.Position {
|
||||
return ob.Position
|
||||
}
|
||||
|
||||
// GetVelocity returns the object's velocity vector
|
||||
func (ob *Object) GetVelocity() d2vector.Vector {
|
||||
return d2vector.NewVector(0, 0)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user