Draw array

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
Cheeta
Prole
Posts: 2
Joined: Mon Jun 07, 2021 6:58 pm

Draw array

Post by Cheeta »

Hello.
I'm pretty sure this is not the best way to achieve my goal (draw the player in the middle of screen and everything near him, emulating a what I think is called "camera movement"??), however this is the only way I can think of.

Code: Select all

function love.load()
  map={}
  w_max=100
  h_max=100
  for y=1,h_max do
    map[y]={}
    for x=1,w_max do
      map[y][x]=love.math.random(0,1)
    end
  end
  playerX,playerY=1,1
  oldchar=map[playerY][playerX]
  map[playerY][playerX]=2
  font_size=12
  love.graphics.setNewFont(font_size)
end

function love.draw()
  local char
  for y=1,#map do
    for x=1,#map[y] do
      if map[y][x]==0 then char="."
      elseif map[y][x]==1 then char="#"
      elseif map[y][x]==2 then char="@" end
      love.graphics.print(char,(x-1)*font_size,(y-1)*font_size)
    end
  end
end

function love.keypressed(k)
  map[playerY][playerX]=oldchar
  if k=="up" then playerY=playerY-1
  elseif k=="down" then playerY=playerY+1
  elseif k=="left" then playerX=playerX-1
  elseif k=="right" then playerX=playerX+1 end
  oldchar=map[playerY][playerX]
  map[playerY][playerX]=2
end
User avatar
darkfrei
Party member
Posts: 1169
Joined: Sat Feb 08, 2020 11:09 pm

Re: Draw array

Post by darkfrei »

Translate: https://love2d.org/wiki/love.graphics.translate


You can use the chars in array:

Code: Select all

chars = {".", "#", "@"}
print (char[1]..char[2]..char[3]) -- ".#@"
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
knorke
Party member
Posts: 238
Joined: Wed Jul 14, 2010 7:06 pm
Contact:

Re: Draw array

Post by knorke »

Hi, maybe something like this:

currently when drawing the map, you loop through the whole array like:

Code: Select all

  for y=1,#map do
    for x=1,#map[y] do
but we only want to draw a smaller part of the map, the part that is near the player.
Say 10 chars to the left, 10 to the right, and 5 to the top, 5 to bottom.

then the loop would look like:

Code: Select all

for y=-5,5 do
    for x=-10,10 do  
so instead of x and y being the absolutes coordinates of the char we want to draw, they get turned into relative offsets from the player. The actual char to be drawn we can calculate to be at these coordinates:

Code: Select all

local xdraw = playerX+x
local ydraw = playerY+y
Where on the screen do we draw it?
We can not just draw at (x-1)*font_size, (y-1)*font_size anymore because then we would be in negative screen coordinates. So we just add an offset like
(x-1)*font_size+500,(y-1)*font_size+300


Below is working example. Instead of fixed numbers I made a "viewport" table that defines the drawing-area. I also put it into a function drawViewport because that allows for neat easy tricks, like having two drawing areas at once: For example the actual gamescreen and a map.

Since the game is tile-based, drawing the player can easily be done like:

Code: Select all

if xdraw==playerX and ydraw==playerY then char = "@" end --draw player
or you could just always draw the play centered in the viewport. Or calculate the on-screen-drawing-postion of the player, similiar to how the drawing-positions of the walls are calculated.

Code: Select all

--viewport.  width, height: size in characters. posX,posY :screencoordinates in pixels
local gamescreen = {width=20, height=10, posX=300, posY=300, font_size=20}
local minimap = {width=50, height=50, posX=90, posY=100, font_size=2}

groundTypes = {" ", "-","#","*"}

local map={}
function love.load()
  w_max=500
  h_max=500
  for x=1,w_max do
    map[x]={}
    for y=1,h_max do
      map[x][y]=love.math.random(1,3)
    end
  end
  playerX,playerY=200,200  
end

function love.draw()
	drawViewport (gamescreen)
	drawViewport (minimap)
end

function drawViewport (viewport)
  love.graphics.setNewFont(viewport.font_size)
  for y=-viewport.height/2,viewport.height/2 do
    for x=-viewport.width/2,viewport.width/2 do      
		local xdraw = playerX+x
		local ydraw = playerY+y
		local char = groundTypes[map[xdraw][ydraw]]
		if xdraw==playerX and ydraw==playerY then char = "@" end --draw player
		love.graphics.print(char,(x*viewport.font_size)+viewport.posX,(y*viewport.font_size)+viewport.posY)
    end
  end
