Regarding placing/removing blocks in game.

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.
StormsAndOceans
Prole
Posts: 18
Joined: Sun Oct 09, 2011 1:12 am

Regarding placing/removing blocks in game.

Post 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!
User avatar
tentus
Inner party member
Posts: 1060
Joined: Sun Oct 31, 2010 7:56 pm
Location: Appalachia
Contact:

Re: Regarding placing/removing blocks in game.

Post 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
Last edited by tentus on Mon Oct 10, 2011 4:49 pm, edited 3 times in total.
Kurosuke needs beta testers
StormsAndOceans
Prole
Posts: 18
Joined: Sun Oct 09, 2011 1:12 am

Re: Regarding placing/removing blocks in game.

Post 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.
User avatar
tentus
Inner party member
Posts: 1060
Joined: Sun Oct 31, 2010 7:56 pm
Location: Appalachia
Contact:

Re: Regarding placing/removing blocks in game.

Post 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.
Kurosuke needs beta testers
StormsAndOceans
Prole
Posts: 18
Joined: Sun Oct 09, 2011 1:12 am

Re: Regarding placing/removing blocks in game.

Post 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?
User avatar
kraftman
Party member
Posts: 277
Joined: Sat May 14, 2011 10:18 am

Re: Regarding placing/removing blocks in game.

Post 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
StormsAndOceans
Prole
Posts: 18
Joined: Sun Oct 09, 2011 1:12 am

Re: Regarding placing/removing blocks in game.

Post 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.
User avatar
kraftman
Party member
Posts: 277
Joined: Sat May 14, 2011 10:18 am

Re: Regarding placing/removing blocks in game.

Post by kraftman »

I'M THE BESTEST! GEIF ME KARMAZ!
StormsAndOceans
Prole
Posts: 18
Joined: Sun Oct 09, 2011 1:12 am

Re: Regarding placing/removing blocks in game.

Post by StormsAndOceans »

kraftman wrote:I'M THE BESTEST! GEIF ME KARMAZ!
I gave you both karma.

Ooooh.
User avatar
Taehl
Dreaming in associative arrays
Posts: 1025
Joined: Mon Jan 11, 2010 5:07 am
Location: CA, USA
Contact:

Re: Regarding placing/removing blocks in game.

Post 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?
Earliest Love2D supporter who can't Love anymore. Let me disable pixel shaders if I don't use them, dammit!
Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 69 guests