Page 1 of 2

Regarding placing/removing blocks in game.

Posted: Mon Oct 10, 2011 4:16 pm
by StormsAndOceans
So I've got this code set up for a game where you can place/remove blocks by using the left and right click keys while hovering over them, similar to minecraft and terraria, and I was wondering if I'm doing this in the best possible way or if I'm over complicating the process. What I'm doing DOES work though.

Sample code as to what I'm doing:

Code: Select all

function love.mousereleased(x, y, button) 
		if ((x > 0 and x < 21) == true) and ((y > 279 and y < 301) == true) and button == "l" then 
		aoff = 1 
		elseif ((x > 0 and x < 21) == true) and ((y > 279 and y < 301) == true) and button == "r" then 
		aoff = 2
		end
Alright, this code makes it so that a variable, called 'aoff', changes whenever the mouse is over a certain x/y area and the user clicks.

Code: Select all

if aoff == 2 then 
		if blockcolor == "a" then
			tiles.a	= love.graphics.draw(water,0 , 280)
		elseif blockcolor == "b" then 
			tiles.a = love.graphics.draw(redb, 0, 280) 
		elseif blockcolor == "c" then 
			tiles.a = love.graphics.draw(greenb, 0, 280)
		end 
	end 
Now, that variable is put to use later. (obviously inside a love.draw() function.) If the variable is 2, then it shows it. (2 is the default.) If the variable is 1, which it's changed to when the user left clicks the area, the program just doesn't show the block. The rest is just for changing the block color, which for now, every block is based on the 'blockcolor' variable which changes when the user presses 'r'.

The issue with this is that I have to do the code over and over again for every possible block. It's not like I won't do that or I'm too lazy , but I'd just like to know if a superior method exists.

Lastly, some screenshots showing blocks. =)

Image
Image
I'd love some feedback so I can improve. Thanks for reading, regardless!

Re: Regarding placing/removing blocks in game.

Posted: Mon Oct 10, 2011 4:45 pm
by tentus
What you need is an overlap function that loops through all your boxes and tests for a collision, and then changes the state.

I'm hesitant to just hand you a working solution, since that can prevent you from figuring it out on your own, but I wrote something identical to what you're asking for when writing up a tutorial (which I need to finish someday). Here it is:

Code: Select all

function love.load()
	box = {}
	for i = 1, 32 do
		box[i] = {
			x = math.random(0, love.graphics.getWidth()),
			y = math.random(0, love.graphics.getHeight()),
			width = math.random(4,64),
			height = math.random(4,64),
			clicked = false
		}
	end
end

function love.draw()
   for i = 1, #box do
	  if box[i].clicked then
		 love.graphics.setColor(255, 255, 0)
		 love.graphics.rectangle("fill", box[i].x, box[i].y, box[i].width, box[i].height)
		 love.graphics.setColor(255, 255, 255)
	  else
		 love.graphics.rectangle("fill", box[i].x, box[i].y, box[i].width, box[i].height)
	  end
   end
end

function love.mousereleased(x, y, button) 
	local mouse = {
		x = x, 
		y = y, 
		width = 1, 
		height = 1
	}
	for i = 1, #box do
		if overlap(box[i], mouse) then
			box[i].clicked = not box[i].clicked
		end
	end
end

function overlap(a, b)
	return not (a.x+a.width < b.x or b.x+b.width < a.x or a.y+a.height < b.y or b.y+b.height < a.y)
end

Re: Regarding placing/removing blocks in game.

Posted: Mon Oct 10, 2011 4:46 pm
by StormsAndOceans
tentus wrote:What you need is an overlap function that loops through all your boxes and tests for a collision, and then changes the state.

I'm hesitant to just hand you a working solution, since that can prevent you from figuring it out on your own, but I wrote something identical to what you're asking for when writing up a tutorial (which I need to finish someday). Here it is:

Code: Select all

function love.load()
	box = {}
	for i = 1, 32 do
		box[i] = {
			x = math.random(0, love.graphics.getWidth()),
			y = math.random(0, love.graphics.getHeight()),
			width = math.random(4,64),
			height = math.random(4,64),
			clicked = false
		}
	end
end

