Scrolling is accomplished by moving the camera on the XY plane and zooming by moving it on the Z axis.
This method has distinct implementations per platform. On desktop computers, the mouse wheel changes the zoom level, and holding down the middle mouse button scrolls the camera. On Android, a two finger pinch and slide gesture zoom and scroll.
Returns true
if the event is used.
Should be called from App::accept_event
before accepting pointer events:
redef class App
redef fun accept_event(event)
do
if world_camera.accept_scroll_and_zoom(event) then return true
# Handle other events...
return false
end
end
# Zoom and scroll this camera from user input
#
# Scrolling is accomplished by moving the camera on the XY plane and
# zooming by moving it on the Z axis.
#
# This method has distinct implementations per platform.
# On desktop computers, the mouse wheel changes the zoom level, and
# holding down the middle mouse button scrolls the camera.
# On Android, a two finger pinch and slide gesture zoom and scroll.
#
# Returns `true` if the event is used.
#
# Should be called from `App::accept_event` before accepting pointer events:
#
# ~~~nitish
# redef class App
# redef fun accept_event(event)
# do
# if world_camera.accept_scroll_and_zoom(event) then return true
#
# # Handle other events...
# return false
# end
# end
# ~~~
fun accept_scroll_and_zoom(event: InputEvent): Bool do return false
lib/gamnit/camera_control.nit:25,2--50,68
redef fun accept_scroll_and_zoom(event)
do
# Zoom
if event isa GamnitMouseWheelEvent then
var dy = event.y
var mod = camera_zoom_mod
if dy > 0.0 then
# Zoom in when moving the wheel up
mod = 1.0/mod
else dy = -dy
position.z *= dy * mod
return true
end
# Scroll
var but_mask = camera_pan_mask
if but_mask != 0 and event isa GamnitPointerEvent then
var native = event.native
if native isa SDLMouseMotionEvent and native.state & but_mask == but_mask then
var dx = native.xrel.to_f
var dy = native.yrel.to_f
var world_height = field_of_view_y.sin * position.z
var mod = app.display.as(not null).height.to_f / world_height
position.x -= dx / mod
position.y += dy / mod # Y is inverted between the input and output
return true
end
end
return false
end
lib/gamnit/camera_control_linux.nit:31,2--63,4
redef fun accept_scroll_and_zoom(event)
do
if not event isa AndroidMotionEvent then return false
if event.pointers.length < 2 then
# Intercept leftovers of the last motion
return event.down_time == last_motion_start
end
# Collect active pointer and their world position
var new_motion_pointers = new HashMap[Int, Point[Float]]
var ids = new Array[Int]
for pointer in event.pointers do
var id = pointer.pointer_id
ids.add id
new_motion_pointers[id] = camera_to_world(pointer.x, pointer.y)
end
var last_motion_pointers = last_motion_pointers
if last_motion_start == event.down_time and
last_motion_pointers.keys.has(ids[0]) and last_motion_pointers.keys.has(ids[1]) then
# Continued motion event
# Get new and old position for 2 fingers
var new_motion_a = new_motion_pointers[ids[0]]
var new_motion_b = new_motion_pointers[ids[1]]
var prev_pos_a = last_motion_pointers[ids[0]]
var prev_pos_b = last_motion_pointers[ids[1]]
# Move camera
var prev_middle_pos = prev_pos_a.lerp(prev_pos_b, 0.5)
var new_middle_pos = new_motion_a.lerp(new_motion_b, 0.5)
position.x -= new_middle_pos.x - prev_middle_pos.x
position.y -= new_middle_pos.y - prev_middle_pos.y
# Zoom camera
var prev_dist = prev_pos_a.dist(prev_pos_b)
var new_dist = new_motion_a.dist(new_motion_b)
position.z = prev_dist * position.z / new_dist
else
# Prepare for a new motion event
last_motion_pointers.clear
last_motion_start = event.down_time
end
# Keep a smooth history
for i in [0..1] do
if last_motion_pointers.keys.has(ids[i]) then
last_motion_pointers[ids[i]] = last_motion_pointers[ids[i]]*0.5 +
new_motion_pointers[ids[i]]*0.5
else last_motion_pointers[ids[i]] = new_motion_pointers[ids[i]]
end
return true
end
lib/gamnit/camera_control_android.nit:28,2--83,4