This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Joe3000's profile picture

Help with how to rotate objects in a game

Started by Joe3000, 01 June 2013 - 12:45 PM
Joe3000 #1
Posted 01 June 2013 - 02:45 PM
So I decided to practice my skills with making the game Tetris… and so just to get a little bit of practice and understand of what I will need to do I wrote a simple code to rotate blocks

running = true
refreshRate = 0.15
gtID = os.startTimer(refreshRate)
l, h = term.getSize()
function draw()
  term.setBackgroundColour(colours.white)
  term.write(" ")
end
xposO = math.floor(l/2)
yposO = math.floor(h/2)
blocks = {
 
  update = {
    xpos = xposO;
    ypos = yposO;
  };
 
  draw = function(self)
    for i = 1,4 do
	  term.setCursorPos(self.update.xpos,
	  self.update.ypos + i)
	  term.setBackgroundColour(colours.white)
	  term.write(" ")
    end
  end;

}
function update()
  id, p1 = os.pullEvent()
  if id == "timer" and p1 == gtID then
    blocks:draw()
    gtID = os.startTimer(refreshRate)
  elseif id == "key" and p1 == keys.left then
    blocks.update.xpos = yposO
    blocks.update.ypos = xposO
    blocks:draw()
  elseif id == "key" and p1 == keys.q then
    running = false
  end
end
while running do
update()
end
term.setBackgroundColour(colours.black)
shell.run("clear")
sleep(0.01)

(first off, if you think there could be something improved here please tell me!!)
Alright, so the object is 4 blocks tall and they go vertially, and what i'm trying to do is make them go horizontaly by switching the xpos and ypos when the left key is clicked… but I'm not sure If I did this right… I don't get any errors but It doesn't rotate…. please help!!
Joe3000 #2
Posted 01 June 2013 - 02:47 PM
oh…. i was just going over the code… ignore that function draw() XD i forgot to take it out!!! also, the code is really messy because I have kinda been experimenting for the past hour…
Yevano #3
Posted 01 June 2013 - 03:04 PM
Why would switching xPos and yPos make it change rotation? That will just translate it. If you want to do something like Tetris, you probably want to store the pieces in a different way. You could store pieces as 2-dimensional arrays which show where all the inner squares are. When you want to turn a piece clockwise, you could create a new piece by iterating over the old one from left to right and up to down while iterating over the new one from up to down and right to left.
Bomb Bloke #4
Posted 01 June 2013 - 07:32 PM
Yes, tables are the way! Something like:

