Page 1 of 1

Trying a Qix clone.

Posted: Mon Apr 11, 2011 8:47 am
by kurai
I know I'm asking a lot, but I'm still learning :)
I was trying to make a small Qix clone, but I'm finding a lot of problems on even how to start.
Basically I want this cursor which movement is bound to the screen's edge and to the already closed lines.
When you press a button you can start to trace an orthogonal line. When you close a rectangle, the rectangle itself gets filled and you can freely move around its perimeter.
When you are tracing your lines, you are vulnerable to attacks not only in the cursor area, but even in the line you are tracing.

Now, I was trying to draw orthogonal lines with the love.graphics.line function, adding points to a table so to build a polyline.
But I've got all sort of problems to limit the direction of the cursor...

I feel lost, here. I need advice on how to proceed, pseudo code, anything pointing me in the right direction.
Can you help me?

Re: Trying a Qix clone.

Posted: Mon Apr 11, 2011 9:19 am
by Lafolie
Always post the latest version of your source code. Helps us understand and help you alot.

Re: Trying a Qix clone.

Posted: Mon Apr 11, 2011 9:29 am
by kurai
Yes, the point is, the code is just a little stub, I don't even know if I'm moving in the right direction.
Right now is not working, because as soon as you start moving, you don't have two vertices to trace a line.

So, here it is, but I doubt it will be useful, probably I'm doing it completely wrong...

Code: Select all


function love.load()
	love.graphics.setMode(1024, 768, false, false)
	hero = {}
	hero.speed=100;

	hero.direction="none"
	hero.position ={}
	
	hero.x=10;
	hero.y=10;
end


function love.draw()
	if hero.direction ~= "none" then
		love.graphics.line(hero.position);
	end
end

function love.update(dt)
	if love.keyboard.isDown("left") then
		if hero.direction ~= "left" then
			hero.direction="left"
			table.insert (hero.position, hero.x, hero.y)
		end
		hero.x=hero.x-(hero.speed*dt)
	elseif love.keyboard.isDown("right") then
		if hero.direction ~= "right" then
			hero.direction="right"
			table.insert (hero.position, hero.x, hero.y)
		end
		hero.x=hero.x+(hero.speed*dt)
	elseif love.keyboard.isDown("up") then
		if hero.direction ~= "up" then
			hero.direction="up"
			table.insert (hero.position, hero.x, hero.y)
		end
		hero.y=hero.y-(hero.speed*dt)
	elseif love.keyboard.isDown("down") then
		if hero.direction ~= "down" then
			hero.direction="down"
			table.insert (hero.position, hero.x, hero.y)
		end
		hero.y=hero.y+(hero.speed*dt)
	end
end

Re: Trying a Qix clone.

Posted: Mon Apr 11, 2011 10:07 am
by Lafolie
Well for a start this line isn't valid syntax:

Code: Select all

      love.graphics.line(hero.position);
The syntax for graphics.line is:

Code: Select all

love.graphics.line( x1, y1, x2, y2, ... )
You made 2 errors - you didn't supply enough arguments to actually draw a line, and the first argument you passed was the wrong datatype; .line accepts numbers and not a table. If you wanted to use a table you could define your own function that breaks the table down as appropriate.

EDIT: I am an idiot. .line does indeed accept a table. Sorry about that.

But yeah, you still need to supply a second argument. At the moment you're attempting to draw a dot really. A line needs 2 sets of co-ords.

Re: Trying a Qix clone.

Posted: Mon Apr 11, 2011 3:43 pm
by kurai
I can see the problem.
But still, I cannot tell if this is the right direction for what I'm trying to do.
And still, I have no clue on how to limit the cursor movement only on the traced lines.
I really need some help to see clearer where I should go...

Re: Trying a Qix clone.

Posted: Mon Apr 11, 2011 11:18 pm
by miko
kurai wrote:I can see the problem.
But still, I cannot tell if this is the right direction for what I'm trying to do.
And still, I have no clue on how to limit the cursor movement only on the traced lines.
I really need some help to see clearer where I should go...
Don't worry, you are almost there.
Some random advices:
- limit x,y with max/min (or if)
- store only integer coordinates (unless you are using scaling)
- you either need a list of visited pixels (which is easier but memory-hungry), or a list of visited lines and some math (to check if a point is on one o those lines)
- if you will want to fill the enclosed area with another color, you probably will need to slice it to rectangles - filling polygons does not work nice in love2d for all polygons.
- you could also use framebuffers for filling with color/detecting visited points, but that would be slower

Here is my code:

Code: Select all

function love.load()
   love.graphics.setMode(1024, 768, false, false)
   hero = {}
   hero.speed=100;

   hero.position ={} 
   
   hero.x=10;
   hero.y=10;
   XMIN, XMAX, YMIN, YMAX=0,1024,0,768

   Visited={}

   enemy={position={x=0,y=0}, prev={x=-1,y=-1}}
end

function enemyNextPos()
  local e=enemy.position
  local p=enemy.prev
  local possible={}
  for _,d in ipairs({{-1,0},{1,0},{0,-1},{0,1}}) do
    local dx,dy=unpack(d)
    local x=e.x+dx
    local y=e.y+dy
    local visited=(Visited[x] and Visited[x][y]==true) or false
    local onEdge=(x==0 or x==1024 or y==0 or y==768)
    local onScreen=(x>=0 and x<=1024 and y>=0 and y<=768)
    local notPrev=not (x==p.x and y==p.y)
    if (visited or onEdge) and onScreen and notPrev then
      table.insert(possible, {x, y})
    end
  end
  return table.remove(possible, math.random(1, #possible))
end

function moveEnemy()
  local x,y=unpack(enemyNextPos())
  enemy.prev=enemy.position
  enemy.position={x=x, y=y}
end

function love.draw()
   --need at least 2 points to draw a line
   love.graphics.setColor(255,255,255,255)
   love.graphics.setLineWidth(3)
   love.graphics.rectangle('line', 0,0,1024,768)
   if #hero.position>=4 then
     love.graphics.setColor(0, 255,0,255)
     love.graphics.line(hero.position);
     love.graphics.circle('line', hero.x, hero.y, 5, 10)
   end
   love.graphics.setColor(255,0,0,255)
   love.graphics.circle('fill', enemy.position.x, enemy.position.y, 5, 10)
end

function love.update(dt)
  tick=(tick or 0)+dt*hero.speed
  if tick>1 then
     tick=tick-1
     local dx,dy=0,0
     if love.keyboard.isDown("left") then
       dx=-1
     elseif love.keyboard.isDown("right") then
       dx=1
     elseif love.keyboard.isDown("up") then
       dy=-1
     elseif love.keyboard.isDown("down") then
       dy=1
     end
     if dx~=0 or dy~=0 then
       -- insert only integer numbers
       local x=math.floor(hero.x)
       local y=math.floor(hero.y)
       if x~=LASTX or y~=LASTY then
         table.insert(hero.position, x)
         table.insert(hero.position, y)
         LASTX=x
         LASTY=y
         if not Visited[x] then Visited[x]={} end
         Visited[x][y]=true
       end
       hero.x=math.max(XMIN, math.min(XMAX, hero.x+dx))
       hero.y=math.max(YMIN, math.min(YMAX, hero.y+dy))
     end
  end
  moveEnemy()
  moveEnemy() --twice as fast
end