Select mode

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
edwardander
Prole
Posts: 10
Joined: Tue May 20, 2014 10:08 am

Select mode

Post by edwardander »

hi,
i am trying to write a very basic program. there are 3 rectangles, when you clicked on one of them, it will be selected. but only one for each time. for instance, if one rectangle is selected and you clicked on another one or on blank area, it should return to unselected mode. my code is here, strangely only the blue box works right. where do i make the mistake?

Code: Select all


function love.load()
  
  --defined colors
  white={255,255,255,255} 
  red={255,0,0,255}
  green={0,255,0,255}
  blue={0,0,255,255}
  
  activeRect=nil  -->selected rectangle is kept here
  
  --rectangles
  rectA={
    x=10,
    y=10,
    width=200,
    height=50,
    color=red,
    tag="red rectangle",
    active=false
  }
  rectB={
    x=10,
    y=70,
    width=100,
    height=50,
    color=green,
    tag="green rectangle",
    active=false
  }
  rectC={
    x=10,
    y=130,
    width=100,
    height=50,
    color=blue,
    tag="blue rectangle",
    active=false
  }
  
  
  end

function makeRect(rect) -->function that makes the rectangles
  
  --some vars
  local x,y,w,h,color,tag,r,g,b,a,active = rect.x,rect.y,rect.width,rect.height,rect.color,rect.tag,rect.color[1],rect.color[2],rect.color[3],rect.color[4],rect.active
  --mouse click vars
  local cursorX,cursorY,button=love.mouse.getX(),love.mouse.getY(),love.mouse.isDown("l")
    
  --draws the rectangle and tags on them
  love.graphics.setColor(r,g,b,a)
  love.graphics.rectangle("fill",x,y,w,h)
  love.graphics.setColor(white,255)
  love.graphics.printf(tag,x,y,w,"center")
  
  --PROBLEMATIC AREA STARTS
  if active==false and cursorX>x and cursorX<x+w and cursorY>y and cursorY<y+h and button==true then
    activeRect=rect
  elseif (cursorX<x or cursorX>x+w or cursorY<y or cursorY>y+h) and button==true then
    rect.active=false
    activeRect=nil
  end
  
  if activeRect==rect then
    love.graphics.setColor(white,255)
    love.graphics.setLineWidth(2)
    love.graphics.rectangle("line",x,y,w,h)
  end
  --PROBLEMATIC AREA ENDS
  
end

function love.draw()
  --draws the rectangles
  makeRect(rectA)
  makeRect(rectB)
  makeRect(rectC)
  
end


User avatar
alesan99
Citizen
Posts: 53
Joined: Sun Feb 09, 2014 3:13 am
Contact:

Re: Select mode

Post by alesan99 »

The problem is that "activeRect" gets set to nil if the mouse isn't over a rectangle active so the red and green boxes aren't active if blue isn't active.
replace

Code: Select all

  if active==false and cursorX>x and cursorX<x+w and cursorY>y and cursorY<y+h and button==true then
    activeRect=rect
  elseif (cursorX<x or cursorX>x+w or cursorY<y or cursorY>y+h) and button==true then
    rect.active=false
    activeRect=nil
  end
with

Code: Select all

  if active==false and cursorX>x and cursorX<x+w and cursorY>y and cursorY<y+h and button==true then
    activeRect=rect
  elseif (cursorX<x or cursorX>x+w or cursorY<y or cursorY>y+h) and button==true then
    rect.active=false
	if activeRect==rect then
		activeRect=nil
	end
  end
But the way you're doing it is difficult. I recommend you use love.mousepressed instead.
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: Select mode

Post by micha »

I'd probably restructure the part of the code like this (Disclaimer: I haven't tested it):

Code: Select all

if button == true then
  if cursorX>x and cursorX<x+w and cursorY>y and cursorY<y+h then
    activeRect = rect
    rect.active = true
  else
    rect.active = false
end
Besides that, there are a couple of things you can improve in your code:
  • The function makeRect does several different things. You should split it up into multiple functions, namely "drawing" and "input handling/game logic". How about these two functions:

    Code: Select all

    drawRectangle()
    findSelectedRectangle()
  • Whenever you have two or more similar objects, it is a good idea to put them into a table. So instead of calling them rectA, rectB and rectC, better call them rect[1], rect[2] and so on. That way you can very easily add and remove some of them and you can make the drawing simpler, by using a loops:

    Code: Select all

    for i = 1,#rect do
      drawRectangle(rect[i])
    end
  • And last, about the clicking logic: There are two possible ways of internally storing, which button is selected. Either have one variable, that stores which button is selected:

    Code: Select all

    selectedRectangle = rect[2]
    , or have a boolean variable on each button, that only knows if this button is the selected one. In your case this would be the ract.active variable. Having both at the same time, is redundant and you risk that they get out of sync. So I suggest having only the first one, a pointer to the current rectangle.
edwardander
Prole
Posts: 10
Joined: Tue May 20, 2014 10:08 am

Re: Select mode

Post by edwardander »

thank you for help. i will take these advices.
edwardander
Prole
Posts: 10
Joined: Tue May 20, 2014 10:08 am