local block = {{{0,0,0,1},
                {0,0,0,1},
                {0,0,0,1),
                {0,0,0,1}},

               {{0,0,0,0},
                {0,0,1,1},
                {0,1,1,0},
                {0,0,0,0}},

     (etc until you've defined all the blocks)

local function getBlock(blocknum, blockrotation)
  local tempblock = {{},{},{},{}}  -- Declare four empty tables in one table

  if blockrotation == 1 then     -- Block is upright
    for x=1,4 do for y=1,4 do tempblock[x][y] = block[blocknum][x][y] end end
  elseif blockrotation == 2 then -- Block is rotated once 90 degrees clockwise
    for x=1,4 do for y=1,4 do tempblock[5-y][x] = block[blocknum][x][y] end end
  elseif blockrotation == 3 then -- Block is rotated twice clockwise
    for x=1,4 do for y=1,4 do tempblock[5-x][5-y] = block[blocknum][x][y] end end
  elseif blockrotation == 4 then -- Block is rotated thrice clockwise
    for x=1,4 do for y=1,4 do tempblock[y][5-x] = block[blocknum][x][y] end end
  end

  return tempblock
end
Joe3000 #5
Posted 01 June 2013 - 08:47 PM
Bomb that is amazing! I never thought of drawing tables out like that! Along with that double for method!!! You're a genius XD!! So now I have got them drawing which is cool but I have come across another problem…. this one is easier though…. when drawing I use that double for method to search for 1's, and when it comes across a 1 to set the xpos and ypos to the x and y from thoes for's…. but there problem is is that I have to manually go into the code and write which blocknum I want to use, how would i set this to a varriable? Hopefully this isnt too confusing XD

–Edit–
Nevermind, figured it out XD
Bomb Bloke #6
Posted 01 June 2013 - 09:08 PM
"math.random(x)" gives you a random integral number each time you call it, somewhere from 1 to whatever x is (so long as x is an integer) - so you'd make x the number of blocks in your table. The easiest way to do this is "math.random(table.getn(block))" (where "table.getn(block)" returns the number of tables in the "block" table. I *think* that'd return as an integer).

So, you'd do something like this:

<initialisation stuff,="" define="" functions="" tables="" etc="">

nextblock = math.random(table.getn(block))
rotation = 1
playing = true

while playing do
  curblock = nextblock
  nextblock = math.random(table.getn(block))

  curblockshape = getBlock(curblock,rotation)  -- "rotation" can be incremented or decremented
                                               -- based on player input, hence rotating the block
  nextblockshape = getBlock(nextblock,1)

  -- Code here to draw the shape stored in "nextblockshape" up the top corner somewhere so the
  -- player can see which block will start falling after the current one.

  blockfalling = true
  while blockfalling do  
    -- Set up a loop here to make the current block fall. Whenever the player hits a rotate button,
    -- update the rotation variable and re-call "curblockshape = getBlock(curblock,rotation)".

    -- When the block hits the bottom, set blockfalling to false to break out of this loop.
  end

  -- Check for completed lines, or for a game-over (set "playing" to false if the grid is full).
end

TL;DR version: To put a number in a variable, you just type "variablename = number".
Joe3000 #7
Posted 02 June 2013 - 03:36 AM
Alright…. I don't want to get ahead of myself XD…. so now I cleaned up the code and made everything look nice and pretty!! But I still can't get my blocks to rotate :/ what did I do wrong now? (Btw, I only want to get the blocks to rotate for right now because I'm trying to make this as best of a learning experience as possible so i'm going one step at a time) heres the code…

l,h = term.getSize()
running = true
refreshRate = 0.15
gtID = os.startTimer(refreshRate)
current = {{};{};{};{};}
--local blocknum = 1
block = {
  {{0,0,0,0};
  {1,1,1,0};
  {0,1,0,0};
  {0,0,0,0};};

  rotate = 1;
  blocknum = 1;
update = function(self, blocknum)
   if self.rotate == 1 then
	 for x=1,4 do for y=1,4 do current[x][y] = block[blocknum][x][y]  end end
   elseif self.rotate == 2 then
	 for x=1,4 do for y=1,4 do current[x][y] = block[blocknum][5-x][y] end end
   elseif self.rotate == 3 then
	 for x=1,4 do for y=1,4 do current[x][y] = block[blocknum][5-x][5-y] end end
   elseif self.rotate == 4 then
	 for x=1,4 do for y=1,4 do current[x][y] = block[blocknum][x][5-y] end end
   end
  end;

  draw = function(self)
	for x=1,4 do for y=1,4 do
	  if block[1][y][x] == 1 then
		term.setCursorPos(x,y)
		term.setBackgroundColour(colours.white)
		term.write(" ")
	  end
	end
	end
  end;
}
function drawGame()
  term.setBackgroundColour(colours.black)
  term.clear()
  block:draw()
end
function updateGame()
  id, p1 =os.pullEvent()
  if id == "key" and p1 == keys.q then running = false
  if id == "key" then
	if p1 == keys.left and block[2] > 1 then
	  block[2] = block[2] - 1
	elseif p1 == keys.right and block[2] < 1 then
	  block[2] = block[2] + 1
	end
  end
  if id == "Timer" and p1 == gtID then
	block:update()
	gtID = os.startTimer(refreshRate)
  end
  end
end
function gameLoop()
  while running do
	drawGame()
	updateGame()
  end
end
gameLoop()
term.setBackgroundColour(colours.black)
shell.run("clear")
sleep(0.01)

Also, I had a problem getting to a table through a varriable again (thats why i have –blocknum=1 at the top, i was using block[blocknum], but apparently that doesnt work… give me a break I'm a noob!!) how else go I go about doing this so i can change which block I want to use?
Bomb Bloke #8
Posted 02 June 2013 - 09:27 AM
Well… you've only defined one block. I don't see any way to switch to another until you define more. :|

Sorry, as I didn't complete my version of the "block" table in my previous example, I think you've gotten the impression that I was going to put things other then actual block shapes in it. My suggested "getBlock" function was to be declared after the table was fully defined. Though I suppose you're going for something similar to a Java object there, which keeps things neat and tidyish.

I got a bit lost when you called "block:update()" without arguments, as it looks like it needs them to me. Though when I tested your code out I found that call never actually gets made, which is why I suppose it sorta works ("Timer" isn't the same thing as "timer"!).

I do see that your "block:draw()" function is rigged to draw what's in the "block" table. As opposed to what's in the "current" table, which is where you'd be putting the rotated versions of the block were the block.update() function being called.

I guess you're trying to modify "block.rotate" by modifying block[2]? They're not the same thing. At least I think that's what you're trying to do; you've got it rigged so that whatever block[2] is, it can only go up if it's less then 1, and only go down if it's more then 1. Which means it can only ever be set to 1. "block.rotate" needs to be able to range from 1 to 4 to do any good.

Be careful of your ordering of indexes in the "update" function. When I said things like "[y][5-x]", I meant them.