end

function love.keypressed(k)
  if k=="up" then playerY=playerY-1
  elseif k=="down" then playerY=playerY+1
  elseif k=="left" then playerX=playerX-1
  elseif k=="right" then playerX=playerX+1 end 
--  map[playerX][playerY]=1   --uncomment for "eating"
end
note: I swapped x and y, so the x-coordinate is first: map[x][y]
Cheeta
Prole
Posts: 2
Joined: Mon Jun 07, 2021 6:58 pm

Re: Draw array

Post by Cheeta »

darkfrei wrote: Mon Jun 07, 2021 9:33 pm Translate: https://love2d.org/wiki/love.graphics.translate


You can use the chars in array:

Code: Select all

chars = {".", "#", "@"}
print (char[1]..char[2]..char[3]) -- ".#@"
Oh, sure. Thank you.
knorke wrote: Mon Jun 07, 2021 10:54 pm Hi, maybe something like this:

currently when drawing the map, you loop through the whole array like:

Code: Select all

  for y=1,#map do
    for x=1,#map[y] do
but we only want to draw a smaller part of the map, the part that is near the player.
Say 10 chars to the left, 10 to the right, and 5 to the top, 5 to bottom.

then the loop would look like:

Code: Select all

for y=-5,5 do
    for x=-10,10 do  
so instead of x and y being the absolutes coordinates of the char we want to draw, they get turned into relative offsets from the player. The actual char to be drawn we can calculate to be at these coordinates:

Code: Select all

local xdraw = playerX+x
local ydraw = playerY+y
Where on the screen do we draw it?
We can not just draw at (x-1)*font_size, (y-1)*font_size anymore because then we would be in negative screen coordinates. So we just add an offset like
(x-1)*font_size+500,(y-1)*font_size+300


Below is working example. Instead of fixed numbers I made a "viewport" table that defines the drawing-area. I also put it into a function drawViewport because that allows for neat easy tricks, like having two drawing areas at once: For example the actual gamescreen and a map.

Since the game is tile-based, drawing the player can easily be done like:

Code: Select all

if xdraw==playerX and ydraw==playerY then char = "@" end --draw player
or you could just always draw the play centered in the viewport. Or calculate the on-screen-drawing-postion of the player, similiar to how the drawing-positions of the walls are calculated.

Code: Select all

--viewport.  width, height: size in characters. posX,posY :screencoordinates in pixels
local gamescreen = {width=20, height=10, posX=300, posY=300, font_size=20}
local minimap = {width=50, height=50, posX=90, posY=100, font_size=2}

groundTypes = {" ", "-","#","*"}

local map={}
function love.load()
  w_max=500
  h_max=500
  for x=1,w_max do
    map[x]={}
    for y=1,h_max do
      map[x][y]=love.math.random(1,3)
    end
  end
  playerX,playerY=200,200  
end

function love.draw()
	drawViewport (gamescreen)
	drawViewport (minimap)
end

function drawViewport (viewport)
  love.graphics.setNewFont(viewport.font_size)
  for y=-viewport.height/2,viewport.height/2 do
    for x=-viewport.width/2,viewport.width/2 do      
		local xdraw = playerX+x
		local ydraw = playerY+y
		local char = groundTypes[map[xdraw][ydraw]]
		if xdraw==playerX and ydraw==playerY then char = "@" end --draw player
		love.graphics.print(char,(x*viewport.font_size)+viewport.posX,(y*viewport.font_size)+viewport.posY)
    end
  end
end

function love.keypressed(k)
  if k=="up" then playerY=playerY-1
  elseif k=="down" then playerY=playerY+1
  elseif k=="left" then playerX=playerX-1
  elseif k=="right" then playerX=playerX+1 end 
--  map[playerX][playerY]=1   --uncomment for "eating"
end
note: I swapped x and y, so the x-coordinate is first: map[x][y]
That's exactly what I was looking for. Thank you sir. =))
Post Reply

Who is online

Users browsing this forum: Google [Bot], Semrush [Bot] and 51 guests