Page 1 of 2

What can I do with love.graphics.point ???

Posted: Wed Dec 02, 2015 8:12 pm
by napolux
First of all, hello everyone! ;)

I would like to create a simple animated starfield using points, I started from this little example https://love2d.org/wiki/love.graphics.point and I added a size. Now I want to add alpha to the points and move them around, simulating a sort of parallax: bigger objects are brighter and will move faster.

Image

Is my approach ok or should I use sprites instead of points? Can I assign points to variable in the stars table and reference them while I update?

Sorry for the stupid questions, but I'm fairly new to this :D

My code is available here: https://github.com/napolux/devember/blo ... /stars.lua

Re: What can I do with love.graphics.point ???

Posted: Thu Dec 03, 2015 1:43 am
by Beelz
I'm not exactly sure what you mean... Do you want the stars to all move around randomly, or all together? If you want them moving together I would suggest just translating the camera. Also I would tile an image of stars, as opposed to rendering hundreds of points. IMO point is only useful for things like bullets and particles.

Re: What can I do with love.graphics.point ???

Posted: Thu Dec 03, 2015 1:56 am
by s-ol
@Beelz: the whole idea is rendering a Startfield point-by-point, instead of using a prefab space image.

Alpha is part of the color, so you can do love.graphics.setColor(255, 255, 255, 120) for a half-transparent point for example. Of course you can save the points in a table, but I am not sure whether there is a löve function that draws a number of points at once, and there definetely isn't one that draws multiple points with different colors (alphas) - you need to write your own loop for that.

Re: What can I do with love.graphics.point ???

Posted: Thu Dec 03, 2015 4:36 am
by bobbyjones
It probably would be faster to use an image with a spritebatch. Well unless you render the stars to a canvas once.

Re: What can I do with love.graphics.point ???

Posted: Thu Dec 03, 2015 6:13 am
by napolux
Thanks, I'll probably try another approach

Re: What can I do with love.graphics.point ???

Posted: Thu Dec 03, 2015 6:58 am
by Ulydev

Code: Select all

local Starfield = {}
Starfield.__index = Starfield

function Starfield:new(density)
  local starfield = {}
  setmetatable(starfield, Starfield)
  
  starfield.density = density
  
  self.stars = {}

  return starfield
end

function Starfield:onLoad()
  
  for i = 1, self.density do --number of stars
    self.stars[i] = {x = love.math.random()*WWIDTH, y = love.math.random()*WHEIGHT, size = love.math.random()*4+.1}
  end

end

function Starfield:update(dt, x, y)
  
  for i = 1, #self.stars do
    self.stars[i].x, self.stars[i].y = (self.stars[i].x + x*dt)%WWIDTH, (self.stars[i].y + y*dt)%WHEIGHT
  end
  
end

function Starfield:draw()
  
  love.graphics.setColor(255, 255, 255)
  
  for i = 1, #self.stars do
    love.graphics.setPointSize(self.stars[i].size)
    love.graphics.point(self.stars[i].x, self.stars[i].y, self.stars[i].size)
  end
  
end

return Starfield
Create a star field with myStarfield = Starfield:new(50), and call myStarfield:onLoad().

Then, update it with myStarfield:update(dt, moveX, moveY) and draw it with myStarfield:draw().

Re: What can I do with love.graphics.point ???

Posted: Thu Dec 03, 2015 9:23 am
by zorg
Modified Ulydev's code a bit; now it includes parallax:

Code: Select all

-- This will be a table returned at the end of the file, holds all the code necessary to create starfields
local Starfield = {}
-- This is here so that the starfields you create will have everything inside them.
Starfield.__index = Starfield

-- degrees to radians constant
local d2r = math.pi/180

function Starfield:new(density)
  local starfield = {}
  -- This gives the above created starfield every function (and variable) the Starfield table in this file has.
  setmetatable(starfield, Starfield)
  
  -- Saves the given density value
  starfield.density = density
  
  -- Creates an empty table that will hold the stars' data.
  self.stars = {}

  return starfield
end

function Starfield:load()

  local w, h = love.graphics.getDimensions()
  
  -- This loop will set up all the stars with their position, size and visibility generated randomly.
  for i = 1, self.density do --number of stars
    self.stars[i] = {
      x = love.math.random()*w,
      y = love.math.random()*h,
      size = love.math.random()*1.4+.1,
      z = love.math.random()*8+.5,       -- depth
      radiance = love.math.random(1,255) -- alpha (transparency)
    }
  end

end

function Starfield:update(dt, x, y)

  -- If we don't pass in an x or y value, take it as 0 by default
  x, y = x or 0, y or 0

  local w, h = love.graphics.getDimensions()
  
  for i = 1, #self.stars do
    -- Modify each star's position, but wrap them around the screen (with the % modulo/modulus, or remainder operator)
    self.stars[i].x, self.stars[i].y = (self.stars[i].x + x*dt)%w, (self.stars[i].y + y*dt)%h
  end
  
end

function Starfield:draw()

  local w, h = love.graphics.getDimensions()
  
  for i = 1, #self.stars do
    -- this helps translate each star with differing amounts, creating a parallax effect
    local parallax = self.stars[i].z * math.tan(90 / 2 * d2r)
    love.graphics.push()
    love.graphics.setPointSize(self.stars[i].size)
    love.graphics.setColor(255, 255, 255, self.stars[i].radiance)
    -- We modify the drawn positions with the parallax.
    love.graphics.point(self.stars[i].x*parallax, self.stars[i].y*parallax, self.stars[i].size)
    love.graphics.pop()
  end
  
end

return Starfield
Here's a test main.lua:

Code: Select all

local starfield,sf

function love.load()
  starfield = require 'starfield'
  -- create a new starfield with 50k stars.
  sf = starfield:new(50000)
  -- and we initialize it (generate the stars)
  sf:load()
end

function love.update(dt)
  local x, y = 0,0
  -- movement
  if love.keyboard.isDown('left')  then x = x - 100 end
  if love.keyboard.isDown('right') then x = x + 100 end
  if love.keyboard.isDown('up')    then y = y - 100 end
  if love.keyboard.isDown('down')  then y = y + 100 end

  sf:update(dt, x ,y)
end

function love.draw()
  sf:draw()
end
Edit: added comments to explain stuff better
Also, note that this code doesn't treat a bigger star as being closer (and moving faster), since those properities are separate from one another.

Re: What can I do with love.graphics.point ???

Posted: Thu Dec 03, 2015 10:58 am
by s-ol
nanoplux, if you are new to LÖVE and/our Lua, DON'T use a SpriteBatch, a Shader or a Canvas for this. Points are perfectly fine for just trying out how to do a parallax Starfield and even if it were performance critical, not trying without other means would be premature optimization.

also your code is perfectly fine and I doubt that you will learn much by using Ulydevs code.

Do you know how parallaxity "works" mathematically?
I would start by adding dt as a parameter to the updateStars function (see the wiki for dt) and then move each star (set a new value for x) by an amount proportional (or otherwise related) to it's size - that will make small starts move slower than large stars.

After that you can do some custom movement, for example depending on the mouse position or keyboard input.

Re: What can I do with love.graphics.point ???

Posted: Thu Dec 03, 2015 5:23 pm
by bobbyjones
zorg just an unrelated question but what's your fps with 50k stars lol. That's a lot.

Re: What can I do with love.graphics.point ???

Posted: Thu Dec 03, 2015 7:25 pm
by napolux
zorg wrote:Modified Ulydev's code a bit; now it includes parallax:
This is the example I was looking for, very well commented and easy to understand. Thanks a lot (both of you)!

I'll study and modify it to make it manage star size and speed... :D