Re: Select mode

Post by edwardander »

by the way, if i want to make a function that finds which rectangle is selected, should i call it in update? or draw?
User avatar
alesan99
Citizen
Posts: 53
Joined: Sun Feb 09, 2014 3:13 am
Contact:

Re: Select mode

Post by alesan99 »

Use love.update.
That way you wont have to find out what box is selected while you're drawing them.
edwardander
Prole
Posts: 10
Joined: Tue May 20, 2014 10:08 am

Same function behaves different

Post by edwardander »

Hello,
i got a little advanced code below. it draws two identical rectangles. it draws frame around of the rectangles if you click on them.

also it should be dragging these rectangles when you click and drag with mouse. this feature works fine for the second rectangle, but not for first. where do i make the mistake? why it works good for one and not for another?

Code: Select all


function love.load()
  
  rectangles={}

--there are two identical rectangles

--first
  table.insert(rectangles,  
    {
    x=10,
    y=20,
    width=200,
    height=50,
    fillColor={255,255,255,255},
    tag="box1",
    tagColor={255,0,0,255},
    isSelected=false,
    selectionColor={0,255,0,255},
    dragging={active=false,diffX=0,diffY=0}
  })
--second
  table.insert(rectangles,  
    {
    x=10,
    y=100,
    width=200,
    height=50,
    fillColor={255,255,255,255},
    tag="box2",
    tagColor={255,0,0,255},
    isSelected=false,
    selectionColor={0,255,0,255},
    dragging={active=false,diffX=0,diffY=0}
  })
  
end



function love.draw()
  
  drawRectangle(rectangles[1])
  drawRectangle(rectangles[2])
  

end



function love.update()
  
  selectRectangle(rectangles[1])
  moveRectangle(rectangles[1])

  selectRectangle(rectangles[2])
  moveRectangle(rectangles[2])

end



function drawRectangle(a)
  --this function draw the rectangle. works properly, i assume
  -- rectangle specs
  local x,y,width,height,fillColor,tag,tagColor,isSelected,selectionColor = a.x,a.y,a.width,a.height,a.fillColor,a.tag,a.tagColor,a.isSelected,a.selectionColor
  
  
  -- color palette
  local fillColorR,fillColorG,fillColorB,fillColorA = fillColor[1],fillColor[2],fillColor[3],fillColor[4]
  local tagColorR,tagColorG,tagColorB,tagColorA = tagColor[1],tagColor[2],tagColor[3],tagColor[4]
  local selectionColorR,selectionColorG,selectionColorB,selectionColorA = selectionColor[1],selectionColor[2],selectionColor[3],selectionColor[4]
  
  -- draws the rectangle body
  love.graphics.setColor(fillColorR,fillColorG,fillColorB,fillColorA)
  love.graphics.rectangle("fill",x,y,width,height)
  love.graphics.setColor(tagColorR,tagColorG,tagColorB,tagColorA)
  love.graphics.printf(tag,x+(width/2),y+(height/2),0,"center")
  
  -- if the rectangle selected, draws the frame
  if isSelected==true then
    
    local lineWidth=2
    love.graphics.setLineWidth(lineWidth)
    love.graphics.setColor(selectionColorR,selectionColorG,selectionColorB,selectionColorA)
    love.graphics.rectangle("line",x-(lineWidth/2),y-(lineWidth/2),width+lineWidth,height+lineWidth)
    
  end
    
end



function selectRectangle(a)
  --this function controls that a rectangle is selected or not. again i assume that works properly too
  
  
  --variables to use
  local mouseX, mouseY, mouseClicked, rectangleX, rectangleY, rectangleWidth, rectangleHeight= love.mouse.getX(), love.mouse.getY(), love.mouse.isDown("l"), a.x, a.y, a.width, a.height

  --selection control
  if mouseClicked==true and (mouseX>rectangleX and mouseY>rectangleY and mouseX<rectangleX+rectangleWidth and mouseY<rectangleY+rectangleHeight) then
    
    a.isSelected=true
    
  elseif mouseClicked==true and not (mouseX>rectangleX and mouseY>rectangleY and mouseX<rectangleX+rectangleWidth and mouseY<rectangleY+rectangleHeight) then
    
    
    a.isSelected=false
    
  end
  
  
end


function moveRectangle(a)  --this function moves the rectangle. the problem is, it works fine for second rectangle but not for first.
  
  function love.mousepressed(x,y,button)

    --if clicked on, dragging mode gets active
    if button == "l" and x>a.x and x < a.x+a.width and y>a.y and y<a.y+a.height then
      a.dragging.active=true
      a.dragging.diffX=x-a.x
      a.dragging.diffY=y-a.y
    end
  end
  
    --if mouse button released dragging mode gets deactive
  function love.mousereleased(x,y,button)
    if button == "l" then
      a.dragging.active=false
    end
  end
  
  -- the calculation of the dragging
  if a.dragging.active==true then

    a.x=love.mouse.getX()-a.dragging.diffX
    a.y=love.mouse.getY()-a.dragging.diffY
  end

end

  


User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: Select mode

