All Downloads are FREE. Search and download functionalities are using the official Maven repository.

indigo.shared.scenegraph.Camera.scala Maven / Gradle / Ivy

The newest version!
package indigo.shared.scenegraph

import indigo.shared.config.GameViewport
import indigo.shared.datatypes.Point
import indigo.shared.datatypes.Radians
import indigo.shared.datatypes.Rectangle
import indigo.shared.datatypes.Size

/** Parent type of camera instances. Cameras are used to look around your games graphics / levels / scenes.
  */
sealed trait Camera:
  def position: Point
  def topLeft(viewport: GameViewport): Point
  def topLeft(viewport: Size): Point
  def bounds(viewport: GameViewport): Rectangle
  def bounds(viewport: Size): Rectangle
  def frustum(viewport: GameViewport): Rectangle = bounds(viewport)
  def frustum(viewport: Size): Rectangle         = bounds(viewport)
  def zoom: Zoom
  def rotation: Radians
  def isLookAt: Boolean
  def withZoom(newZoom: Zoom): Camera
  def rotateTo(angle: Radians): Camera
  def rotateBy(angle: Radians): Camera
  def withRotation(newRotation: Radians): Camera

object Camera:

  /** Indigo's default camera is fixed. It starts at position 0,0 and shows you everything down and right from there
    * until it runs out of screen. Fixed cameras are useful for replicating the behaviour of Indigos normal windowing
    * while controlling the position, zoom and rotation.
    */
  final case class Fixed(position: Point, zoom: Zoom, rotation: Radians) extends Camera:
    def topLeft(viewport: GameViewport): Point    = position
    def topLeft(viewport: Size): Point            = position
    def bounds(viewport: GameViewport): Rectangle = Rectangle(position, viewport.size)
    def bounds(viewport: Size): Rectangle         = Rectangle(position, viewport)
    val isLookAt: Boolean                         = false

    def withX(newX: Int): Fixed =
      this.copy(position = position.withX(newX))
    def withY(newY: Int): Fixed =
      this.copy(position = position.withY(newY))

    def moveTo(newPosition: Point): Fixed =
      this.copy(position = newPosition)
    def moveTo(x: Int, y: Int): Fixed =
      moveTo(Point(x, y))

    def moveBy(amount: Point): Fixed =
      this.copy(position = position + amount)
    def moveBy(x: Int, y: Int): Fixed =
      moveBy(Point(x, y))

    def withZoom(newZoom: Zoom): Fixed =
      this.copy(zoom = newZoom)

    def rotateTo(angle: Radians): Fixed =
      this.copy(rotation = angle)
    def rotateBy(angle: Radians): Fixed =
      rotateTo(rotation + angle)
    def withRotation(newRotation: Radians): Fixed =
      rotateTo(newRotation)

    def toLookAt: LookAt =
      LookAt(position, zoom, rotation)

  object Fixed:
    def apply(position: Point): Fixed =
      Fixed(position, Zoom.x1, Radians.zero)

    def apply(position: Point, zoom: Zoom): Fixed =
      Fixed(position, zoom, Radians.zero)

  /** LookAt cameras center the screen on whatever position they are looking at. Useful for following a players
    * character, for example.
    */
  final case class LookAt(target: Point, zoom: Zoom, rotation: Radians) extends Camera:
    val isLookAt: Boolean = true
    val position: Point   = target
    def topLeft(viewport: GameViewport): Point =
      topLeft(viewport.size)
    def topLeft(viewport: Size): Point =
      target - (viewport.toPoint / 2) / zoom.toDouble.toInt
    def bounds(viewport: GameViewport): Rectangle =
      bounds(viewport.size)
    def bounds(viewport: Size): Rectangle =
      Rectangle(topLeft(viewport), viewport)

    def withTarget(newTarget: Point): LookAt =
      this.copy(target = newTarget)
    def lookAt(newTarget: Point): LookAt =
      withTarget(newTarget)

    def withZoom(newZoom: Zoom): LookAt =
      this.copy(zoom = newZoom)

    def rotateTo(angle: Radians): LookAt =
      this.copy(rotation = angle)
    def rotateBy(angle: Radians): LookAt =
      rotateTo(rotation + angle)
    def withRotation(newRotation: Radians): LookAt =
      rotateTo(newRotation)

    def toFixed: Fixed =
      Fixed(position, zoom, rotation)

  object LookAt:
    def apply(target: Point): LookAt =
      LookAt(target, Zoom.x1, Radians.zero)

    def apply(target: Point, zoom: Zoom): LookAt =
      LookAt(target, zoom, Radians.zero)

  def default: Fixed =
    Fixed(Point.zero, Zoom.x1, Radians.zero)

  given CanEqual[Fixed, Fixed]                   = CanEqual.derived
  given CanEqual[LookAt, LookAt]                 = CanEqual.derived
  given CanEqual[Option[Camera], Option[Camera]] = CanEqual.derived

/** Zoom your camera in and out! Behaves like physical camera's zoom, so x2 means "make everything twice as big". Unlike
  * a real camera, you can zoom in or our infinitely!
  */
opaque type Zoom = Double
object Zoom:
  inline def apply(amount: Double): Zoom = amount

  val x025: Zoom = Zoom(0.25)
  val x05: Zoom  = Zoom(0.5)
  val x1: Zoom   = Zoom(1.0)
  val x2: Zoom   = Zoom(2.0)
  val x3: Zoom   = Zoom(3.0)
  val x4: Zoom   = Zoom(4.0)

  extension (z: Zoom) def toDouble: Double = z




© 2015 - 2024 Weber Informatics LLC | Privacy Policy