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
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
|
||||
|
@ -14,7 +16,6 @@ import (
|
|||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2mapengine"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
|
@ -128,9 +129,7 @@ func (v *Game) Update(tickTime float64) {
|
|||
}
|
||||
|
||||
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
|
||||
mx, my := ebiten.CursorPosition()
|
||||
px, py := d2helper.ScreenToIso(float64(mx)-v.mapEngine.OffsetX, float64(my)-v.mapEngine.OffsetY)
|
||||
|
||||
px, py := v.mapEngine.ScreenToIso(ebiten.CursorPosition())
|
||||
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) {
|
||||
v.mapEngine.Render(screen)
|
||||
actualX := float64(v.uiManager.CursorX) - v.mapEngine.OffsetX
|
||||
actualY := float64(v.uiManager.CursorY) - v.mapEngine.OffsetY
|
||||
tileX, tileY := d2helper.ScreenToIso(actualX, actualY)
|
||||
actualX := v.uiManager.CursorX
|
||||
actualY := v.uiManager.CursorY
|
||||
tileX, tileY := v.mapEngine.ScreenToIso(actualX, actualY)
|
||||
subtileX := int(math.Ceil(math.Mod((tileX*10), 10))) / 2
|
||||
subtileY := int(math.Ceil(math.Mod((tileY*10), 10))) / 2
|
||||
curRegion := v.mapEngine.GetRegionAt(int(tileX), int(tileY))
|
||||
|
@ -182,8 +182,8 @@ func (v *MapEngineTest) Render(screen *ebiten.Image) {
|
|||
return
|
||||
}
|
||||
line := fmt.Sprintf("%d, %d (Tile %d.%d, %d.%d)",
|
||||
int(math.Ceil(actualX)),
|
||||
int(math.Ceil(actualY)),
|
||||
actualX,
|
||||
actualY,
|
||||
int(math.Floor(tileX))-curRegion.Rect.Left,
|
||||
subtileX,
|
||||
int(math.Floor(tileY))-curRegion.Rect.Top,
|
||||
|
@ -217,33 +217,22 @@ func (v *MapEngineTest) Update(tickTime float64) {
|
|||
ctrlPressed := v.uiManager.KeyPressed(ebiten.KeyControl)
|
||||
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.KeyShift) {
|
||||
v.mapEngine.OffsetY -= tickTime * 200
|
||||
} else {
|
||||
v.mapEngine.OffsetY -= tickTime * 800
|
||||
}
|
||||
v.mapEngine.MoveCameraBy(0, moveSpeed*tickTime)
|
||||
}
|
||||
if v.uiManager.KeyPressed(ebiten.KeyUp) {
|
||||
if v.uiManager.KeyPressed(ebiten.KeyShift) {
|
||||
v.mapEngine.OffsetY += tickTime * 200
|
||||
} else {
|
||||
v.mapEngine.OffsetY += tickTime * 800
|
||||
}
|
||||
v.mapEngine.MoveCameraBy(0, -moveSpeed*tickTime)
|
||||
}
|
||||
if v.uiManager.KeyPressed(ebiten.KeyLeft) {
|
||||
if v.uiManager.KeyPressed(ebiten.KeyShift) {
|
||||
v.mapEngine.OffsetX += tickTime * 200
|
||||
} else {
|
||||
v.mapEngine.OffsetX += tickTime * 800
|
||||
}
|
||||
v.mapEngine.MoveCameraBy(-moveSpeed*tickTime, 0)
|
||||
}
|
||||
if v.uiManager.KeyPressed(ebiten.KeyRight) {
|
||||
if v.uiManager.KeyPressed(ebiten.KeyShift) {
|
||||
v.mapEngine.OffsetX -= tickTime * 200
|
||||
} else {
|
||||
v.mapEngine.OffsetX -= tickTime * 800
|
||||
}
|
||||
v.mapEngine.MoveCameraBy(moveSpeed*tickTime, 0)
|
||||
}
|
||||
|
||||
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/d2helper"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2common/d2interface"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||
|
@ -36,27 +34,31 @@ type Engine struct {
|
|||
fileProvider d2interface.FileProvider
|
||||
region int
|
||||
regions []EngineRegion
|
||||
OffsetX float64
|
||||
OffsetY float64
|
||||
ShowTiles int
|
||||
Hero *d2core.Hero
|
||||
|
||||
viewport *Viewport
|
||||
camera Camera
|
||||
}
|
||||
|
||||
func CreateMapEngine(gameState *d2core.GameState, soundManager *d2audio.Manager, fileProvider d2interface.FileProvider) *Engine {
|
||||
result := &Engine{
|
||||
engine := &Engine{
|
||||
gameState: gameState,
|
||||
soundManager: soundManager,
|
||||
fileProvider: fileProvider,
|
||||
regions: make([]EngineRegion, 0),
|
||||
viewport: NewViewport(0, 0, 800, 600),
|
||||
}
|
||||
return result
|
||||
|
||||
engine.viewport.SetCamera(&engine.camera)
|
||||
return engine
|
||||
}
|
||||
|
||||
func (v *Engine) Region() *EngineRegion {
|
||||
return &v.regions[v.region]
|
||||
}
|
||||
|
||||
func (v *Engine) SetRegion(region int) {
|
||||
func (v *Engine) SetRegion(region int) {
|
||||
v.region = region
|
||||
}
|
||||
|
||||
|
@ -65,8 +67,19 @@ func (v *Engine) GetRegion(regionIndex int) *EngineRegion {
|
|||
}
|
||||
|
||||
func (v *Engine) CenterCameraOn(x, y float64) {
|
||||
v.OffsetX = -(x - 400)
|
||||
v.OffsetY = -(y - 300)
|
||||
v.camera.MoveTo(x, y)
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -109,36 +122,31 @@ func (v *Engine) GenerateAct1Overworld() {
|
|||
v.GenTilesCache(&v.regions[i])
|
||||
}
|
||||
|
||||
sx, sy := d2helper.IsoToScreen(region.StartX, region.StartY, 0, 0)
|
||||
v.OffsetX = sx - 400
|
||||
v.OffsetY = sy - 300
|
||||
v.camera.MoveTo(v.viewport.IsoToWorld(region.StartX, region.StartY))
|
||||
}
|
||||
|
||||
func (v *Engine) GetRegionAt(x, y int) *EngineRegion {
|
||||
if v.regions == nil {
|
||||
return nil
|
||||
}
|
||||
for _, region := range v.regions {
|
||||
if !region.Rect.IsInRect(x, y) {
|
||||
continue
|
||||
if region.Rect.IsInRect(x, y) {
|
||||
return ®ion
|
||||
}
|
||||
return ®ion
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Engine) Render(target *ebiten.Image) {
|
||||
for _, region := range v.regions {
|
||||
// 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
|
||||
top := (region.Rect.Left + region.Rect.Top) * 40
|
||||
top := float64((region.Rect.Left + region.Rect.Top) * 40)
|
||||
// X of right
|
||||
right := (region.Rect.Right() - region.Rect.Top) * 80
|
||||
right := float64((region.Rect.Right() - region.Rect.Top) * 80)
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
@ -191,56 +199,61 @@ func (v *Engine) GenTilesCache(region *EngineRegion) {
|
|||
|
||||
func (v *Engine) RenderRegion(region EngineRegion, target *ebiten.Image) {
|
||||
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 sx > -160 && sy > -380 && sx <= 880 && sy <= 1240 {
|
||||
if v.viewport.IsWorldTileVisbile(float64(region.Tiles[tileIdx].tileX+region.Rect.Left), float64(region.Tiles[tileIdx].tileY+region.Rect.Top)) {
|
||||
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 {
|
||||
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 sx > -160 && sy > -380 && sx <= 880 && sy <= 1240 {
|
||||
v.RenderPass2(region.Region, region.Tiles[tileIdx].offX, region.Tiles[tileIdx].offY, region.Tiles[tileIdx].tileX, region.Tiles[tileIdx].tileY, target)
|
||||
if v.viewport.IsWorldTileVisbile(float64(region.Tiles[tileIdx].tileX+region.Rect.Left), float64(region.Tiles[tileIdx].tileY+region.Rect.Top)) {
|
||||
v.viewport.PushTranslation(float64(region.Tiles[tileIdx].offX), float64(region.Tiles[tileIdx].offY))
|
||||
v.RenderPass2(region.Region, region.Tiles[tileIdx].tileX, region.Tiles[tileIdx].tileY, target)
|
||||
v.viewport.PopTranslation()
|
||||
}
|
||||
}
|
||||
|
||||
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 sx > -160 && sy > -380 && sx <= 880 && sy <= 1240 {
|
||||
v.RenderPass3(region.Region, region.Tiles[tileIdx].offX, region.Tiles[tileIdx].offY, region.Tiles[tileIdx].tileX, region.Tiles[tileIdx].tileY, target)
|
||||
if v.viewport.IsWorldTileVisbile(float64(region.Tiles[tileIdx].tileX+region.Rect.Left), float64(region.Tiles[tileIdx].tileY+region.Rect.Top)) {
|
||||
v.viewport.PushTranslation(float64(region.Tiles[tileIdx].offX), float64(region.Tiles[tileIdx].offY))
|
||||
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]
|
||||
// Draw lower walls
|
||||
for i := range tile.Walls {
|
||||
if !tile.Walls[i].Type.LowerWall() || tile.Walls[i].Prop1 == 0 || tile.Walls[i].Hidden {
|
||||
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 {
|
||||
if tile.Floors[i].Hidden || tile.Floors[i].Prop1 == 0 {
|
||||
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 {
|
||||
if tile.Shadows[i].Hidden || tile.Shadows[i].Prop1 == 0 {
|
||||
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]
|
||||
|
||||
// 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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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]
|
||||
// Draw ceilings
|
||||
for i := range tile.Walls {
|
||||
if tile.Walls[i].Type != d2enum.Roof {
|
||||
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 {
|
||||
subtileColor := color.RGBA{80, 80, 255, 100}
|
||||
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)
|
||||
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))
|
||||
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.DebugPrintAt(target, coords, offX+int(v.OffsetX)-10, offY+int(v.OffsetY)+10)
|
||||
ebitenutil.DrawLine(
|
||||
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 {
|
||||
for i := 1; i <= 4; i++ {
|
||||
x := (16 * i)
|
||||
y := (8 * i)
|
||||
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(target, float64(offX+x)+v.OffsetX, float64(offY+y)+v.OffsetY,
|
||||
float64(offX+x)+v.OffsetX-80, float64(offY+y)+v.OffsetY+40, subtileColor)
|
||||
x := i * 16
|
||||
y := i * 8
|
||||
|
||||
ebitenutil.DrawLine(
|
||||
target,
|
||||
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]
|
||||
for i := range tile.Floors {
|
||||
floorSpec := fmt.Sprintf("f: %v-%v", tile.Floors[i].Style, tile.Floors[i].Sequence)
|
||||
ebitenutil.DebugPrintAt(target, floorSpec, offX+int(v.OffsetX)-20, offY+int(v.OffsetY)+10+((i+1)*14))
|
||||
ebitenutil.DebugPrintAt(
|
||||
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/OpenDiablo2/d2core"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
|
||||
|
||||
"github.com/OpenDiablo2/D2Shared/d2helper"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
|
||||
|
||||
"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) {
|
||||
offsetX -= 80
|
||||
func (v *Region) RenderTile(viewport *Viewport, tileX, tileY int, layerType d2enum.RegionLayerType, layerIndex int, target *ebiten.Image) {
|
||||
switch layerType {
|
||||
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:
|
||||
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:
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
if !tile.Animated {
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
||||
viewport.PushTranslation(-80, float64(tile.YAdjust))
|
||||
screenX, screenY := viewport.WorldToScreen(viewport.GetTranslation())
|
||||
opts := &ebiten.DrawImageOptions{}
|
||||
opts.GeoM.Translate(float64(offsetX), float64(offsetY))
|
||||
_ = target.DrawImage(img, opts)
|
||||
return
|
||||
opts.GeoM.Translate(float64(screenX), float64(screenY))
|
||||
target.DrawImage(img, opts)
|
||||
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)
|
||||
if img == nil {
|
||||
log.Printf("Render called on uncached wall {%v,%v,%v}", tile.Style, tile.Sequence, tile.Type)
|
||||
return
|
||||
}
|
||||
|
||||
viewport.PushTranslation(-80, float64(tile.YAdjust))
|
||||
screenX, screenY := viewport.WorldToScreen(viewport.GetTranslation())
|
||||
opts := &ebiten.DrawImageOptions{}
|
||||
opts.GeoM.Translate(float64(offsetX), float64(offsetY+tile.YAdjust))
|
||||
opts.GeoM.Translate(float64(screenX), float64(screenY))
|
||||
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)
|
||||
if img == nil {
|
||||
log.Printf("Render called on uncached shadow {%v,%v}", tile.Style, tile.Sequence)
|
||||
return
|
||||
}
|
||||
|
||||
viewport.PushTranslation(-80, float64(tile.YAdjust))
|
||||
screenX, screenY := viewport.WorldToScreen(viewport.GetTranslation())
|
||||
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})
|
||||
target.DrawImage(img, opts)
|
||||
viewport.PopTranslation()
|
||||
}
|
||||
|
||||
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