Post by micha »

You have two nested functions: love.mousepressed is defined inside the function moveRectangle. That means that love.mousepressed is redefined every frame. And since you call moveRectangle for the second rectangle last, this function only works for the second rectangle.

Try to rewrite the love.mousepressed function such that it loops over all rectangles. And put the definition of love.mousepressed outside any other function.
edwardander
Prole
Posts: 10
Joined: Tue May 20, 2014 10:08 am

Re: Select mode

Post by edwardander »

thank you sir! that's my final code. works good so far.

Code: Select all

function love.load()
  
  rectangles={}

--there are two identical rectangles

--first
  table.insert(rectangles,  
    {
    x=10,
    y=20,
    width=200,
    height=50,
    fillColor={0,255,0,255},
    tag="box1",
    tagColor={255,0,0,255},
    isSelected=false,
    selectionColor={255,255,255,255},
    dragging={active=false,diffX=0,diffY=0}
  })
--second
  table.insert(rectangles,  
    {
    x=10,
    y=100,
    width=200,
    height=50,
    fillColor={0,0,255,255},
    tag="box2",
    tagColor={255,0,0,255},
    isSelected=false,
    selectionColor={255,255,255,255},
    dragging={active=false,diffX=0,diffY=0}
  })
  
end



function love.draw()
  
  drawRectangle(rectangles[1])
  drawRectangle(rectangles[2])
  

end



function love.update()
  
  selectRectangle(rectangles[1])

  selectRectangle(rectangles[2])
  
  for k,a in ipairs(rectangles) do
    
    if a.dragging.active==true then
      
      dragRectangle(a)  --drags the rectangle
      
    end
  end
  
 

end



function drawRectangle(a)
  --this function draw the rectangle. works properly, i assume
  -- rectangle specs
  local x,y,width,height,fillColor,tag,tagColor,isSelected,selectionColor = a.x,a.y,a.width,a.height,a.fillColor,a.tag,a.tagColor,a.isSelected,a.selectionColor
  
  
  -- color palette
  local fillColorR,fillColorG,fillColorB,fillColorA = fillColor[1],fillColor[2],fillColor[3],fillColor[4]
  local tagColorR,tagColorG,tagColorB,tagColorA = tagColor[1],tagColor[2],tagColor[3],tagColor[4]
  local selectionColorR,selectionColorG,selectionColorB,selectionColorA = selectionColor[1],selectionColor[2],selectionColor[3],selectionColor[4]
  
  -- draws the rectangle body
  love.graphics.setColor(fillColorR,fillColorG,fillColorB,fillColorA)
  love.graphics.rectangle("fill",x,y,width,height)
  love.graphics.setColor(tagColorR,tagColorG,tagColorB,tagColorA)
  love.graphics.printf(tag,x+(width/2),y+(height/2),0,"center")
  
  -- if the rectangle selected, draws the frame
  if isSelected==true then
    
    local lineWidth=2
    love.graphics.setLineWidth(lineWidth)
    love.graphics.setColor(selectionColorR,selectionColorG,selectionColorB,selectionColorA)
    love.graphics.rectangle("line",x-(lineWidth/2),y-(lineWidth/2),width+lineWidth,height+lineWidth)
    
  end
    
end



function selectRectangle(a)
  --this function controls that a rectangle is selected or not. again i assume that works properly too
  
  
  --variables to use
  local mouseX, mouseY, mouseClicked, rectangleX, rectangleY, rectangleWidth, rectangleHeight= love.mouse.getX(), love.mouse.getY(), love.mouse.isDown("l"), a.x, a.y, a.width, a.height

  --selection control
  if mouseClicked==true and (mouseX>rectangleX and mouseY>rectangleY and mouseX<rectangleX+rectangleWidth and mouseY<rectangleY+rectangleHeight) then
    
    a.isSelected=true
    
  elseif mouseClicked==true and not (mouseX>rectangleX and mouseY>rectangleY and mouseX<rectangleX+rectangleWidth and mouseY<rectangleY+rectangleHeight) then
    
    
    a.isSelected=false
    
  end
  
  
end


function dragRectangle(a) --function that drags the rectangle
  
  if a.dragging.active==true then

  a.x=love.mouse.getX()-a.dragging.diffX
  a.y=love.mouse.getY()-a.dragging.diffY
    
  end

  
end

function makeRectangleDragActive(a,x,y) --function that actives drag mode
  
 
  a.dragging.active=true
  a.dragging.diffX=x-a.x
  a.dragging.diffY=y-a.y
  

  
end

function love.mousepressed(x,y,button)
  
  for k,a in ipairs(rectangles) do

    if button=="l" and x > a.x and x < a.x+a.width and y > a.y and y < a.y+a.height then
      
      makeRectangleDragActive(a,x,y)  --calls the activation function if it is not active
    end
    
  end
  
 end
 
 function love.mousereleased(x,y,button)
   
    
   for k,a in ipairs(rectangles) do 
     
     if a.dragging.active==true then
       a.dragging.active=false
     end
   end
 end
 

Post Reply

Who is online

Users browsing this forum: Google [Bot] and 4 guests