mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-06-26 17:15:24 +00:00
Create viewport and camera types (#246)
This commit is contained in:
parent
9a8e16c411
commit
1262c80e6b
|
@ -1,6 +1,8 @@
|
||||||
package d2scene
|
package d2scene
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"image/color"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||||
|
@ -14,7 +16,6 @@ import (
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2mapengine"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2mapengine"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
"image/color"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Game struct {
|
type Game struct {
|
||||||
|
@ -128,9 +129,7 @@ func (v *Game) Update(tickTime float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
|
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
|
||||||
mx, my := ebiten.CursorPosition()
|
px, py := v.mapEngine.ScreenToIso(ebiten.CursorPosition())
|
||||||
px, py := d2helper.ScreenToIso(float64(mx)-v.mapEngine.OffsetX, float64(my)-v.mapEngine.OffsetY)
|
|
||||||
|
|
||||||
v.mapEngine.Hero.AnimatedEntity.SetTarget(px*5, py*5, 1)
|
v.mapEngine.Hero.AnimatedEntity.SetTarget(px*5, py*5, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -172,9 +172,9 @@ func (v *MapEngineTest) Unload() {
|
||||||
|
|
||||||
func (v *MapEngineTest) Render(screen *ebiten.Image) {
|
func (v *MapEngineTest) Render(screen *ebiten.Image) {
|
||||||
v.mapEngine.Render(screen)
|
v.mapEngine.Render(screen)
|
||||||
actualX := float64(v.uiManager.CursorX) - v.mapEngine.OffsetX
|
actualX := v.uiManager.CursorX
|
||||||
actualY := float64(v.uiManager.CursorY) - v.mapEngine.OffsetY
|
actualY := v.uiManager.CursorY
|
||||||
tileX, tileY := d2helper.ScreenToIso(actualX, actualY)
|
tileX, tileY := v.mapEngine.ScreenToIso(actualX, actualY)
|
||||||
subtileX := int(math.Ceil(math.Mod((tileX*10), 10))) / 2
|
subtileX := int(math.Ceil(math.Mod((tileX*10), 10))) / 2
|
||||||
subtileY := int(math.Ceil(math.Mod((tileY*10), 10))) / 2
|
subtileY := int(math.Ceil(math.Mod((tileY*10), 10))) / 2
|
||||||
curRegion := v.mapEngine.GetRegionAt(int(tileX), int(tileY))
|
curRegion := v.mapEngine.GetRegionAt(int(tileX), int(tileY))
|
||||||
|
@ -182,8 +182,8 @@ func (v *MapEngineTest) Render(screen *ebiten.Image) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
line := fmt.Sprintf("%d, %d (Tile %d.%d, %d.%d)",
|
line := fmt.Sprintf("%d, %d (Tile %d.%d, %d.%d)",
|
||||||
int(math.Ceil(actualX)),
|
actualX,
|
||||||
int(math.Ceil(actualY)),
|
actualY,
|
||||||
int(math.Floor(tileX))-curRegion.Rect.Left,
|
int(math.Floor(tileX))-curRegion.Rect.Left,
|
||||||
subtileX,
|
subtileX,
|
||||||
int(math.Floor(tileY))-curRegion.Rect.Top,
|
int(math.Floor(tileY))-curRegion.Rect.Top,
|
||||||
|
@ -217,33 +217,22 @@ func (v *MapEngineTest) Update(tickTime float64) {
|
||||||
ctrlPressed := v.uiManager.KeyPressed(ebiten.KeyControl)
|
ctrlPressed := v.uiManager.KeyPressed(ebiten.KeyControl)
|
||||||
shiftPressed := v.uiManager.KeyPressed(ebiten.KeyShift)
|
shiftPressed := v.uiManager.KeyPressed(ebiten.KeyShift)
|
||||||
|
|
||||||
|
var moveSpeed float64 = 800
|
||||||
|
if v.uiManager.KeyPressed(ebiten.KeyShift) {
|
||||||
|
moveSpeed = 200
|
||||||
|
}
|
||||||
|
|
||||||
if v.uiManager.KeyPressed(ebiten.KeyDown) {
|
if v.uiManager.KeyPressed(ebiten.KeyDown) {
|
||||||
if v.uiManager.KeyPressed(ebiten.KeyShift) {
|
v.mapEngine.MoveCameraBy(0, moveSpeed*tickTime)
|
||||||
v.mapEngine.OffsetY -= tickTime * 200
|
|
||||||
} else {
|
|
||||||
v.mapEngine.OffsetY -= tickTime * 800
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if v.uiManager.KeyPressed(ebiten.KeyUp) {
|
if v.uiManager.KeyPressed(ebiten.KeyUp) {
|
||||||
if v.uiManager.KeyPressed(ebiten.KeyShift) {
|
v.mapEngine.MoveCameraBy(0, -moveSpeed*tickTime)
|
||||||
v.mapEngine.OffsetY += tickTime * 200
|
|
||||||
} else {
|
|
||||||
v.mapEngine.OffsetY += tickTime * 800
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if v.uiManager.KeyPressed(ebiten.KeyLeft) {
|
if v.uiManager.KeyPressed(ebiten.KeyLeft) {
|
||||||
if v.uiManager.KeyPressed(ebiten.KeyShift) {
|
v.mapEngine.MoveCameraBy(-moveSpeed*tickTime, 0)
|
||||||
v.mapEngine.OffsetX += tickTime * 200
|
|
||||||
} else {
|
|
||||||
v.mapEngine.OffsetX += tickTime * 800
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if v.uiManager.KeyPressed(ebiten.KeyRight) {
|
if v.uiManager.KeyPressed(ebiten.KeyRight) {
|
||||||
if v.uiManager.KeyPressed(ebiten.KeyShift) {
|
v.mapEngine.MoveCameraBy(moveSpeed*tickTime, 0)
|
||||||
v.mapEngine.OffsetX -= tickTime * 200
|
|
||||||
} else {
|
|
||||||
v.mapEngine.OffsetX -= tickTime * 800
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if inpututil.IsKeyJustPressed(ebiten.KeyF7) {
|
if inpututil.IsKeyJustPressed(ebiten.KeyF7) {
|
||||||
|
|
20
d2render/d2mapengine/camera.go
Normal file
20
d2render/d2mapengine/camera.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package d2mapengine
|
||||||
|
|
||||||
|
type Camera struct {
|
||||||
|
x float64
|
||||||
|
y float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Camera) MoveTo(x, y float64) {
|
||||||
|
c.x = x
|
||||||
|
c.y = y
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Camera) MoveBy(x, y float64) {
|
||||||
|
c.x += x
|
||||||
|
c.y += y
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Camera) GetPosition() (float64, float64) {
|
||||||
|
return c.x, c.y
|
||||||
|
}
|
|
@ -7,8 +7,6 @@ import (
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2helper"
|
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||||
|
@ -36,27 +34,31 @@ type Engine struct {
|
||||||
fileProvider d2interface.FileProvider
|
fileProvider d2interface.FileProvider
|
||||||
region int
|
region int
|
||||||
regions []EngineRegion
|
regions []EngineRegion
|
||||||
OffsetX float64
|
|
||||||
OffsetY float64
|
|
||||||
ShowTiles int
|
ShowTiles int
|
||||||
Hero *d2core.Hero
|
Hero *d2core.Hero
|
||||||
|
|
||||||
|
viewport *Viewport
|
||||||
|
camera Camera
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateMapEngine(gameState *d2core.GameState, soundManager *d2audio.Manager, fileProvider d2interface.FileProvider) *Engine {
|
func CreateMapEngine(gameState *d2core.GameState, soundManager *d2audio.Manager, fileProvider d2interface.FileProvider) *Engine {
|
||||||
result := &Engine{
|
engine := &Engine{
|
||||||
gameState: gameState,
|
gameState: gameState,
|
||||||
soundManager: soundManager,
|
soundManager: soundManager,
|
||||||
fileProvider: fileProvider,
|
fileProvider: fileProvider,
|
||||||
regions: make([]EngineRegion, 0),
|
regions: make([]EngineRegion, 0),
|
||||||
|
viewport: NewViewport(0, 0, 800, 600),
|
||||||
}
|
}
|
||||||
return result
|
|
||||||
|
engine.viewport.SetCamera(&engine.camera)
|
||||||
|
return engine
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Engine) Region() *EngineRegion {
|
func (v *Engine) Region() *EngineRegion {
|
||||||
return &v.regions[v.region]
|
return &v.regions[v.region]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Engine) SetRegion(region int) {
|
func (v *Engine) SetRegion(region int) {
|
||||||
v.region = region
|
v.region = region
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,8 +67,19 @@ func (v *Engine) GetRegion(regionIndex int) *EngineRegion {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Engine) CenterCameraOn(x, y float64) {
|
func (v *Engine) CenterCameraOn(x, y float64) {
|
||||||
v.OffsetX = -(x - 400)
|
v.camera.MoveTo(x, y)
|
||||||
v.OffsetY = -(y - 300)
|
}
|
||||||
|
|
||||||
|
func (v *Engine) MoveCameraBy(x, y float64) {
|
||||||
|
v.camera.MoveBy(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Engine) ScreenToIso(x, y int) (float64, float64) {
|
||||||
|
return v.viewport.ScreenToIso(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Engine) ScreenToWorld(x, y int) (float64, float64) {
|
||||||
|
return v.viewport.ScreenToWorld(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Engine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int, fileIndex int) {
|
func (v *Engine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int, fileIndex int) {
|
||||||
|
@ -109,36 +122,31 @@ func (v *Engine) GenerateAct1Overworld() {
|
||||||
v.GenTilesCache(&v.regions[i])
|
v.GenTilesCache(&v.regions[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
sx, sy := d2helper.IsoToScreen(region.StartX, region.StartY, 0, 0)
|
v.camera.MoveTo(v.viewport.IsoToWorld(region.StartX, region.StartY))
|
||||||
v.OffsetX = sx - 400
|
|
||||||
v.OffsetY = sy - 300
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Engine) GetRegionAt(x, y int) *EngineRegion {
|
func (v *Engine) GetRegionAt(x, y int) *EngineRegion {
|
||||||
if v.regions == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for _, region := range v.regions {
|
for _, region := range v.regions {
|
||||||
if !region.Rect.IsInRect(x, y) {
|
if region.Rect.IsInRect(x, y) {
|
||||||
continue
|
return ®ion
|
||||||
}
|
}
|
||||||
return ®ion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Engine) Render(target *ebiten.Image) {
|
func (v *Engine) Render(target *ebiten.Image) {
|
||||||
for _, region := range v.regions {
|
for _, region := range v.regions {
|
||||||
// X position of leftmost point of region
|
// X position of leftmost point of region
|
||||||
left := (region.Rect.Left - region.Rect.Bottom()) * 80
|
left := float64((region.Rect.Left - region.Rect.Bottom()) * 80)
|
||||||
// Y position of top of region
|
// Y position of top of region
|
||||||
top := (region.Rect.Left + region.Rect.Top) * 40
|
top := float64((region.Rect.Left + region.Rect.Top) * 40)
|
||||||
// X of right
|
// X of right
|
||||||
right := (region.Rect.Right() - region.Rect.Top) * 80
|
right := float64((region.Rect.Right() - region.Rect.Top) * 80)
|
||||||
// Y of bottom
|
// Y of bottom
|
||||||
bottom := (region.Rect.Right() + region.Rect.Bottom()) * 40
|
bottom := float64((region.Rect.Right() + region.Rect.Bottom()) * 40)
|
||||||
|
|
||||||
if -v.OffsetX+800 > float64(left) && -v.OffsetX < float64(right) && -v.OffsetY+600 > float64(top) && -v.OffsetY < float64(bottom) {
|
if v.viewport.IsWorldRectVisible(left, top, right, bottom) {
|
||||||
v.RenderRegion(region, target)
|
v.RenderRegion(region, target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,56 +199,61 @@ func (v *Engine) GenTilesCache(region *EngineRegion) {
|
||||||
|
|
||||||
func (v *Engine) RenderRegion(region EngineRegion, target *ebiten.Image) {
|
func (v *Engine) RenderRegion(region EngineRegion, target *ebiten.Image) {
|
||||||
for tileIdx := range region.Tiles {
|
for tileIdx := range region.Tiles {
|
||||||
sx, sy := d2helper.IsoToScreen(float64(region.Tiles[tileIdx].tileX+region.Rect.Left), float64(region.Tiles[tileIdx].tileY+region.Rect.Top), v.OffsetX, v.OffsetY)
|
if v.viewport.IsWorldTileVisbile(float64(region.Tiles[tileIdx].tileX+region.Rect.Left), float64(region.Tiles[tileIdx].tileY+region.Rect.Top)) {
|
||||||
if sx > -160 && sy > -380 && sx <= 880 && sy <= 1240 {
|
|
||||||
region.Region.UpdateAnimations()
|
region.Region.UpdateAnimations()
|
||||||
v.RenderPass1(region.Region, region.Tiles[tileIdx].offX, region.Tiles[tileIdx].offY, region.Tiles[tileIdx].tileX, region.Tiles[tileIdx].tileY, target)
|
|
||||||
if v.ShowTiles > 0 {
|
|
||||||
v.DrawTileLines(region.Region, region.Tiles[tileIdx].offX, region.Tiles[tileIdx].offY, region.Tiles[tileIdx].tileX, region.Tiles[tileIdx].tileY, target)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
v.viewport.PushTranslation(float64(region.Tiles[tileIdx].offX), float64(region.Tiles[tileIdx].offY))
|
||||||
|
v.RenderPass1(region.Region, region.Tiles[tileIdx].tileX, region.Tiles[tileIdx].tileY, target)
|
||||||
|
v.DrawTileLines(region.Region, region.Tiles[tileIdx].tileX, region.Tiles[tileIdx].tileY, target)
|
||||||
|
v.viewport.PopTranslation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for tileIdx := range region.Tiles {
|
for tileIdx := range region.Tiles {
|
||||||
sx, sy := d2helper.IsoToScreen(float64(region.Tiles[tileIdx].tileX+region.Rect.Left), float64(region.Tiles[tileIdx].tileY+region.Rect.Top), v.OffsetX, v.OffsetY)
|
if v.viewport.IsWorldTileVisbile(float64(region.Tiles[tileIdx].tileX+region.Rect.Left), float64(region.Tiles[tileIdx].tileY+region.Rect.Top)) {
|
||||||
if sx > -160 && sy > -380 && sx <= 880 && sy <= 1240 {
|
v.viewport.PushTranslation(float64(region.Tiles[tileIdx].offX), float64(region.Tiles[tileIdx].offY))
|
||||||
v.RenderPass2(region.Region, region.Tiles[tileIdx].offX, region.Tiles[tileIdx].offY, region.Tiles[tileIdx].tileX, region.Tiles[tileIdx].tileY, target)
|
v.RenderPass2(region.Region, region.Tiles[tileIdx].tileX, region.Tiles[tileIdx].tileY, target)
|
||||||
|
v.viewport.PopTranslation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for tileIdx := range region.Tiles {
|
for tileIdx := range region.Tiles {
|
||||||
sx, sy := d2helper.IsoToScreen(float64(region.Tiles[tileIdx].tileX+region.Rect.Left), float64(region.Tiles[tileIdx].tileY+region.Rect.Top), v.OffsetX, v.OffsetY)
|
if v.viewport.IsWorldTileVisbile(float64(region.Tiles[tileIdx].tileX+region.Rect.Left), float64(region.Tiles[tileIdx].tileY+region.Rect.Top)) {
|
||||||
if sx > -160 && sy > -380 && sx <= 880 && sy <= 1240 {
|
v.viewport.PushTranslation(float64(region.Tiles[tileIdx].offX), float64(region.Tiles[tileIdx].offY))
|
||||||
v.RenderPass3(region.Region, region.Tiles[tileIdx].offX, region.Tiles[tileIdx].offY, region.Tiles[tileIdx].tileX, region.Tiles[tileIdx].tileY, target)
|
v.RenderPass3(region.Region, region.Tiles[tileIdx].tileX, region.Tiles[tileIdx].tileY, target)
|
||||||
|
v.viewport.PopTranslation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Engine) RenderPass1(region *Region, offX, offY, x, y int, target *ebiten.Image) {
|
func (v *Engine) RenderPass1(region *Region, x, y int, target *ebiten.Image) {
|
||||||
tile := region.DS1.Tiles[y][x]
|
tile := region.DS1.Tiles[y][x]
|
||||||
// Draw lower walls
|
// Draw lower walls
|
||||||
for i := range tile.Walls {
|
for i := range tile.Walls {
|
||||||
if !tile.Walls[i].Type.LowerWall() || tile.Walls[i].Prop1 == 0 || tile.Walls[i].Hidden {
|
if !tile.Walls[i].Type.LowerWall() || tile.Walls[i].Prop1 == 0 || tile.Walls[i].Hidden {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
region.RenderTile(offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, d2enum.RegionLayerTypeWalls, i, target)
|
|
||||||
|
region.RenderTile(v.viewport, x, y, d2enum.RegionLayerTypeWalls, i, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range tile.Floors {
|
for i := range tile.Floors {
|
||||||
if tile.Floors[i].Hidden || tile.Floors[i].Prop1 == 0 {
|
if tile.Floors[i].Hidden || tile.Floors[i].Prop1 == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
region.RenderTile(offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, d2enum.RegionLayerTypeFloors, i, target)
|
|
||||||
|
region.RenderTile(v.viewport, x, y, d2enum.RegionLayerTypeFloors, i, target)
|
||||||
}
|
}
|
||||||
for i := range tile.Shadows {
|
for i := range tile.Shadows {
|
||||||
if tile.Shadows[i].Hidden || tile.Shadows[i].Prop1 == 0 {
|
if tile.Shadows[i].Hidden || tile.Shadows[i].Prop1 == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
region.RenderTile(offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, d2enum.RegionLayerTypeShadows, i, target)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
region.RenderTile(v.viewport, x, y, d2enum.RegionLayerTypeShadows, i, target)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Engine) RenderPass2(region *Region, offX, offY, x, y int, target *ebiten.Image) {
|
func (v *Engine) RenderPass2(region *Region, x, y int, target *ebiten.Image) {
|
||||||
tile := region.DS1.Tiles[y][x]
|
tile := region.DS1.Tiles[y][x]
|
||||||
|
|
||||||
// Draw upper walls
|
// Draw upper walls
|
||||||
|
@ -248,63 +261,108 @@ func (v *Engine) RenderPass2(region *Region, offX, offY, x, y int, target *ebite
|
||||||
if !tile.Walls[i].Type.UpperWall() || tile.Walls[i].Hidden {
|
if !tile.Walls[i].Type.UpperWall() || tile.Walls[i].Hidden {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
region.RenderTile(offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, d2enum.RegionLayerTypeWalls, i, target)
|
|
||||||
|
region.RenderTile(v.viewport, x, y, d2enum.RegionLayerTypeWalls, i, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
screenX, screenY := v.viewport.WorldToScreen(v.viewport.GetTranslation())
|
||||||
|
|
||||||
for _, obj := range region.AnimationEntities {
|
for _, obj := range region.AnimationEntities {
|
||||||
if obj.TileX == x && obj.TileY == y {
|
if obj.TileX == x && obj.TileY == y {
|
||||||
obj.Render(target, offX+int(v.OffsetX), offY+int(v.OffsetY))
|
obj.Render(target, screenX, screenY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, npc := range region.NPCs {
|
for _, npc := range region.NPCs {
|
||||||
if npc.AnimatedEntity.TileX == x && npc.AnimatedEntity.TileY == y {
|
if npc.AnimatedEntity.TileX == x && npc.AnimatedEntity.TileY == y {
|
||||||
npc.Render(target, offX+int(v.OffsetX), offY+int(v.OffsetY))
|
npc.Render(target, screenX, screenY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.Hero != nil && v.Hero.AnimatedEntity.TileX == x && v.Hero.AnimatedEntity.TileY == y {
|
if v.Hero != nil && v.Hero.AnimatedEntity.TileX == x && v.Hero.AnimatedEntity.TileY == y {
|
||||||
v.Hero.Render(target, offX+int(v.OffsetX), offY+int(v.OffsetY))
|
v.Hero.Render(target, screenX, screenY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Engine) RenderPass3(region *Region, offX, offY, x, y int, target *ebiten.Image) {
|
func (v *Engine) RenderPass3(region *Region, x, y int, target *ebiten.Image) {
|
||||||
tile := region.DS1.Tiles[y][x]
|
tile := region.DS1.Tiles[y][x]
|
||||||
// Draw ceilings
|
// Draw ceilings
|
||||||
for i := range tile.Walls {
|
for i := range tile.Walls {
|
||||||
if tile.Walls[i].Type != d2enum.Roof {
|
if tile.Walls[i].Type != d2enum.Roof {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
region.RenderTile(offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, d2enum.RegionLayerTypeWalls, i, target)
|
|
||||||
|
region.RenderTile(v.viewport, x, y, d2enum.RegionLayerTypeWalls, i, target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Engine) DrawTileLines(region *Region, offX, offY, x, y int, target *ebiten.Image) {
|
func (v *Engine) DrawTileLines(region *Region, x, y int, target *ebiten.Image) {
|
||||||
if v.ShowTiles > 0 {
|
if v.ShowTiles > 0 {
|
||||||
subtileColor := color.RGBA{80, 80, 255, 100}
|
subtileColor := color.RGBA{80, 80, 255, 100}
|
||||||
tileColor := color.RGBA{255, 255, 255, 255}
|
tileColor := color.RGBA{255, 255, 255, 255}
|
||||||
|
|
||||||
ebitenutil.DrawLine(target, float64(offX)+v.OffsetX, float64(offY)+v.OffsetY, float64(offX)+v.OffsetX+80, float64(offY)+v.OffsetY+40, tileColor)
|
screenX1, screenY1 := v.viewport.IsoToScreen(float64(x), float64(y))
|
||||||
ebitenutil.DrawLine(target, float64(offX)+v.OffsetX, float64(offY)+v.OffsetY, float64(offX)+v.OffsetX-80, float64(offY)+v.OffsetY+40, tileColor)
|
screenX2, screenY2 := v.viewport.IsoToScreen(float64(x+1), float64(y))
|
||||||
|
screenX3, screenY3 := v.viewport.IsoToScreen(float64(x), float64(y+1))
|
||||||
|
|
||||||
coords := fmt.Sprintf("%v,%v", x, y)
|
ebitenutil.DrawLine(
|
||||||
ebitenutil.DebugPrintAt(target, coords, offX+int(v.OffsetX)-10, offY+int(v.OffsetY)+10)
|
target,
|
||||||
|
float64(screenX1),
|
||||||
|
float64(screenY1),
|
||||||
|
float64(screenX2),
|
||||||
|
float64(screenY2),
|
||||||
|
tileColor,
|
||||||
|
)
|
||||||
|
|
||||||
|
ebitenutil.DrawLine(
|
||||||
|
target,
|
||||||
|
float64(screenX1),
|
||||||
|
float64(screenY1),
|
||||||
|
float64(screenX3),
|
||||||
|
float64(screenY3),
|
||||||
|
tileColor,
|
||||||
|
)
|
||||||
|
|
||||||
|
ebitenutil.DebugPrintAt(
|
||||||
|
target,
|
||||||
|
fmt.Sprintf("%v,%v", x, y),
|
||||||
|
screenX1-10,
|
||||||
|
screenY1+10,
|
||||||
|
)
|
||||||
|
|
||||||
if v.ShowTiles > 1 {
|
if v.ShowTiles > 1 {
|
||||||
for i := 1; i <= 4; i++ {
|
for i := 1; i <= 4; i++ {
|
||||||
x := (16 * i)
|
x := i * 16
|
||||||
y := (8 * i)
|
y := i * 8
|
||||||
ebitenutil.DrawLine(target, float64(offX-x)+v.OffsetX, float64(offY+y)+v.OffsetY,
|
|
||||||
float64(offX-x)+v.OffsetX+80, float64(offY+y)+v.OffsetY+40, subtileColor)
|
ebitenutil.DrawLine(
|
||||||
ebitenutil.DrawLine(target, float64(offX+x)+v.OffsetX, float64(offY+y)+v.OffsetY,
|
target,
|
||||||
float64(offX+x)+v.OffsetX-80, float64(offY+y)+v.OffsetY+40, subtileColor)
|
float64(screenX1-x),
|
||||||
|
float64(screenY1+y),
|
||||||
|
float64(screenX1-x+80),
|
||||||
|
float64(screenY1+y+40),
|
||||||
|
subtileColor,
|
||||||
|
)
|
||||||
|
|
||||||
|
ebitenutil.DrawLine(
|
||||||
|
target,
|
||||||
|
float64(screenX1+x),
|
||||||
|
float64(screenY1+y),
|
||||||
|
float64(screenX1+x-80),
|
||||||
|
float64(screenY1+y+40),
|
||||||
|
subtileColor,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
tile := region.DS1.Tiles[y][x]
|
tile := region.DS1.Tiles[y][x]
|
||||||
for i := range tile.Floors {
|
for i := range tile.Floors {
|
||||||
floorSpec := fmt.Sprintf("f: %v-%v", tile.Floors[i].Style, tile.Floors[i].Sequence)
|
ebitenutil.DebugPrintAt(
|
||||||
ebitenutil.DebugPrintAt(target, floorSpec, offX+int(v.OffsetX)-20, offY+int(v.OffsetY)+10+((i+1)*14))
|
target,
|
||||||
|
fmt.Sprintf("f: %v-%v", tile.Floors[i].Style, tile.Floors[i].Sequence),
|
||||||
|
screenX1-20,
|
||||||
|
screenY1+10+(i+1)*14,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
// wallSpec := fmt.Sprintf("w: %v-%v", tile.Walls[0].Style, tile.Walls[0].Sequence)
|
|
||||||
// ebitenutil.DebugPrintAt(target, wallSpec, offX+int(v.OffsetX)-20, offY+int(v.OffsetY)+34)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,9 @@ import (
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2ds1"
|
"github.com/OpenDiablo2/D2Shared/d2data/d2ds1"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2helper"
|
"github.com/OpenDiablo2/D2Shared/d2helper"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
|
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||||
|
|
||||||
|
@ -150,15 +150,14 @@ func (v *Region) UpdateAnimations() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Region) RenderTile(offsetX, offsetY, tileX, tileY int, layerType d2enum.RegionLayerType, layerIndex int, target *ebiten.Image) {
|
func (v *Region) RenderTile(viewport *Viewport, tileX, tileY int, layerType d2enum.RegionLayerType, layerIndex int, target *ebiten.Image) {
|
||||||
offsetX -= 80
|
|
||||||
switch layerType {
|
switch layerType {
|
||||||
case d2enum.RegionLayerTypeFloors:
|
case d2enum.RegionLayerTypeFloors:
|
||||||
v.renderFloor(v.DS1.Tiles[tileY][tileX].Floors[layerIndex], offsetX, offsetY, target, tileX, tileY)
|
v.renderFloor(v.DS1.Tiles[tileY][tileX].Floors[layerIndex], viewport, target, tileX, tileY)
|
||||||
case d2enum.RegionLayerTypeWalls:
|
case d2enum.RegionLayerTypeWalls:
|
||||||
v.renderWall(v.DS1.Tiles[tileY][tileX].Walls[layerIndex], offsetX, offsetY, target, tileX, tileY)
|
v.renderWall(v.DS1.Tiles[tileY][tileX].Walls[layerIndex], viewport, target, tileX, tileY)
|
||||||
case d2enum.RegionLayerTypeShadows:
|
case d2enum.RegionLayerTypeShadows:
|
||||||
v.renderShadow(v.DS1.Tiles[tileY][tileX].Shadows[layerIndex], offsetX, offsetY, target, tileX, tileY)
|
v.renderShadow(v.DS1.Tiles[tileY][tileX].Shadows[layerIndex], viewport, target, tileX, tileY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +211,7 @@ func (v *Region) getTiles(style, sequence, tileType int32, x, y int, seed int64)
|
||||||
return tiles
|
return tiles
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Region) renderFloor(tile d2ds1.FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image, tileX, tileY int) {
|
func (v *Region) renderFloor(tile d2ds1.FloorShadowRecord, viewport *Viewport, target *ebiten.Image, tileX, tileY int) {
|
||||||
var img *ebiten.Image
|
var img *ebiten.Image
|
||||||
if !tile.Animated {
|
if !tile.Animated {
|
||||||
img = v.GetImageCacheRecord(tile.Style, tile.Sequence, 0, tile.RandomIndex)
|
img = v.GetImageCacheRecord(tile.Style, tile.Sequence, 0, tile.RandomIndex)
|
||||||
|
@ -223,33 +222,44 @@ func (v *Region) renderFloor(tile d2ds1.FloorShadowRecord, offsetX, offsetY int,
|
||||||
log.Printf("Render called on uncached floor {%v,%v}", tile.Style, tile.Sequence)
|
log.Printf("Render called on uncached floor {%v,%v}", tile.Style, tile.Sequence)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewport.PushTranslation(-80, float64(tile.YAdjust))
|
||||||
|
screenX, screenY := viewport.WorldToScreen(viewport.GetTranslation())
|
||||||
opts := &ebiten.DrawImageOptions{}
|
opts := &ebiten.DrawImageOptions{}
|
||||||
opts.GeoM.Translate(float64(offsetX), float64(offsetY))
|
opts.GeoM.Translate(float64(screenX), float64(screenY))
|
||||||
_ = target.DrawImage(img, opts)
|
target.DrawImage(img, opts)
|
||||||
return
|
viewport.PopTranslation()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Region) renderWall(tile d2ds1.WallRecord, offsetX, offsetY int, target *ebiten.Image, tileX, tileY int) {
|
func (v *Region) renderWall(tile d2ds1.WallRecord, viewport *Viewport, target *ebiten.Image, tileX, tileY int) {
|
||||||
img := v.GetImageCacheRecord(tile.Style, tile.Sequence, tile.Type, tile.RandomIndex)
|
img := v.GetImageCacheRecord(tile.Style, tile.Sequence, tile.Type, tile.RandomIndex)
|
||||||
if img == nil {
|
if img == nil {
|
||||||
log.Printf("Render called on uncached wall {%v,%v,%v}", tile.Style, tile.Sequence, tile.Type)
|
log.Printf("Render called on uncached wall {%v,%v,%v}", tile.Style, tile.Sequence, tile.Type)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewport.PushTranslation(-80, float64(tile.YAdjust))
|
||||||
|
screenX, screenY := viewport.WorldToScreen(viewport.GetTranslation())
|
||||||
opts := &ebiten.DrawImageOptions{}
|
opts := &ebiten.DrawImageOptions{}
|
||||||
opts.GeoM.Translate(float64(offsetX), float64(offsetY+tile.YAdjust))
|
opts.GeoM.Translate(float64(screenX), float64(screenY))
|
||||||
target.DrawImage(img, opts)
|
target.DrawImage(img, opts)
|
||||||
|
viewport.PopTranslation()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Region) renderShadow(tile d2ds1.FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image, tileX, tileY int) {
|
func (v *Region) renderShadow(tile d2ds1.FloorShadowRecord, viewport *Viewport, target *ebiten.Image, tileX, tileY int) {
|
||||||
img := v.GetImageCacheRecord(tile.Style, tile.Sequence, 13, tile.RandomIndex)
|
img := v.GetImageCacheRecord(tile.Style, tile.Sequence, 13, tile.RandomIndex)
|
||||||
if img == nil {
|
if img == nil {
|
||||||
log.Printf("Render called on uncached shadow {%v,%v}", tile.Style, tile.Sequence)
|
log.Printf("Render called on uncached shadow {%v,%v}", tile.Style, tile.Sequence)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewport.PushTranslation(-80, float64(tile.YAdjust))
|
||||||
|
screenX, screenY := viewport.WorldToScreen(viewport.GetTranslation())
|
||||||
opts := &ebiten.DrawImageOptions{}
|
opts := &ebiten.DrawImageOptions{}
|
||||||
opts.GeoM.Translate(float64(offsetX), float64(offsetY+tile.YAdjust))
|
opts.GeoM.Translate(float64(screenX), float64(screenY))
|
||||||
opts.ColorM = d2corehelper.ColorToColorM(color.RGBA{255, 255, 255, 160})
|
opts.ColorM = d2corehelper.ColorToColorM(color.RGBA{255, 255, 255, 160})
|
||||||
target.DrawImage(img, opts)
|
target.DrawImage(img, opts)
|
||||||
|
viewport.PopTranslation()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Region) decodeTileGfxData(blocks []d2dt1.Block, pixels *[]byte, tileYOffset int32, tileWidth int32) {
|
func (v *Region) decodeTileGfxData(blocks []d2dt1.Block, pixels *[]byte, tileYOffset int32, tileWidth int32) {
|
||||||
|
|
117
d2render/d2mapengine/viewport.go
Normal file
117
d2render/d2mapengine/viewport.go
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
package d2mapengine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/D2Shared/d2common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type worldTrans struct {
|
||||||
|
x float64
|
||||||
|
y float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type Viewport struct {
|
||||||
|
screenRect d2common.Rectangle
|
||||||
|
transStack []worldTrans
|
||||||
|
transCurrent worldTrans
|
||||||
|
camera *Camera
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewViewport(x, y, width, height int) *Viewport {
|
||||||
|
return &Viewport{
|
||||||
|
screenRect: d2common.Rectangle{
|
||||||
|
Left: x,
|
||||||
|
Top: y,
|
||||||
|
Width: width,
|
||||||
|
Height: height,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viewport) SetCamera(camera *Camera) {
|
||||||
|
v.camera = camera
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viewport) IsoToScreen(x, y float64) (int, int) {
|
||||||
|
return v.WorldToScreen(v.IsoToWorld(x, y))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viewport) ScreenToIso(x, y int) (float64, float64) {
|
||||||
|
return v.WorldToIso(v.ScreenToWorld(x, y))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viewport) WorldToIso(x, y float64) (float64, float64) {
|
||||||
|
isoX := (x/80 + y/40) / 2
|
||||||
|
isoY := (y/40 - x/80) / 2
|
||||||
|
return isoX, isoY
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viewport) IsoToWorld(x, y float64) (float64, float64) {
|
||||||
|
worldX := (x - y) * 80
|
||||||
|
worldY := (x + y) * 40
|
||||||
|
return worldX, worldY
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viewport) ScreenToWorld(x, y int) (float64, float64) {
|
||||||
|
camX, camY := v.getCameraOffset()
|
||||||
|
screenX := float64(x) + camX - float64(v.screenRect.Left)
|
||||||
|
screenY := float64(y) + camY - float64(v.screenRect.Top)
|
||||||
|
return screenX, screenY
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viewport) WorldToScreen(x, y float64) (int, int) {
|
||||||
|
camX, camY := v.getCameraOffset()
|
||||||
|
worldX := int(math.Floor(x - camX + float64(v.screenRect.Left)))
|
||||||
|
worldY := int(math.Floor(y - camY + float64(v.screenRect.Top)))
|
||||||
|
return worldX, worldY
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viewport) IsWorldTileVisbile(x, y float64) bool {
|
||||||
|
worldX1, worldY1 := v.IsoToWorld(x-2, y)
|
||||||
|
worldX2, worldY2 := v.IsoToWorld(x+2, y)
|
||||||
|
return v.IsWorldRectVisible(worldX1, worldY1, worldX2, worldY2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viewport) IsWorldPointVisible(x, y float64) bool {
|
||||||
|
screenX, screenY := v.WorldToScreen(x, y)
|
||||||
|
return screenX >= 0 && screenX < v.screenRect.Width && screenY >= 0 && screenY < v.screenRect.Height
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viewport) IsWorldRectVisible(x1, y1, x2, y2 float64) bool {
|
||||||
|
screenX1, screenY1 := v.WorldToScreen(x1, y1)
|
||||||
|
screenX2, screenY2 := v.WorldToScreen(x2, y2)
|
||||||
|
return !(screenX1 >= v.screenRect.Width || screenX2 < 0 || screenY1 >= v.screenRect.Height || screenY2 < 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viewport) GetTranslation() (float64, float64) {
|
||||||
|
return v.transCurrent.x, v.transCurrent.y
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viewport) PushTranslation(x, y float64) {
|
||||||
|
v.transStack = append(v.transStack, v.transCurrent)
|
||||||
|
v.transCurrent.x += x
|
||||||
|
v.transCurrent.y += y
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viewport) PopTranslation() {
|
||||||
|
count := len(v.transStack)
|
||||||
|
if count == 0 {
|
||||||
|
panic("empty stack")
|
||||||
|
}
|
||||||
|
|
||||||
|
v.transCurrent = v.transStack[count-1]
|
||||||
|
v.transStack = v.transStack[:count-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Viewport) getCameraOffset() (float64, float64) {
|
||||||
|
var camX, camY float64
|
||||||
|
if v.camera != nil {
|
||||||
|
camX, camY = v.camera.GetPosition()
|
||||||
|
}
|
||||||
|
|
||||||
|
camX -= float64(v.screenRect.Width / 2)
|
||||||
|
camY -= float64(v.screenRect.Height / 2)
|
||||||
|
|
||||||
|
return camX, camY
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user