function love.draw()
   for i = 1, #box do
	  if box[i].clicked then
		 love.graphics.setColor(255, 255, 0)
		 love.graphics.rectangle("fill", box[i].x, box[i].y, box[i].width, box[i].height)
		 love.graphics.setColor(255, 255, 255)
	  else
		 love.graphics.rectangle("fill", box[i].x, box[i].y, box[i].width, box[i].height)
	  end
   end
end

function love.mousereleased(x, y, button) 
	local mouse = {
		x = x, 
		y = y, 
		width = 1, 
		height = 1
	}
	for i = 1, #box do
		if overlap(box[i], mouse) then
			box[i].clicked = not box[i].clicked
		end
	end
end

function overlap(a, b)
	return not (a.x+a.width < b.x or b.x+b.width < a.x or a.y+a.height < b.y or b.y+b.height < a.y)
end
Thank you! That seems much easier than doing each one.

Re: Regarding placing/removing blocks in game.

Posted: Mon Oct 10, 2011 4:49 pm
by tentus
StormsAndOceans wrote:
tentus wrote:What you need is an overlap function that loops through all your boxes and tests for a collision, and then changes the state.

I'm hesitant to just hand you a working solution, since that can prevent you from figuring it out on your own, but I wrote something identical to what you're asking for when writing up a tutorial (which I need to finish someday). Here it is:

Code: Select all

function love.load()
	box = {}
	for i = 1, 32 do
		box[i] = {
			x = math.random(0, love.graphics.getWidth()),
			y = math.random(0, love.graphics.getHeight()),
			width = math.random(4,64),
			height = math.random(4,64),
			clicked = false
		}
	end
end

function love.draw()
   for i = 1, #box do
	  if box[i].clicked then
		 love.graphics.setColor(255, 255, 0)
		 love.graphics.rectangle("fill", box[i].x, box[i].y, box[i].width, box[i].height)
		 love.graphics.setColor(255, 255, 255)
	  else
		 love.graphics.rectangle("fill", box[i].x, box[i].y, box[i].width, box[i].height)
	  end
   end
end

function love.mousereleased(x, y, button) 
	local mouse = {
		x = x, 
		y = y, 
		width = 1, 
		height = 1
	}
	for i = 1, #box do
		if overlap(box[i], mouse) then
			box[i].clicked = not box[i].clicked
		end
	end
end

function overlap(a, b)
	return not (a.x+a.width < b.x or b.x+b.width < a.x or a.y+a.height < b.y or b.y+b.height < a.y)
end
Thank you! That seems much easier than doing each one.
Things you should take from this are:
1: Use tables for your blocks, since it's easy to loop through.
2: The overlap function is very generic and easy to break. You have to give it two tables with x, y, width, and height entries or it doesn't work.
3: You can toggle the state of a box by making it a boolean, and using the "thing = not thing" trick. This is very convenient when you only have to states.

Re: Regarding placing/removing blocks in game.

Posted: Mon Oct 10, 2011 4:50 pm
by StormsAndOceans
tentus wrote:
StormsAndOceans wrote:
tentus wrote:What you need is an overlap function that loops through all your boxes and tests for a collision, and then changes the state.

I'm hesitant to just hand you a working solution, since that can prevent you from figuring it out on your own, but I wrote something identical to what you're asking for when writing up a tutorial (which I need to finish someday). Here it is:

Code: Select all

function love.load()
	box = {}
	for i = 1, 32 do
		box[i] = {
			x = math.random(0, love.graphics.getWidth()),
			y = math.random(0, love.graphics.getHeight()),
			width = math.random(4,64),
			height = math.random(4,64),
			clicked = false
		}
	end
end

function love.draw()
   for i = 1, #box do
	  if box[i].clicked then
		 love.graphics.setColor(255, 255, 0)
		 love.graphics.rectangle("fill", box[i].x, box[i].y, box[i].width, box[i].height)
		 love.graphics.setColor(255, 255, 255)
	  else
		 love.graphics.rectangle("fill", box[i].x, box[i].y, box[i].width, box[i].height)
	  end
   end
end

function love.mousereleased(x, y, button) 
	local mouse = {
		x = x, 
		y = y, 
		width = 1, 
		height = 1
	}
	for i = 1, #box do
		if overlap(box[i], mouse) then
			box[i].clicked = not box[i].clicked
		end
	end
