bmp aspect ratio issue - lua
I've been trying to understand how bmp files work so I can render some Mandelbrot set pictures and output them as bmp files since that seems to be one of the easiest methods but for some reason when I use an aspect ratio that isn't 1:1 even though its something to the power of 4 (so no padding is needed) I get weird artifacts like these 200:100 48:100 what I'm trying to do is turning an array of pixels that has white for even numbers and black for odd numbers into a bmp, this (100:100) is what it looks like with 1:1 aspect ratio.
I've tried reading through the wikipedia article to see if I can figure out what I'm doing wrong but I still don't get what I'm missing.
This is the script I've written in Lua so far:
ResolutionX = 100
ResolutionY = 100
local cos, atan, sin, atan2, sqrt, floor = math.cos, math.atan, math.sin, math.atan2, math.sqrt, math.floor
local insert, concat = table.insert, table.concat
local sub, char, rep = string.sub, string.char, string.rep
io.output("Test.bmp")
function Basen(n,b)
n = floor(n)
if not b or b == 10 then return tostring(n) end
local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
local t = {}
repeat
local d = (n % b) + 1
n = floor(n / b)
insert(t, 1, digits:sub(d,d))
until n == 0
return rep("0",32-#t)..concat(t,"")
end
FileSize = Basen(ResolutionY*ResolutionX*3 + 54,2)
FileSize4 = tonumber(sub(FileSize,1,8),2) or 0
FileSize3 = tonumber(sub(FileSize,9,16),2) or 0
FileSize2 = tonumber(sub(FileSize,17,24),2) or 0
FileSize1 = tonumber(sub(FileSize,25,32),2) or 0
Width = Basen(ResolutionX,2)
print("Width: ",Width)
Width4 = tonumber(sub(Width,1,8),2) or 0
Width3 = tonumber(sub(Width,9,16),2) or 0
Width2 = tonumber(sub(Width,17,24),2) or 0
Width1 = tonumber(sub(Width,25,32),2) or 0
Height = Basen(ResolutionY,2)
print("Height: ",Height)
Height4 = tonumber(sub(Height,1,8),2) or 0
Height3 = tonumber(sub(Height,9,16),2) or 0
Height2 = tonumber(sub(Height,17,24),2) or 0
Height1 = tonumber(sub(Height,25,32),2) or 0
BMPSize = Basen(ResolutionY*ResolutionX*3,2)
BMPSize4 = tonumber(sub(BMPSize,1,8),2) or 0
BMPSize3 = tonumber(sub(BMPSize,9,16),2) or 0
BMPSize2 = tonumber(sub(BMPSize,17,24),2) or 0
BMPSize1 = tonumber(sub(BMPSize,25,32),2) or 0
print("TotalSize: ",FileSize1,FileSize2,FileSize3,FileSize4,"\nWidth: ",Width1,Width2,Width3,Width4,"\nHeight: ",Height1,Height2,Height3,Height4,"\nImage data: ",BMPSize1,BMPSize2,BMPSize3,BMPSize4)
Result = {"BM"..char( --File type
FileSize1,FileSize2,FileSize3,FileSize4,--File size
0,0,0,0, --Reserved
54,0,0,0, --Where the pixel data starts
40,0,0,0, --DIB header
Width1,Width2,Width3,Width4, --Width
Height1,Height2,Height3,Height4, --Height
1,0, --Color planes
24,00, --Bit depth
0,0,0,0, --Compression
BMPSize1,BMPSize2,BMPSize3,BMPSize4, --The amount of bytes pixel data will consume
Width1,Width2,Width3,Width4,
Height1,Height2,Height3,Height4,
0,0,0,0, --Number of colors in palatte
0,0,0,0
)}
for X = 0, ResolutionX - 1 do
for Y = 0, ResolutionY - 1 do
insert(Result,rep(char(255 * ((X + 1) % 2) * ((Y + 1) % 2)),3))
end
end
io.write(table.concat(Result))
Ok, here's a BMP version. I've put things in a module so it might be easier to use.
local writeBMP = {}
local floor = math.floor
local insert, concat = table.insert, table.concat
local sub, char, rep = string.sub, string.char, string.rep
local function Basen(n,b)
n = floor(n)
if not b or b == 10 then return tostring(n) end
local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
local t = {}
repeat
local d = (n % b) + 1
n = floor(n / b)
insert(t, 1, digits:sub(d,d))
until n == 0
return rep("0",32-#t)..concat(t,"")
end
local function nextMul4(x)
if ( x % 4 == 0 ) then
return x
else
return x+4-(x%4)
end
end
local function clamp(x)
local y = x
if ( x > 255 ) then
y = 255
elseif ( x < 0 ) then
y = 0
end
return floor(y)
end
-- Accepts array of type pixelsXYC[X][Y][C] of numbers 0-255
-- C=1,2,3 are the red, green and blue channels respectively
-- X increases left to right, and Y increases top to bottom
function writeBMP.data(pixelsXYC, resolutionX, resolutionY)
local Pixels = pixelsXYC
local ResolutionX = resolutionX
local ResolutionY = resolutionY
assert(#Pixels == ResolutionX, "Table size and X resolution mismatch")
assert(#Pixels[1] == ResolutionY, "Table size and Y resolution mismatch")
local FileSize = Basen(ResolutionY*nextMul4(3*ResolutionX) + 54,2)
local FileSize4 = tonumber(sub(FileSize,1,8),2) or 0
local FileSize3 = tonumber(sub(FileSize,9,16),2) or 0
local FileSize2 = tonumber(sub(FileSize,17,24),2) or 0
local FileSize1 = tonumber(sub(FileSize,25,32),2) or 0
local Width = Basen(ResolutionX,2)
local Width4 = tonumber(sub(Width,1,8),2) or 0
local Width3 = tonumber(sub(Width,9,16),2) or 0
local Width2 = tonumber(sub(Width,17,24),2) or 0
local Width1 = tonumber(sub(Width,25,32),2) or 0
local Height = Basen(ResolutionY,2)
local Height4 = tonumber(sub(Height,1,8),2) or 0
local Height3 = tonumber(sub(Height,9,16),2) or 0
local Height2 = tonumber(sub(Height,17,24),2) or 0
local Height1 = tonumber(sub(Height,25,32),2) or 0
local BMPSize = Basen(ResolutionY*nextMul4(3*ResolutionX),2)
local BMPSize4 = tonumber(sub(BMPSize,1,8),2) or 0
local BMPSize3 = tonumber(sub(BMPSize,9,16),2) or 0
local BMPSize2 = tonumber(sub(BMPSize,17,24),2) or 0
local BMPSize1 = tonumber(sub(BMPSize,25,32),2) or 0
local Result = {}
Result[1] = "BM" .. char( --File type
FileSize1,FileSize2,FileSize3,FileSize4,--File size
0,0, --Reserved
0,0, --Reserved
54,0,0,0, --Where the pixel data starts
40,0,0,0, --DIB header
Width1,Width2,Width3,Width4, --Width
Height1,Height2,Height3,Height4, --Height
1,0, --Color planes
24,0, --Bit depth
0,0,0,0, --Compression
BMPSize1,BMPSize2,BMPSize3,BMPSize4, --The amount of bytes pixel data will consume
37,22,0,0, --Pixels per meter horizontal
37,22,0,0, --Pixels per meter vertical
0,0,0,0, --Number of colors in palatte
0,0,0,0
)
local Y = ResolutionY
while( Y >= 1 ) do
for X = 1, ResolutionX do
local r = clamp( Pixels[X][Y][1] )
local g = clamp( Pixels[X][Y][2] )
local b = clamp( Pixels[X][Y][3] )
Result[#Result+1] = char(b)
Result[#Result+1] = char(g)
Result[#Result+1] = char(r)
end
-- byte alignment
if ( ( (3*ResolutionX) % 4 ) ~= 0 ) then
local Padding = 4 - ((3*ResolutionX) % 4)
Result[#Result+1] = rep(char(0),Padding)
end
Y = Y - 1
end
return table.concat(Result)
end
function writeBMP.write(pixelsXYC, resolutionX, resolutionY, filename)
local file = io.open(filename,"wb")
local data = writeBMP.data(pixelsXYC, resolutionX, resolutionY)
file:write(data)
end
return writeBMP
A simple test:
-- writeBMP example
local writeBMP = require "writeBMP"
local resolutionX = 100
local resolutionY = 100
-- Pixel data
local pixels = {}
for x=1,resolutionX do
pixels[x] = {}
for y=1, resolutionY do
pixels[x][y] = {}
local red = 255*(resolutionX-x+resolutionY-y)/(resolutionX+resolutionY)
local green = 255*y/resolutionY
local blue = 255*x/resolutionX
pixels[x][y][1] = red
pixels[x][y][2] = green
pixels[x][y][3] = blue
end
end
writeBMP.write(pixels,resolutionX,resolutionY,"testwritebmp.bmp")
return
Note: In BMP, the Y axis starts on the bottom. I am more used to Y axis going from top down in computer graphics (so I wrote it that way).
Thanks HAX for the code.
Welcome to Stack Exchange :)
I suggest having a look at PPM files, they are easy. They can be converted with other tools to png or bmp with other tools.
Wikipedia PPM Specification
Here is a PPM solution:
ResolutionX = 48
ResolutionY = 100
local cos, atan, sin, atan2, sqrt, floor = math.cos, math.atan, math.sin, math.atan2, math.sqrt, math.floor
local insert, concat = table.insert, table.concat
local sub, char, rep = string.sub, string.char, string.rep
local file = io.open("Test.ppm","w")
-- PPM File headers
local Output = { }
Output[1] = "P3"
Output[2] = tostring(ResolutionX) .. " " .. tostring(ResolutionY)
Output[3] = "255"
-- Image body
for Y = 0, ResolutionY - 1 do
for X = 0, ResolutionX - 1 do
local value = 255 * ((X + 1) % 2) * ((Y + 1) % 2)
Output[#Output+1] = rep(tostring(floor(value)),3," ")
end
end
-- Join lines together
local Result = table.concat(Output,"\n")
file:write(Result)
Notes: I could not get your code to write to file (see my usage of file). The inner loop must be X (columns) and the outer loop must be Y (rows) if the write order is English reading order (left-right down-up).
Related
Love2D trying to generate a chunk that has blocks inside it, but after moving a few chunks away it renders more chunks then intended
I have created a basic chunk generator, a chunk is area filled with squares, when the player moves a few blocks away from 0,0 it works correctly but after moving 4 chunks away it renders more then one chunk instead of one, I am not sure what I am doing wrong, I have given it a go changing some values, but I am left head scratching. here is the full code, you can copy and paste into VSCODE with love2D to see what happens. I think the main issue is somewhere around check_boarders function since that is what checks if the player is inside a chunk. function Key_input(key) if love.keyboard.isDown(key) then return 1 else return 0 end end function love.load() Camera = require "camera" Cam = Camera() Basic_Player = {} Basic_Player.X = 100 Basic_Player.Y = 100 Basic_Player.Speed = 15 Movement = {} end function love.update(dt) Movement.X = Key_input("d") - Key_input("a") Movement.Y = Key_input("s") - Key_input("w") Basic_Player.X = Basic_Player.X + Movement.X * Basic_Player.Speed Basic_Player.Y = Basic_Player.Y + Movement.Y * Basic_Player.Speed Cam:lookAt(Basic_Player.X,Basic_Player.Y) X, Y = Cam:position() -- Set cam position to global values end function love.draw() love.graphics.setBackgroundColor(0.5,0.5,0.9) Cam:attach() -- Renders the player and world inside its own scene generate_world(10,0) love.graphics.setColor( 0,0,1, 1 ) love.graphics.rectangle("fill",Basic_Player.X,Basic_Player.Y,30,30) love.graphics.setColor( 1,1,1, 1 ) Cam:detach() love.graphics.setColor( 1,0,0, 1 ) --Stays on the screen love.graphics.print(X .. " / " .. Y ,300,400) love.graphics.print(love.timer.getFPS( ) ,300,450) love.graphics.setColor( 1,1,1, 1 ) end function old_generate_world(_world_size, _seed) -- Before optimization local _chunk_size = 30 local _block_size = 30 for i = 0, _world_size - 1 do for f = 0, _world_size - 1 do local x_val = (_chunk_size * _block_size) * i -- Position value for actually building the chunks local y_val = (_chunk_size * _block_size) * f gen_chunk(_chunk_size,_block_size,_seed,{X = x_val ,Y = y_val }) end end end function generate_world(_world_size, _seed) local _chunk_size = 10 -- Chunk size width and height local _block_size = 30 -- block size inside the chunk for i = 0, _world_size - 1 do -- loop through world size for f = 0, _world_size - 1 do local x_val = (_chunk_size * _block_size) * i -- Position value for actually building the chunks local y_val = (_chunk_size * _block_size) * f local chunk_x_local_size = 0 -- To make sure we get a length for when i and f = 0 local chunk_y_local_size = 0 if i == 0 then -- To make sure the size of the chunk isnt zero chunk_x_local_size = _chunk_size * _block_size -- Get length of chunk when i = 0 else chunk_x_local_size = x_val end if f == 0 then -- ditto chunk_y_local_size = _chunk_size * _block_size else chunk_y_local_size = y_val end -- Checks if the player is inside a chunk if true draw it. if Check_boarders({X = X,Y = Y},{X = x_val,Y = y_val}, {X = chunk_x_local_size, Y = chunk_y_local_size}) then gen_chunk(_chunk_size,_block_size,_seed,{X = x_val ,Y = y_val }) -- Actually generate the chunk end love.graphics.setColor( 0,1,0, 1 ) love.graphics.rectangle("fill",x_val,y_val,15,15) love.graphics.setColor( 1,1,1, 1 ) end end end function Check_boarders(player_pos, boarder_pos, chunk_length) -- Checks player position is inside the boarder of the currently generated chunk if player_pos.X > boarder_pos.X and player_pos.X < boarder_pos.X + chunk_length.X then -- Check if the player is greater then top left and less then top right if player_pos.Y > boarder_pos.Y and player_pos.Y < boarder_pos.Y + chunk_length.Y then -- check if player is greater then top and less then bottom left return true end end return false end function gen_chunk(chunk_size,block_size,seed,position) -- chunk size is how many blocks inside the chunk, block size is self explain, seed n/a, pos starting chunk position for i = 0, chunk_size - 1 do for e = 0, chunk_size - 1 do -- loop until chunk size is met this is the amount of blocks being created love.graphics.rectangle("fill",position.X + i * block_size,position.Y + e * block_size,block_size - 1,block_size - 1) end end love.graphics.setColor( 1,0,0, 1 ) love.graphics.rectangle("fill",position.X ,position.Y,6,6) love.graphics.setColor( 1,1,1, 1 ) end You will need this camera.lua script just create it and paste this into it: local _PATH = (...):match('^(.*[%./])[^%.%/]+$') or '' local cos, sin = math.cos, math.sin local camera = {} camera.__index = camera -- Movement interpolators (for camera locking/windowing) camera.smooth = {} function camera.smooth.none() return function(dx,dy) return dx,dy end end function camera.smooth.linear(speed) assert(type(speed) == "number", "Invalid parameter: speed = "..tostring(speed)) return function(dx,dy, s) -- normalize direction local d = math.sqrt(dx*dx+dy*dy) local dts = math.min((s or speed) * love.timer.getDelta(), d) -- prevent overshooting the goal if d > 0 then dx,dy = dx/d, dy/d end return dx*dts, dy*dts end end function camera.smooth.damped(stiffness) assert(type(stiffness) == "number", "Invalid parameter: stiffness = "..tostring(stiffness)) return function(dx,dy, s) local dts = love.timer.getDelta() * (s or stiffness) return dx*dts, dy*dts end end local function new(x,y, zoom, rot, smoother) x,y = x or love.graphics.getWidth()/2, y or love.graphics.getHeight()/2 zoom = zoom or 1 rot = rot or 0 smoother = smoother or camera.smooth.none() -- for locking, see below return setmetatable({x = x, y = y, scale = zoom, rot = rot, smoother = smoother}, camera) end function camera:lookAt(x,y) self.x, self.y = x, y return self end function camera:move(dx,dy) self.x, self.y = self.x + dx, self.y + dy return self end function camera:position() return self.x, self.y end function camera:rotate(phi) self.rot = self.rot + phi return self end function camera:rotateTo(phi) self.rot = phi return self end function camera:zoom(mul) self.scale = self.scale * mul return self end function camera:zoomTo(zoom) self.scale = zoom return self end function camera:attach(x,y,w,h, noclip) x,y = x or 0, y or 0 w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight() self._sx,self._sy,self._sw,self._sh = love.graphics.getScissor() if not noclip then love.graphics.setScissor(x,y,w,h) end local cx,cy = x+w/2, y+h/2 love.graphics.push() love.graphics.translate(cx, cy) love.graphics.scale(self.scale) love.graphics.rotate(self.rot) love.graphics.translate(-self.x, -self.y) end function camera:detach() love.graphics.pop() love.graphics.setScissor(self._sx,self._sy,self._sw,self._sh) end function camera:draw(...) local x,y,w,h,noclip,func local nargs = select("#", ...) if nargs == 1 then func = ... elseif nargs == 5 then x,y,w,h,func = ... elseif nargs == 6 then x,y,w,h,noclip,func = ... else error("Invalid arguments to camera:draw()") end self:attach(x,y,w,h,noclip) func() self:detach() end -- world coordinates to camera coordinates function camera:cameraCoords(x,y, ox,oy,w,h) ox, oy = ox or 0, oy or 0 w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight() -- x,y = ((x,y) - (self.x, self.y)):rotated(self.rot) * self.scale + center local c,s = cos(self.rot), sin(self.rot) x,y = x - self.x, y - self.y x,y = c*x - s*y, s*x + c*y return x*self.scale + w/2 + ox, y*self.scale + h/2 + oy end -- camera coordinates to world coordinates function camera:worldCoords(x,y, ox,oy,w,h) ox, oy = ox or 0, oy or 0 w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight() -- x,y = (((x,y) - center) / self.scale):rotated(-self.rot) + (self.x,self.y) local c,s = cos(-self.rot), sin(-self.rot) x,y = (x - w/2 - ox) / self.scale, (y - h/2 - oy) / self.scale x,y = c*x - s*y, s*x + c*y return x+self.x, y+self.y end function camera:mousePosition(ox,oy,w,h) local mx,my = love.mouse.getPosition() return self:worldCoords(mx,my, ox,oy,w,h) end -- camera scrolling utilities function camera:lockX(x, smoother, ...) local dx, dy = (smoother or self.smoother)(x - self.x, self.y, ...) self.x = self.x + dx return self end function camera:lockY(y, smoother, ...) local dx, dy = (smoother or self.smoother)(self.x, y - self.y, ...) self.y = self.y + dy return self end function camera:lockPosition(x,y, smoother, ...) return self:move((smoother or self.smoother)(x - self.x, y - self.y, ...)) end function camera:lockWindow(x, y, x_min, x_max, y_min, y_max, smoother, ...) -- figure out displacement in camera coordinates x,y = self:cameraCoords(x,y) local dx, dy = 0,0 if x < x_min then dx = x - x_min elseif x > x_max then dx = x - x_max end if y < y_min then dy = y - y_min elseif y > y_max then dy = y - y_max end -- transform displacement to movement in world coordinates local c,s = cos(-self.rot), sin(-self.rot) dx,dy = (c*dx - s*dy) / self.scale, (s*dx + c*dy) / self.scale -- move self:move((smoother or self.smoother)(dx,dy,...)) end -- the module return setmetatable({new = new, smooth = camera.smooth}, {__call = function(_, ...) return new(...) end})
Check Collision Between Ball And Array Of Bricks
Since I have a collision check function in Lua: function onCollision(obj1,obj2) obj1x = obj1.left obj1y = obj1.top obj1w = obj1.width obj1h = obj1.height obj2x = obj2.left obj2y = obj2.top obj2w = obj2.width obj2h = obj2.height if obj2x + obj2w >= obj1x and obj2y + obj2h >= obj1y and obj2y <= obj1y + obj1h and obj2x <= obj1x + obj1w then return true end end And I did make some panels as bricks using array table on my form, with this function, I did collision check between ball with each form sides without problems. function createBricks() for row = 1, brickRows do bricks[row] = {} for col = 1, brickColumns do local x = (col - 1) * (width + gap) -- x offset local y = (row - 1) * (height + gap) -- y offset local newBrick = createPanel(gamePanel) newBrick.width = brickWidth newBrick.height = brickHeight newBrick.top = y + 15 newBrick.left = x + 15 newBrick.BorderStyle = 'bsNone' if level == 1 then newBrick.color = '65407' -- green elseif level == 2 then newBrick.color = '858083' -- red elseif level == 3 then newBrick.color = '9125192' -- brown elseif level == 4 then newBrick.color = math.random(8,65255) end bricks[row][col] = newBrick end end end Next how to detect if the ball collided with the bricks?. So far I did: for row = 1, brickRows do bricks[row] = {} for col = 1, brickColumns do dBrick = bricks[row][col] if onCollision(gameBall,dBrick) then dBrick.destroy() -- destroy the collided brick end end end I want to learn how to implement this collision logic in VB Net script which VB script easier for me, I did the whole game project using VB Net, now I try to re-write the project using CE Lua. Private brickArray(brickRows, brickColumns) As Rectangle Private isBrickEnabled(brickRows, brickColumns) As Boolean For rows As Integer = 0 To brickRows For columns As Integer = 0 To brickColumns If Not isBrickEnabled(rows, columns) Then Continue For If gameBall.IntersectsWith(brickArray(rows, columns)) Then isBrickEnabled(rows, columns) = False If gameBall.X + 10 < brickArray(rows, columns).X Or _ gameBall.X > brickArray(rows, columns).X + brickArray(rows, columns).Width _ Then xVel = -xVel Else yVel = -yVel End If End If Next Next And also this private sub, how to write it CE Lua? Sub loadBricks() Dim xOffset As Integer = 75, yOffset As Integer = 100 For row As Integer = 0 To brickRows For column As Integer = 0 To brickColumns brickArray(row, column) = New Rectangle(xOffset, yOffset, brickWidth, brickHeight) xOffset += brickWidth + 10 isBrickEnabled(row, column) = True Next yOffset += brickHeight + 10 xOffset = 75 Next End Sub Function getBrickCount() As Integer Dim Count As Integer = 0 For Each brick As Boolean In isBrickEnabled If brick = True Then Count += 1 Next Return Count End Function
function onCollision(obj1,obj2) obj1x = obj1.left obj1y = obj1.top obj1w = obj1.width obj1h = obj1.height obj2x = obj2.left obj2y = obj2.top obj2w = obj2.width obj2h = obj2.height if obj2x + obj2w >= obj1x and obj2y + obj2h >= obj1y and obj2y <= obj1y + obj1h and obj2x <= obj1x + obj1w then return true end end Then to detect collision the collision and remove from the table: -- Drawback table local function tcount( t ) local c = 0 for k,v in pairs(t) do c = c + 1 end return c end local count = #brickArray for x = 1, count do if onCollision(gameBall, brickArray[x]) then if gameBall.Left + 10 < brickArray[x].Left or gameBall.Left > brickArray[x].Left + brickArray[x].Width then xVel = -xVel else yVel = -yVel end playSound(findTableFile('strikeball.wav')) brickArray[x] = brickArray[count] brickArray[x] = x brickArray[count] = nil brickArray[x].Visible = false tcount(brickArray) end end The code above detected the collision and remove the object from the table, but that is not removed from display. How to remove the bricks from the table and display, using Cheat Engine Lua script?.
Is it possible to change multiple values, by different amounts concurrently?
I'm trying to resize and relocate an object, by changing the x, y and area values, all at the same time. I can do them one after another by running 3 separate for loops, but the animation needs to be smooth and as one. I tried nesting another for loop inside the function but that provides the same result as 1 loop has to finish before the next one starts. The only way I can find to complete it is to make 3 separate scripts and run all 3 at the same time. SSxPOSA = 0.00 SSxPOSB = -12.00 SSyPOSA = 0.00 SSyPOSB = -6.55 SSsizeA = 1.00 SSsizeB = 0.2 function SSBox1X() for i = SSxPOSA, SSxPOSB, 0.1 do Object1X( i ); end; end; function SSBox1Y() for i = SSyPOSA, SSyPOSB, 0.5 do Object1Y( i ); end; end; function SSBox1Scale() for i = SSsizeA, SSsizeB, 0.8 do Object1Scale( i ); end; end; SSBox1X(); SSBox1Y(); SSBox1Scale(); Happy to read and learn best practice
If I understood your problem correctly, something like this should work: function xys() local x, y, s = SSxPOSA, SSyPOSA, SSsizeA return coroutine.wrap( function() while x >= SSxPOSB and y >= SSyPOSB and s >= SSsizeB do coroutine.yield(x,y,s) x = x - 0.1 y = y - 0.5 s = s - 0.8 end end) end SSxPOSA = 0.00 SSxPOSB = -12.00 SSyPOSA = 0.00 SSyPOSB = -6.55 SSsizeA = 1.00 SSsizeB = 0.2 for x,y,s in xys() do print(x,y,s) --Object1X(x) --Object1Y(y) --Object1Scale(s) end And, because of floating point comparison not always yielding the expected result, it's probably better to convert to integers and divide just before using. Like so: function xys() local x, y, s = SSxPOSA, SSyPOSA, SSsizeA return coroutine.wrap( function() while x >= SSxPOSB and y >= SSyPOSB and s >= SSsizeB do coroutine.yield(x/100,y/100,s/100) x = x - 10 y = y - 50 s = s - 80 end end) end SSxPOSA = 0 SSxPOSB = -1200 SSyPOSA = 0 SSyPOSB = -655 SSsizeA = 100 SSsizeB = 20 for x,y,s in xys() do print(x,y,s) --Object1X(x) --Object1Y(y) --Object1Scale(s) end You can also do it without coroutines: function xys() local x, y, s = SSxPOSA, SSyPOSA, SSsizeA return function() if x < SSxPOSB or y < SSyPOSB or s < SSsizeB then return end local xx, yy, ss = x/100, y/100, s/100 x = x - 10 y = y - 50 s = s - 80 return xx,yy,ss end end
Table value doesn't change
I have a 2 dim array and all it's cells filled with zeros. What i'm trying to do is to take some randomly chosen cells and fill it with 4 or 5 but what i get is either empty gird with all value equal to zero or i get just one value that has changed to 4 or 5 and that's my code below: local grid = {} for i=1,10 do grid[i] = {} for j=1,10 do grid[i][j] = 0 end end local empty={} for i=1,10 do for j=1,10 do if grid[i][j]==0 then table.insert(empty,i ..'-'.. j) end end end local fp=math.floor(table.maxn(empty)/3) local fx,fy for i=1,fp do math.randomseed(os.time()) math.random(0,1) local fo=math.random(0,1) math.random(table.maxn(empty)) local temp= empty[math.random(table.maxn(empty))] local dashindex=string.find(temp,'-') fx=tonumber(string.sub(temp,1,dashindex-1)) fy=tonumber(string.sub(temp,dashindex+1,string.len(temp))) if fo==0 then grid[fx][fy]=4 elseif fo==1 then grid[fx][fy]=5 end end for i=1,10 do for j=1,10 do print(grid[i][j]) end print('\n') end
I'm not sure what the for i=1,fp loop is doing with temp and fo, for example the seed should only be set once, and also, the return value on line after local fo is ignored, seems very messy. But based on your post, if you really just want to randomly select N cells from your 2D array and set those to either 4 or 5 (randomly), this should work: -- maybe N = fp local N = 5 math.randomseed(os.time()) local i = 1 repeat fx = math.random(1, 10) fy = math.random(1, 10) if grid[fx][fy] == 0 then grid[fx][fy] = math.random(4,5) i = i + 1 end until i > N Note however that the closer N is to number of items in array (100 in your example), the longer it will take for the loop to complete. If this is a concern, then for large N values, you could do the opposite: initialize each cell to 4 or 5 randomly, and then randomly set size - N of them to 0. math.randomseed(os.time()) local rows = 10 local columns = 10 local grid = {} if N > rows*columns/2 then for i=1,rows do grid[i] = {} for j=1,columns do grid[i][j] = math.random(4,5) end end local i = 1 repeat fx = math.random(1, 10) fy = math.random(1, 10) if grid[fx][fy] ~= 0 then grid[fx][fy] = 0 i = i + 1 end until i > N else for i=1,rows do grid[i] = {} for j=1,columns do grid[i][j] = 0 end end local i = 1 repeat fx = math.random(1, 10) fy = math.random(1, 10) if grid[fx][fy] == 0 then grid[fx][fy] = math.random(4,5) i = i + 1 end until i > N end
Getting differen coordinates in lua
I have this code: local function createBlocks() local rowcount = 8 local colcount = 4 local blockWidth = display.contentWidth / (colcount*4) local blockHeight = display.contentWidth / (rowcount*2) local row local col local pan = 3 local i=0 for row = 1, rowcount do for col = 1, colcount do local x = (col - 1) * blockWidth + pan local y = (row + 1) * blockHeight + pan local random= math.random(1,6) random = revisarTres(i, random) print (random) print ("primeras") print (x) print (y) block[i] = display.newImage(images[random], x, y) block[i].value= random block[i]:addEventListener("touch", blockTouch) i=i+1 end end print ("coordenadas") for i=0,31 do print (i) print (block[i].x) print (block[i].y) end end Why I get a differen x and y value? print (block[i].x) print (x) print (block[i].y) print (y) Hope you can help me, I'm new with lua and I have been stuck here a long time. Thank you
Try this: local image = display.newImage(images[random], 0, 0) image.x = x image.y = y image.value = random image:addEventListener("touch", blockTouch) block[i] = image