mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-20 07:27:19 -05:00
Smooth camera targetting (#607)
* smooth camera with vectors * add smooth cam support to map engine test smooth cam now works in map engine test. clicking or holding the left-mouse button will move the camera. also works with freecam mode in single-player. * Update ebiten_renderer.go did not mean to edit this file
This commit is contained in:
parent
6db299b31d
commit
aadfa35e6b
@ -1,25 +1,56 @@
|
||||
package d2maprenderer
|
||||
|
||||
// Camera is the position of the camera perspective in orthogonal world space. See viewport.go.
|
||||
// TODO: Has a coordinate (issue #456)
|
||||
import "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
|
||||
// Camera is the position of the Camera perspective in orthogonal world space. See viewport.go.
|
||||
type Camera struct {
|
||||
x float64
|
||||
y float64
|
||||
position *d2vector.Position
|
||||
target *d2vector.Position
|
||||
}
|
||||
|
||||
// MoveTo sets the position of the camera to the given x and y coordinates.
|
||||
func (c *Camera) MoveTo(x, y float64) {
|
||||
c.x = x
|
||||
c.y = y
|
||||
// MoveTo sets the position of the Camera to the given position
|
||||
func (c *Camera) MoveTo(position *d2vector.Position) {
|
||||
c.position = position
|
||||
}
|
||||
|
||||
// MoveBy adds the given vector to the current position of the camera.
|
||||
func (c *Camera) MoveBy(x, y float64) {
|
||||
c.x += x
|
||||
c.y += y
|
||||
// MoveBy adds the given vector to the current position of the Camera.
|
||||
func (c *Camera) MoveBy(vector *d2vector.Vector) {
|
||||
c.position.Add(vector)
|
||||
}
|
||||
|
||||
// GetPosition returns the camera x and y position.
|
||||
func (c *Camera) GetPosition() (float64, float64) {
|
||||
return c.x, c.y
|
||||
// SetTarget sets the target position
|
||||
func (c *Camera) SetTarget(target *d2vector.Position) {
|
||||
c.target = target
|
||||
}
|
||||
|
||||
// MoveBy adds the given vector to the current position of the Camera.
|
||||
func (c *Camera) MoveTargetBy(vector *d2vector.Vector) {
|
||||
if c.target == nil {
|
||||
v := c.position.Clone()
|
||||
c.target = &d2vector.Position{v}
|
||||
}
|
||||
c.target.Add(vector)
|
||||
}
|
||||
|
||||
// ClearTarget sets the target position
|
||||
func (c *Camera) ClearTarget() {
|
||||
c.target = nil
|
||||
}
|
||||
|
||||
// GetPosition returns the Camera position
|
||||
func (c *Camera) GetPosition() *d2vector.Position {
|
||||
return c.position
|
||||
}
|
||||
|
||||
// Advance returns the Camera position
|
||||
func (c *Camera) Advance(elapsed float64) {
|
||||
c.advanceToTarget(elapsed)
|
||||
}
|
||||
|
||||
func (c *Camera) advanceToTarget(_ float64) {
|
||||
if c.target != nil {
|
||||
diff := c.position.World().Subtract(c.target.World())
|
||||
diff.Scale(-0.85)
|
||||
c.MoveBy(diff)
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package d2maprenderer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
"image/color"
|
||||
"log"
|
||||
"math"
|
||||
@ -14,13 +15,13 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
|
||||
)
|
||||
|
||||
// MapRenderer manages the game viewport and camera. It requests tile and entity data from MapEngine and renders it.
|
||||
// MapRenderer manages the game viewport and Camera. It requests tile and entity data from MapEngine and renders it.
|
||||
type MapRenderer struct {
|
||||
renderer d2interface.Renderer // Used for drawing operations
|
||||
mapEngine *d2mapengine.MapEngine // The map engine that is being rendered
|
||||
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
|
||||
Camera Camera // Used to determine where on the map we are rendering
|
||||
debugVisLevel int // Debug visibility index (0=none, 1=tiles, 2=sub-tiles)
|
||||
lastFrameTime float64 // The last time the map was rendered
|
||||
currentFrame int // Current render frame (for animations)
|
||||
@ -34,7 +35,10 @@ func CreateMapRenderer(renderer d2interface.Renderer, mapEngine *d2mapengine.Map
|
||||
viewport: NewViewport(0, 0, 800, 600),
|
||||
}
|
||||
|
||||
result.viewport.SetCamera(&result.camera)
|
||||
result.Camera = Camera{}
|
||||
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
|
||||
@ -91,14 +95,19 @@ func (mr *MapRenderer) Render(target d2interface.Surface) {
|
||||
mr.renderPass4(target, startX, startY, endX, endY)
|
||||
}
|
||||
|
||||
// MoveCameraTo sets the position of the camera to the given x and y coordinates.
|
||||
func (mr *MapRenderer) MoveCameraTo(x, y float64) {
|
||||
mr.camera.MoveTo(x, y)
|
||||
// MoveCameraTo sets the position of the Camera to the given x and y coordinates.
|
||||
func (mr *MapRenderer) MoveCameraTo(position *d2vector.Position) {
|
||||
mr.Camera.MoveTo(position)
|
||||
}
|
||||
|
||||
// MoveCameraBy adds the given vector to the current position of the camera.
|
||||
func (mr *MapRenderer) MoveCameraBy(x, y float64) {
|
||||
mr.camera.MoveBy(x, y)
|
||||
// MoveCameraBy adds the given vector to the current position of the Camera.
|
||||
func (mr *MapRenderer) MoveCameraBy(vector *d2vector.Vector) {
|
||||
mr.Camera.MoveBy(vector)
|
||||
}
|
||||
|
||||
// MoveCameraTargetBy adds the given vector to the current position of the Camera.
|
||||
func (mr *MapRenderer) MoveCameraTargetBy(vector *d2vector.Vector) {
|
||||
mr.Camera.MoveTargetBy(vector)
|
||||
}
|
||||
|
||||
// ScreenToWorld returns the world position for the given screen (pixel) position.
|
||||
@ -387,6 +396,8 @@ func (mr *MapRenderer) Advance(elapsed float64) {
|
||||
if mr.currentFrame > 9 {
|
||||
mr.currentFrame = 0
|
||||
}
|
||||
|
||||
mr.Camera.Advance(elapsed)
|
||||
}
|
||||
|
||||
func loadPaletteForAct(levelType d2enum.RegionIdType) (d2interface.Palette, error) {
|
||||
@ -429,3 +440,8 @@ func (mr *MapRenderer) ViewportToRight() {
|
||||
func (mr *MapRenderer) ViewportDefault() {
|
||||
mr.viewport.resetAlign()
|
||||
}
|
||||
|
||||
// SetCameraTarget sts the Camera target
|
||||
func (mr *MapRenderer) SetCameraTarget(position *d2vector.Position) {
|
||||
mr.Camera.SetTarget(position)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ const (
|
||||
right = 2
|
||||
)
|
||||
|
||||
// Viewport is used for converting vectors between screen (pixel), orthogonal (camera) and world (isometric) space.
|
||||
// Viewport is used for converting vectors between screen (pixel), orthogonal (Camera) and world (isometric) space.
|
||||
// TODO: Has a coordinate (issue #456)
|
||||
type Viewport struct {
|
||||
defaultScreenRect d2common.Rectangle
|
||||
@ -46,7 +46,7 @@ func NewViewport(x, y, width, height int) *Viewport {
|
||||
}
|
||||
}
|
||||
|
||||
// SetCamera sets the current camera to the given value.
|
||||
// SetCamera sets the current Camera to the given value.
|
||||
func (v *Viewport) SetCamera(camera *Camera) {
|
||||
v.camera = camera
|
||||
}
|
||||
@ -178,7 +178,8 @@ func (v *Viewport) PopTranslation() {
|
||||
func (v *Viewport) getCameraOffset() (float64, float64) {
|
||||
var camX, camY float64
|
||||
if v.camera != nil {
|
||||
camX, camY = v.camera.GetPosition()
|
||||
camPosition := v.camera.GetPosition()
|
||||
camX, camY = camPosition.X(), camPosition.Y()
|
||||
}
|
||||
|
||||
camX -= float64(v.screenRect.Width / 2)
|
||||
|
@ -2,6 +2,7 @@ package d2gamescreen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
@ -114,18 +115,18 @@ func (v *Game) Render(screen d2interface.Surface) error {
|
||||
}
|
||||
|
||||
// Advance runs the update logic on the Gameplay screen
|
||||
func (v *Game) Advance(tickTime float64) error {
|
||||
func (v *Game) Advance(elapsed float64) error {
|
||||
if (v.escapeMenu != nil && !v.escapeMenu.isOpen) || len(v.gameClient.Players) != 1 {
|
||||
v.gameClient.MapEngine.Advance(tickTime) // TODO: Hack
|
||||
v.gameClient.MapEngine.Advance(elapsed) // TODO: Hack
|
||||
}
|
||||
|
||||
if v.gameControls != nil {
|
||||
if err := v.gameControls.Advance(tickTime); err != nil {
|
||||
if err := v.gameControls.Advance(elapsed); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
v.ticksSinceLevelCheck += tickTime
|
||||
v.ticksSinceLevelCheck += elapsed
|
||||
if v.ticksSinceLevelCheck > 1.0 {
|
||||
v.ticksSinceLevelCheck = 0
|
||||
if v.localPlayer != nil {
|
||||
@ -160,7 +161,8 @@ func (v *Game) Advance(tickTime float64) error {
|
||||
if v.localPlayer != nil && !v.gameControls.FreeCam {
|
||||
worldPosition := v.localPlayer.Position.World()
|
||||
rx, ry := v.mapRenderer.WorldToOrtho(worldPosition.X(), worldPosition.Y())
|
||||
v.mapRenderer.MoveCameraTo(rx, ry)
|
||||
position := d2vector.NewPosition(rx, ry)
|
||||
v.mapRenderer.SetCameraTarget(&position)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -2,6 +2,7 @@ package d2gamescreen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
@ -167,7 +168,8 @@ func (met *MapEngineTest) loadRegionByIndex(n, levelPreset, fileIndex int) {
|
||||
}
|
||||
|
||||
met.mapRenderer.SetMapEngine(met.mapEngine)
|
||||
met.mapRenderer.MoveCameraTo(met.mapRenderer.WorldToOrtho(met.mapEngine.GetCenterPosition()))
|
||||
position := d2vector.NewPosition(met.mapRenderer.WorldToOrtho(met.mapEngine.GetCenterPosition()))
|
||||
met.mapRenderer.SetCameraTarget(&position)
|
||||
}
|
||||
|
||||
// OnLoad loads the resources for the Map Engine Test screen
|
||||
@ -317,6 +319,14 @@ func (met *MapEngineTest) OnMouseButtonDown(event d2interface.MouseEvent) bool {
|
||||
met.selY = int(py)
|
||||
met.selectedTile = met.mapEngine.TileAt(int(px), int(py))
|
||||
|
||||
camVect := met.mapRenderer.Camera.GetPosition().Vector
|
||||
|
||||
x, y := float64(met.lastMouseX-400)/5, float64(met.lastMouseY-300)/5
|
||||
targetPosition := d2vector.NewPositionTile(x, y)
|
||||
targetPosition.Add(&camVect)
|
||||
|
||||
met.mapRenderer.SetCameraTarget(&targetPosition)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@ -329,6 +339,27 @@ func (met *MapEngineTest) OnMouseButtonDown(event d2interface.MouseEvent) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (met *MapEngineTest) OnMouseButtonRepeat(event d2interface.MouseEvent) bool {
|
||||
if event.Button() == d2enum.MouseButtonLeft {
|
||||
px, py := met.mapRenderer.ScreenToWorld(met.lastMouseX, met.lastMouseY)
|
||||
met.selX = int(px)
|
||||
met.selY = int(py)
|
||||
met.selectedTile = met.mapEngine.TileAt(int(px), int(py))
|
||||
|
||||
camVect := met.mapRenderer.Camera.GetPosition().Vector
|
||||
|
||||
x, y := float64(met.lastMouseX-400)/5, float64(met.lastMouseY-300)/5
|
||||
targetPosition := d2vector.NewPositionTile(x, y)
|
||||
targetPosition.Add(&camVect)
|
||||
|
||||
met.mapRenderer.SetCameraTarget(&targetPosition)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Advance runs the update logic on the Map Engine Test screen
|
||||
func (met *MapEngineTest) Advance(tickTime float64) error {
|
||||
met.mapEngine.Advance(tickTime)
|
||||
@ -345,22 +376,30 @@ func (met *MapEngineTest) OnKeyRepeat(event d2interface.KeyEvent) bool {
|
||||
}
|
||||
|
||||
if event.Key() == d2enum.KeyDown {
|
||||
met.mapRenderer.MoveCameraBy(0, moveSpeed)
|
||||
v := d2vector.NewVector(0, moveSpeed)
|
||||
met.mapRenderer.MoveCameraTargetBy(&v)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if event.Key() == d2enum.KeyUp {
|
||||
met.mapRenderer.MoveCameraBy(0, -moveSpeed)
|
||||
v := d2vector.NewVector(0, -moveSpeed)
|
||||
met.mapRenderer.MoveCameraTargetBy(&v)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if event.Key() == d2enum.KeyRight {
|
||||
met.mapRenderer.MoveCameraBy(moveSpeed, 0)
|
||||
v := d2vector.NewVector(moveSpeed, 0)
|
||||
met.mapRenderer.MoveCameraTargetBy(&v)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if event.Key() == d2enum.KeyLeft {
|
||||
met.mapRenderer.MoveCameraBy(-moveSpeed, 0)
|
||||
v := d2vector.NewVector(-moveSpeed, 0)
|
||||
met.mapRenderer.MoveCameraTargetBy(&v)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package d2player
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||
"image"
|
||||
"image/color"
|
||||
@ -157,22 +158,30 @@ func (g *GameControls) OnKeyRepeat(event d2interface.KeyEvent) bool {
|
||||
}
|
||||
|
||||
if event.Key() == d2enum.KeyDown {
|
||||
g.mapRenderer.MoveCameraBy(0, moveSpeed)
|
||||
v := d2vector.NewVector(0, moveSpeed)
|
||||
g.mapRenderer.MoveCameraTargetBy(&v)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if event.Key() == d2enum.KeyUp {
|
||||
g.mapRenderer.MoveCameraBy(0, -moveSpeed)
|
||||
v := d2vector.NewVector(0, -moveSpeed)
|
||||
g.mapRenderer.MoveCameraTargetBy(&v)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if event.Key() == d2enum.KeyRight {
|
||||
g.mapRenderer.MoveCameraBy(moveSpeed, 0)
|
||||
v := d2vector.NewVector(moveSpeed, 0)
|
||||
g.mapRenderer.MoveCameraTargetBy(&v)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if event.Key() == d2enum.KeyLeft {
|
||||
g.mapRenderer.MoveCameraBy(-moveSpeed, 0)
|
||||
v := d2vector.NewVector(-moveSpeed, 0)
|
||||
g.mapRenderer.MoveCameraTargetBy(&v)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -225,6 +234,21 @@ func (g *GameControls) OnMouseButtonRepeat(event d2interface.MouseEvent) bool {
|
||||
if isLeft && shouldDoLeft && inRect {
|
||||
lastLeftBtnActionTime = now
|
||||
g.inputListener.OnPlayerMove(px, py)
|
||||
|
||||
if g.FreeCam {
|
||||
if event.Button() == d2enum.MouseButtonLeft {
|
||||
camVect := g.mapRenderer.Camera.GetPosition().Vector
|
||||
|
||||
x, y := float64(g.lastMouseX-400)/5, float64(g.lastMouseY-300)/5
|
||||
targetPosition := d2vector.NewPositionTile(x, y)
|
||||
targetPosition.Add(&camVect)
|
||||
|
||||
g.mapRenderer.SetCameraTarget(&targetPosition)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@ -323,6 +347,7 @@ func (g *GameControls) onToggleRunButton() {
|
||||
|
||||
// ScreenAdvanceHandler
|
||||
func (g *GameControls) Advance(elapsed float64) error {
|
||||
g.mapRenderer.Advance(elapsed)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user