end

function overlap(a, b)
	return not (a.x+a.width < b.x or b.x+b.width < a.x or a.y+a.height < b.y or b.y+b.height < a.y)
end
Thank you! That seems much easier than doing each one.
Things you should take from this are:
1: Use tables for your blocks, since it's easy to loop through.
2: The overlap function is very generic and easy to break. You have to give it two tables with x, y, width, and height entries or it doesn't work.
3: You can toggle the state of a box by making it a boolean, and using the "thing = not thing" trick. This is very convenient when you only have to states.
I did use tables, but not in the right way. The rest I'll make sure to keep note.

Also, how could I do math.random except using multiples of 20?

Re: Regarding placing/removing blocks in game.

Posted: Mon Oct 10, 2011 6:15 pm
by kraftman
If your blocks are going to be in a grid like terraria/minecraft, you don't even need to use a loop: you can just divide the mouse coordinates by the block size and then round down, to get the exact block you want to change.

Eg:

Code: Select all

local grid_size = 40
local block_grid = {}
local block_size = 10


for i = 1, grid_size do
	if not block_grid[i] then
			block_grid[i] = {}
	end
	for j = 1, grid_size do
		block_grid[i][j] = {
									x = i,
									y = j,
									color = {255,0,0,255},
									clicked = false,
									}
	end
end
		
function love.mousepressed(x,y,button)
	x = math.floor(x/block_size)
	y = math.floor(y/block_size)
	
	block_grid[x][y].clicked = not block_grid[x][y].clicked
end

function love.draw()
	for i = 1, grid_size do
		for j = 1, grid_size do
			if block_grid[i][j].clicked then
				love.graphics.setColor(block_grid[i][j].color)
				love.graphics.rectangle("fill", i*block_size, j*block_size, block_size, block_size)
			end
		end
	end
end

Re: Regarding placing/removing blocks in game.

Posted: Mon Oct 10, 2011 6:23 pm
by StormsAndOceans
kraftman wrote:If your blocks are going to be in a grid like terraria/minecraft, you don't even need to use a loop: you can just divide the mouse coordinates by the block size and then round down, to get the exact block you want to change.

Eg:

Code: Select all

local grid_size = 40
local block_grid = {}
local block_size = 10


for i = 1, grid_size do
	if not block_grid[i] then
			block_grid[i] = {}
	end
	for j = 1, grid_size do
		block_grid[i][j] = {
									x = i,
									y = j,
									color = {255,0,0,255},
									clicked = false,
									}
	end
end
		
function love.mousepressed(x,y,button)
	x = math.floor(x/block_size)
	y = math.floor(y/block_size)
	
	block_grid[x][y].clicked = not block_grid[x][y].clicked
end

function love.draw()
	for i = 1, grid_size do
		for j = 1, grid_size do
			if block_grid[i][j].clicked then
				love.graphics.setColor(block_grid[i][j].color)
				love.graphics.rectangle("fill", i*block_size, j*block_size, block_size, block_size)
			end
		end
	end
end
That's more what I was looking to do.

This is a very helpful community. Wow.

Re: Regarding placing/removing blocks in game.

Posted: Mon Oct 10, 2011 6:28 pm
by kraftman
I'M THE BESTEST! GEIF ME KARMAZ!

Re: Regarding placing/removing blocks in game.

Posted: Mon Oct 10, 2011 6:32 pm
by StormsAndOceans
kraftman wrote:I'M THE BESTEST! GEIF ME KARMAZ!
I gave you both karma.

Ooooh.

Re: Regarding placing/removing blocks in game.

Posted: Mon Oct 10, 2011 6:42 pm
by Taehl
Just a quick note, but you don't need to check if something equals true - unless the variable is nil or false, it will be evaluated as true. Likewise, saying "a and b" ITSELF will equal true or false. It sounds crazy, but short-circuit evaluation is really handy and convenient once you get comfortable with it. For example, your statement:

Code: Select all

if ((x > 0 and x < 21) == true) and ((y > 279 and y < 301) == true) then
could be written as merely

Code: Select all

if x > 0 and x < 21 and y > 279 and y < 301 then
It reads much more easily, doesn't it?