Vendor libs/hump, sfxrlua, json4lua, narrator as real files
These were committed as empty submodule gitlinks with no .gitmodules, so the folders were never populated and the game could not load (require of libs/hump/timer, libs/sfxrlua/sfxr, narrator.narrator). Checked out each at its pinned commit and vendored the files, matching the existing bundled-libs convention. Removed the junk libs/libs/ tree. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e73f63b5d4
commit
03532d29e4
219 changed files with 20254 additions and 252 deletions
567
libs/hump/docs/camera.rst
Normal file
567
libs/hump/docs/camera.rst
Normal file
|
|
@ -0,0 +1,567 @@
|
|||
hump.camera
|
||||
===========
|
||||
|
||||
::
|
||||
|
||||
Camera = require "hump.camera"
|
||||
|
||||
A camera utility for LÖVE. A camera can "look" at a position. It can zoom in
|
||||
and out and it can rotate it's view. In the background, this is done by
|
||||
actually moving, scaling and rotating everything in the game world. But don't
|
||||
worry about that.
|
||||
|
||||
**Example**::
|
||||
|
||||
function love.load()
|
||||
camera = Camera(player.pos.x, player.pos.y)
|
||||
end
|
||||
|
||||
function love.update(dt)
|
||||
local dx,dy = player.x - camera.x, player.y - camera.y
|
||||
camera:move(dx/2, dy/2)
|
||||
end
|
||||
|
||||
function love.draw()
|
||||
camera:attach()
|
||||
-- do your drawing here
|
||||
camera:detach()
|
||||
end
|
||||
|
||||
List of Functions
|
||||
-----------------
|
||||
|
||||
* :func:`Camera.new(x,y, zoom, rot) <Camera.new>`
|
||||
* :func:`camera:move(dx,dy) <camera:move>`
|
||||
* :func:`camera:lookAt(x,y) <camera:lookAt>`
|
||||
* :func:`camera:position() <camera:position>`
|
||||
* :func:`camera:rotate(angle) <camera:rotate>`
|
||||
* :func:`camera:rotateTo(angle) <camera:rotateTo>`
|
||||
* :func:`camera:zoom(mul) <camera:zoom>`
|
||||
* :func:`camera:zoomTo(zoom) <camera:zoomTo>`
|
||||
* :func:`camera:attach() <camera:attach>`
|
||||
* :func:`camera:detach() <camera:detach>`
|
||||
* :func:`camera:draw(func) <camera:draw>`
|
||||
* :func:`camera:worldCoords(x, y) <camera:worldCoords>`
|
||||
* :func:`camera:cameraCoords(x, y) <camera:cameraCoords>`
|
||||
* :func:`camera:mousePosition() <camera:mousePosition>`
|
||||
* :func:`camera:lockX(x, smoother, ...) <camera:lockX>`
|
||||
* :func:`camera:lockY(y, smoother, ...) <camera:lockY>`
|
||||
* :func:`camera:lockPosition(x,y, smoother, ...) <camera:lockPosition>`
|
||||
* :func:`camera:lockWindow(x,y, x_min, x_max, y_min, y_max, smoother, ...) <camera:lockWindow>`
|
||||
* :func:`Camera.smooth.none() <Camera.smooth.none>`
|
||||
* :func:`Camera.smooth.linear(speed) <Camera.smooth.linear>`
|
||||
* :func:`Camera.smooth.damped(stiffness) <Camera.smooth.damped>`
|
||||
|
||||
Function Reference
|
||||
------------------
|
||||
|
||||
.. function:: Camera.new(x,y, zoom, rot)
|
||||
|
||||
:param numbers x,y: Point for the camera to look at. (optional)
|
||||
:param number zoom: Camera zoom. (optional)
|
||||
:param number rot: Camera rotation in radians. (optional)
|
||||
:returns: A new camera.
|
||||
|
||||
|
||||
Creates a new camera. You can access the camera position using ``camera.x,
|
||||
camera.y``, the zoom using ``camera.scale`` and the rotation using ``camera.rot``.
|
||||
|
||||
The module variable name can be used at a shortcut to ``new()``.
|
||||
|
||||
**Example**::
|
||||
|
||||
camera = require 'hump.camera'
|
||||
-- camera looking at (100,100) with zoom 2 and rotated by 45 degrees
|
||||
cam = camera(100,100, 2, math.pi/2)
|
||||
|
||||
|
||||
.. function:: camera:move(dx,dy)
|
||||
|
||||
:param numbers dx,dy: Direction to move the camera.
|
||||
:returns: The camera.
|
||||
|
||||
|
||||
Move the camera *by* some vector. To set the position, use
|
||||
:func:`camera:lookAt`.
|
||||
|
||||
This function is shortcut to ``camera.x,camera.y = camera.x+dx, camera.y+dy``.
|
||||
|
||||
**Examples**::
|
||||
|
||||
function love.update(dt)
|
||||
camera:move(dt * 5, dt * 6)
|
||||
end
|
||||
|
||||
::
|
||||
|
||||
function love.update(dt)
|
||||
camera:move(dt * 5, dt * 6):rotate(dt)
|
||||
end
|
||||
|
||||
|
||||
.. function:: camera:lookAt(x,y)
|
||||
|
||||
:param numbers x,y: Position to look at.
|
||||
:returns: The camera.
|
||||
|
||||
|
||||
Let the camera look at a point. In other words, it sets the camera position. To
|
||||
move the camera *by* some amount, use :func:`camera:move`.
|
||||
|
||||
This function is shortcut to ``camera.x,camera.y = x, y``.
|
||||
|
||||
**Examples**::
|
||||
|
||||
function love.update(dt)
|
||||
camera:lookAt(player.pos:unpack())
|
||||
end
|
||||
|
||||
::
|
||||
|
||||
function love.update(dt)
|
||||
camera:lookAt(player.pos:unpack()):rotate(player.rot)
|
||||
end
|
||||
|
||||
.. function:: camera:position()
|
||||
|
||||
:returns: ``x,y`` -- Camera position.
|
||||
|
||||
|
||||
Returns ``camera.x, camera.y``.
|
||||
|
||||
**Example**::
|
||||
|
||||
-- let the camera fly!
|
||||
local cam_dx, cam_dy = 0, 0
|
||||
|
||||
function love.mousereleased(x,y)
|
||||
local cx,cy = camera:position()
|
||||
dx, dy = x-cx, y-cy
|
||||
end
|
||||
|
||||
function love.update(dt)
|
||||
camera:move(dx * dt, dy * dt)
|
||||
end
|
||||
|
||||
|
||||
.. function:: camera:rotate(angle)
|
||||
|
||||
:param number angle: Rotation angle in radians
|
||||
:returns: The camera.
|
||||
|
||||
|
||||
Rotate the camera by some angle. To set the angle use :func:`camera:rotateTo`.
|
||||
|
||||
This function is shortcut to ``camera.rot = camera.rot + angle``.
|
||||
|
||||
**Examples**::
|
||||
|
||||
function love.update(dt)
|
||||
camera:rotate(dt)
|
||||
end
|
||||
|
||||
::
|
||||
|
||||
function love.update(dt)
|
||||
camera:rotate(dt):move(dt,dt)
|
||||
end
|
||||
|
||||
|
||||
.. function:: camera:rotateTo(angle)
|
||||
|
||||
:param number angle: Rotation angle in radians
|
||||
:returns: The camera.
|
||||
|
||||
Set rotation: ``camera.rot = angle``.
|
||||
|
||||
**Example**::
|
||||
|
||||
camera:rotateTo(math.pi/2)
|
||||
|
||||
|
||||
.. function:: camera:zoom(mul)
|
||||
|
||||
:param number mul: Zoom change. Should be > 0.
|
||||
:returns: The camera.
|
||||
|
||||
|
||||
*Multiply* zoom: ``camera.scale = camera.scale * mul``.
|
||||
|
||||
**Examples**::
|
||||
|
||||
camera:zoom(2) -- make everything twice as big
|
||||
|
||||
::
|
||||
|
||||
camera:zoom(0.5) -- ... and back to normal
|
||||
|
||||
::
|
||||
|
||||
camera:zoom(-1) -- mirror and flip everything upside down
|
||||
|
||||
|
||||
.. function:: camera:zoomTo(zoom)
|
||||
|
||||
:param number zoom: New zoom.
|
||||
:returns: The camera.
|
||||
|
||||
|
||||
Set zoom: ``camera.scale = zoom``.
|
||||
|
||||
**Example**::
|
||||
|
||||
camera:zoomTo(1) -- reset zoom
|
||||
|
||||
|
||||
.. function:: camera:attach()
|
||||
|
||||
Start looking through the camera.
|
||||
|
||||
Apply camera transformations, i.e. move, scale and rotate everything until
|
||||
``camera:detach()`` as if looking through the camera.
|
||||
|
||||
**Example**::
|
||||
|
||||
function love.draw()
|
||||
camera:attach()
|
||||
draw_world()
|
||||
camera:detach()
|
||||
|
||||
draw_hud()
|
||||
end
|
||||
|
||||
|
||||
.. function:: camera:detach()
|
||||
|
||||
Stop looking through the camera.
|
||||
|
||||
**Example**::
|
||||
|
||||
function love.draw()
|
||||
camera:attach()
|
||||
draw_world()
|
||||
camera:detach()
|
||||
|
||||
draw_hud()
|
||||
end
|
||||
|
||||
|
||||
.. function:: camera:draw(func)
|
||||
|
||||
:param function func: Drawing function to be wrapped.
|
||||
|
||||
Wrap a function between a ``camera:attach()``/``camera:detach()`` pair.
|
||||
Equivalent to::
|
||||
|
||||
camera:attach()
|
||||
func()
|
||||
camera:detach()
|
||||
|
||||
|
||||
**Example**::
|
||||
|
||||
function love.draw()
|
||||
camera:draw(draw_world)
|
||||
draw_hud()
|
||||
end
|
||||
|
||||
|
||||
.. function:: camera:worldCoords(x, y)
|
||||
|
||||
:param numbers x, y: Point to transform.
|
||||
:returns: ``x,y`` -- Transformed point.
|
||||
|
||||
Because a camera has a point it looks at, a rotation and a zoom factor, it
|
||||
defines a coordinate system. A point now has two sets of coordinates: One
|
||||
defines where the point is to be found in the game world, and the other
|
||||
describes the position on the computer screen. The first set of coordinates is
|
||||
called world coordinates, the second one camera coordinates. Sometimes it is
|
||||
needed to convert between the two coordinate systems, for example to get the
|
||||
position of a mouse click in the game world in a strategy game, or to see if an
|
||||
object is visible on the screen.
|
||||
|
||||
:func:`camera:worldCoords` and :func:`camera:cameraCoords` transform points
|
||||
between these two coordinate systems.
|
||||
|
||||
**Example**::
|
||||
|
||||
x,y = camera:worldCoords(love.mouse.getPosition())
|
||||
selectedUnit:plotPath(x,y)
|
||||
|
||||
|
||||
.. function:: camera:cameraCoords(x, y)
|
||||
|
||||
:param numbers x, y: Point to transform.
|
||||
:returns: ``x,y`` -- Transformed point.
|
||||
|
||||
|
||||
Because a camera has a point it looks at, a rotation and a zoom factor, it
|
||||
defines a coordinate system. A point now has two sets of coordinates: One
|
||||
defines where the point is to be found in the game world, and the other
|
||||
describes the position on the computer screen. The first set of coordinates is
|
||||
called world coordinates, the second one camera coordinates. Sometimes it is
|
||||
needed to convert between the two coordinate systems, for example to get the
|
||||
position of a mouse click in the game world in a strategy game, or to see if an
|
||||
object is visible on the screen.
|
||||
|
||||
:func:`camera:worldCoords` and :func:`camera:cameraCoords` transform points
|
||||
between these two coordinate systems.
|
||||
|
||||
**Example**::
|
||||
|
||||
x,y = camera:cameraCoords(player.pos.x, player.pos.y)
|
||||
love.graphics.line(x, y, love.mouse.getPosition())
|
||||
|
||||
|
||||
.. function:: camera:mousePosition()
|
||||
|
||||
:returns: Mouse position in world coordinates.
|
||||
|
||||
|
||||
Shortcut to ``camera:worldCoords(love.mouse.getPosition())``.
|
||||
|
||||
**Example**::
|
||||
|
||||
x,y = camera:mousePosition()
|
||||
selectedUnit:plotPath(x,y)
|
||||
|
||||
|
||||
Camera Movement Control
|
||||
-----------------------
|
||||
|
||||
Camera movement is one of these things that go almost unnoticed when done well,
|
||||
but add a lot to the overall experience.
|
||||
The article `Scroll Back: The Theory and Practice of Cameras in SideScrollers
|
||||
<http://gamasutra.com/blogs/ItayKeren/20150511/243083/Scroll_Back_The_Theory_and_Practice_of_Cameras_in_SideScrollers.php>`_
|
||||
by Itay Keren gives a lot of insight into how to design good camera systems.
|
||||
|
||||
**hump.camera** offers functions that help to implement most of the techniques
|
||||
discussed in the article. The functions :func:`camera:lockX`,
|
||||
:func:`camera:lockY`, :func:`camera:lockPosition`, and :func:`camera:lockWindow`
|
||||
move the camera so that the interesting content stays in frame.
|
||||
Note that the functions must be called every frame::
|
||||
|
||||
function love.update()
|
||||
-- vertical locking
|
||||
camera:lockX(player.pos.x)
|
||||
end
|
||||
|
||||
|
||||
All movements are subject to smoothing (see :ref:`Movement Smoothers
|
||||
<movement-smoothers>`).
|
||||
You can specify a default movement smoother by assigning the variable
|
||||
:attr:`camera.smoother`::
|
||||
|
||||
cam.smoother = Camera.smooth.linear(100)
|
||||
|
||||
|
||||
|
||||
.. function:: camera:lockX(x, smoother, ...)
|
||||
|
||||
:param number x: X coordinate (in world coordinates) to lock to.
|
||||
:param function smoother: Movement smoothing override. (optional)
|
||||
:param mixed ...: Additional parameters to the smoothing function. (optional)
|
||||
|
||||
Horizontal camera locking: Keep the camera locked on the defined ``x``-position
|
||||
(in *world coordinates*). The ``y``-position is not affected.
|
||||
|
||||
You can define an off-center locking position by "aiming" the camera left or
|
||||
right of your actual target. For example, to center the player 20 pixels to the
|
||||
*left* of the screen, aim 20 pixels to it's *right* (see examples).
|
||||
|
||||
**Examples**::
|
||||
|
||||
-- lock on player vertically
|
||||
camera:lockX(player.x)
|
||||
|
||||
::
|
||||
|
||||
-- ... with linear smoothing at 25 px/s
|
||||
camera:lockX(player.x, Camera.smooth.linear(25))
|
||||
|
||||
::
|
||||
|
||||
-- lock player 20px left of center
|
||||
camera:lockX(player.x + 20)
|
||||
|
||||
|
||||
|
||||
.. function:: camera:lockY(y, smoother, ...)
|
||||
|
||||
:param number y: Y coordinate (in world coordinates) to lock to.
|
||||
:param function smoother: Movement smoothing override. (optional)
|
||||
:param mixed ...: Additional parameters to the smoothing function. (optional)
|
||||
|
||||
Vertical camera locking: Keep the camera locked on the defined ``y``-position
|
||||
(in *world coordinates*). The ``x``-position is not affected.
|
||||
|
||||
You can define an off-center locking position by "aiming" the camera above or
|
||||
below your actual target. For example, to center the player 20 pixels *below* the
|
||||
screen center, aim 20 pixels *above* it (see examples).
|
||||
|
||||
**Examples**::
|
||||
|
||||
-- lock on player horizontally
|
||||
camera:lockY(player.y)
|
||||
|
||||
::
|
||||
|
||||
-- ... with damped smoothing with a stiffness of 10
|
||||
camera:lockY(player.y, Camera.smooth.damped(10))
|
||||
|
||||
::
|
||||
|
||||
-- lock player 20px below the screen center
|
||||
camera:lockY(player.y - 20)
|
||||
|
||||
|
||||
|
||||
.. function:: camera:lockPosition(x,y, smoother, ...)
|
||||
|
||||
:param numbers x,y: Position (in world coordinates) to lock to.
|
||||
:param function smoother: Movement smoothing override. (optional)
|
||||
:param mixed ...: Additional parameters to the smoothing function. (optional)
|
||||
|
||||
Horizontal and vertical camera locking: Keep the camera locked on the defined
|
||||
position (in *world coordinates*).
|
||||
|
||||
You can define an off-center locking position by "aiming" the camera to the
|
||||
opposite direction away from your real target.
|
||||
For example, to center the player 10 pixels to the *left* and 20 pixels *above*
|
||||
the screen center, aim 10 pixels to the *right* and 20 pixels *below*.
|
||||
|
||||
**Examples**::
|
||||
|
||||
-- lock on player
|
||||
camera:lockPosition(player.x, player.y)
|
||||
|
||||
::
|
||||
|
||||
-- lock 50 pixels into player's aiming direction
|
||||
camera:lockPosition(player.x - player.aiming.x * 50, player.y - player.aiming.y * 50)
|
||||
|
||||
|
||||
|
||||
.. function:: camera:lockWindow(x,y, x_min, x_max, y_min, y_max, smoother, ...)
|
||||
|
||||
:param numbers x,y: Position (in world coordinates) to lock to.
|
||||
:param numbers x_min: Upper left X coordinate of the camera window *(in camera coordinates!)*.
|
||||
:param numbers x_max: Lower right X coordinate of the camera window *(in camera coordinates!)*.
|
||||
:param numbers y_min: Upper left Y coordinate of the camera window *(in camera coordinates!)*.
|
||||
:param numbers y_max: Lower right Y coordinate of the camera window *(in camera coordinates!)*.
|
||||
:param function smoother: Movement smoothing override. (optional)
|
||||
:param mixed ...: Additional parameters to the smoothing function. (optional)
|
||||
|
||||
The most powerful locking method: Lock camera to ``x,y``, but only move the
|
||||
camera if the position would be out of the screen-rectangle defined by ``x_min``,
|
||||
``x_max``, ``y_min``, ``y_max``.
|
||||
|
||||
.. note::
|
||||
The locking window is defined in camera coordinates, whereas the position to
|
||||
lock to is defined in world coordinates!
|
||||
|
||||
All of the other locking methods can be implemented by window locking. For
|
||||
position locking, set ``x_min = x_max`` and ``y_min = y_max``.
|
||||
Off-center locking can be done by defining the locking window accordingly.
|
||||
|
||||
**Examples**::
|
||||
|
||||
-- lock on player
|
||||
camera:lock(player.x, player.y)
|
||||
|
||||
.. attribute:: camera.smoother
|
||||
|
||||
The default smoothing operator. Must be a ``function`` with the following
|
||||
prototype::
|
||||
|
||||
function customSmoother(dx,dy, ...)
|
||||
do_stuff()
|
||||
return new_dx,new_dy
|
||||
end
|
||||
|
||||
where ``dx,dy`` is the offset the camera would move before smoothing and
|
||||
``new_dx, new_dy`` is the offset the camera should move after smoothing.
|
||||
|
||||
|
||||
.. _movement-smoothers:
|
||||
|
||||
Movement Smoothers
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
It is not always desirable that the camera instantly locks on a target.
|
||||
`Platform snapping
|
||||
<http://gamasutra.com/blogs/ItayKeren/20150511/243083/Scroll_Back_The_Theory_and_Practice_of_Cameras_in_SideScrollers.php#h.rncuomopycy0>`_,
|
||||
for example, would look terrible if the camera would instantly jump to the
|
||||
focussed platform.
|
||||
Smoothly moving the camera to the locked position can also give the illusion of
|
||||
a camera operator an add to the overall feel of your game.
|
||||
|
||||
**hump.camera** allows to smooth the movement by either passing movement
|
||||
smoother functions to the locking functions or by setting a default smoother
|
||||
(see :attr:`camera.smoother`).
|
||||
|
||||
Smoothing functions must have the following prototype::
|
||||
|
||||
function customSmoother(dx,dy, ...)
|
||||
do_stuff()
|
||||
return new_dx,new_dy
|
||||
end
|
||||
|
||||
where ``dx,dy`` is the offset the camera would move before smoothing and
|
||||
``new_dx, new_dy`` is the offset the camera should move after smoothing.
|
||||
|
||||
This is a simple "rubber-band" smoother::
|
||||
|
||||
function rubber_band(dx,dy)
|
||||
local dt = love.timer.getDelta()
|
||||
return dx*dt, dy*dt
|
||||
end
|
||||
|
||||
**hump.camera** defines generators for the most common smoothers:
|
||||
|
||||
.. function:: Camera.smooth.none()
|
||||
|
||||
:returns: Smoothing function.
|
||||
|
||||
Dummy smoother: does not smooth the motion.
|
||||
|
||||
**Example**::
|
||||
|
||||
cam.smoother = Camera.smooth.none()
|
||||
|
||||
|
||||
.. function:: Camera.smooth.linear(speed)
|
||||
|
||||
:param number speed: Smoothing speed.
|
||||
:returns: Smoothing function.
|
||||
|
||||
Smoothly moves the camera towards to snapping goal with constant speed.
|
||||
|
||||
**Examples**::
|
||||
|
||||
cam.smoother = Camera.smooth.linear(100)
|
||||
|
||||
::
|
||||
|
||||
-- warning: creates a function every frame!
|
||||
camera:lockX(player.x, Camera.smooth.linear(25))
|
||||
|
||||
|
||||
.. function:: Camera.smooth.damped(stiffness)
|
||||
|
||||
:param number stiffness: Speed of the camera movement.
|
||||
:returns: Smoothing function.
|
||||
|
||||
Smoothly moves the camera towards the goal with a speed proportional to the
|
||||
distance to the target.
|
||||
Stiffness defines the speed of the motion: Higher values mean that the camera
|
||||
moves more quickly.
|
||||
|
||||
**Examples**::
|
||||
|
||||
cam.smoother = Camera.smooth.damped(10)
|
||||
|
||||
::
|
||||
|
||||
-- warning: creates a function every frame!
|
||||
camera:lockPosition(player.x, player.y, Camera.smooth.damped(2))
|
||||
Loading…
Add table
Add a link
Reference in a new issue