[Solved] Camera zoom between 3 players?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Jomkin
Prole
Posts: 8
Joined: Wed Jul 15, 2020 2:12 am

[Solved] Camera zoom between 3 players?

Post by Jomkin »

Hello, how can I make a camera unzoom and zoom between 3 players.
Like when the players are going away the camera unzoom, and when they get closer the camera zoom.

I have :

Code: Select all

player1.x = x
player1.y = y

player2.x = x
player2.y = y

player3.x = x
player3.y = y
and for the scale (zoom) and the positions of the camera I use :

Code: Select all

camera:setScale(*,*)
camera.x = ((player1.x + player2.x + player3.x)/3) - screenWidth 
camera.y = ((player1.y + player2.y + player3.y)/3) - screenHeight 
Thank you!
Last edited by Jomkin on Wed Nov 04, 2020 1:47 am, edited 1 time in total.
User avatar
pgimeno
Party member
Posts: 3593
Joined: Sun Oct 18, 2015 2:58 pm

Re: Camera zoom between 3 players?

Post by pgimeno »

Jomkin wrote: Mon Nov 02, 2020 10:48 pm

Code: Select all

camera:setScale(*,*)
camera.x = ((player1.x + player2.x + player3.x)/3) - screenWidth 
camera.y = ((player1.y + player2.y + player3.y)/3) - screenHeight 
Shouldn't that be the average between the maximum and minimum position? The player that lies between max and min should not influence the camera position IMO. So:

Code: Select all

local min, max = math.min, math.max
local minX = min(min(player1.x, player2.x), player3.x)
local maxX = max(max(player1.x, player2.x), player3.x)
local minY = min(min(player1.y, player2.y), player3.y)
local maxY = max(max(player1.y, player2.y), player3.y)

camera.x = (minX + maxX)/2 -- - screenWidth (can't understand why the "- screenWidth")
camera.y = (minY + maxY)/2
The zoom factor should be the smallest of the ratios between the distance from centre to the edge of the screen at a zoom of 1x, and the distance from centre to min/max, but I imagine that you need to set some margins and maybe a zoom-in limiter.

Since both numerator and denominator should be divided by 2, I've simplified away the division by 2 below.

Code: Select all

-- You'll have to find an appropriate margin in each direction.
-- Note that the actual margin will be half the value below,
-- because of the simplification.
local marginX, marginY = 20, 20
local zoomX = screenWidth / (maxX - minX + marginX)
local zoomY = screenHeight / (maxY - minY + marginY)
local zoom = min(min(zoomX, zoomY), 1) -- limit zoom to no more than 1x

camera:setScale(zoom, zoom)
(edited because I screwed up the division order)

Edit2: Quick and dirty PoC:

Code: Select all

local camera = require 'cam11'()
local min, max = math.min, math.max
local isDown = love.keyboard.isScancodeDown

local marginX, marginY = 20, 50
local playerW = 10
local playerH = 30
local player1 = {x = 20, y = 20}
local player2 = {x = 50, y = 450}
local player3 = {x = 720, y = 30}
local playerSpeed = 200
local curPlayer = player1

local screenWidth = 800
local screenHeight = 600
if love.graphics.getWidth() ~= screenWidth then
  love.graphics.setMode(screenWidth, screenHeight)
end

function love.update(dt)
  if isDown("a") then curPlayer.x = curPlayer.x - playerSpeed * dt end
  if isDown("d") then curPlayer.x = curPlayer.x + playerSpeed * dt end
  if isDown("w") then curPlayer.y = curPlayer.y - playerSpeed * dt end
  if isDown("s") then curPlayer.y = curPlayer.y + playerSpeed * dt end
  local minX = min(min(player1.x, player2.x), player3.x)
  local maxX = max(max(player1.x, player2.x), player3.x)
  local minY = min(min(player1.y, player2.y), player3.y)
  local maxY = max(max(player1.y, player2.y), player3.y)

  camera:setPos((minX + maxX) * 0.5, (minY + maxY) * 0.5)

  local zoomX = screenWidth / (maxX - minX + marginX)
  local zoomY = screenHeight / (maxY - minY + marginY)
  local zoom = min(min(zoomX, zoomY), 1) -- limit zoom to no more than 1x

  camera:setZoom(zoom)
end

local function setColourFor(n)
  local n_player = player1
  if n == 2 then n_player = player2 end
  if n == 3 then n_player = player3 end
  if n_player == curPlayer then
    love.graphics.setColor(1, 0.5, 0)
  else
    love.graphics.setColor(0.5, 1, 1)
  end
end

function love.draw()
  camera:attach()
  setColourFor(1)
  love.graphics.rectangle("fill",
    player1.x - playerW*0.5, player1.y - playerH*0.5, playerW, playerH)
  setColourFor(2)
  love.graphics.rectangle("fill",
    player2.x - playerW*0.5, player2.y - playerH*0.5, playerW, playerH)
  setColourFor(3)
  love.graphics.rectangle("fill",
    player3.x - playerW*0.5, player3.y - playerH*0.5, playerW, playerH)
  love.graphics.setColor(1, 1, 1)
  camera:detach()
end

function love.keypressed(keycode, scancode)
  if scancode == '1' then curPlayer = player1 end
  if scancode == '2' then curPlayer = player2 end
  if scancode == '3' then curPlayer = player3 end
  if scancode == 'escape' then return love.event.quit() end
end
(use wasd for movement; to switch player use 1, 2, 3 of the regular keyboard, not of the keypad)
Needs https://notabug.org/pgimeno/cam11
Jomkin
Prole
Posts: 8
Joined: Wed Jul 15, 2020 2:12 am

Re: Camera zoom between 3 players?

Post by Jomkin »

Thank you very much for your time and your help it worked perfectly!
Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests