Related
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})
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).
Im attempting to make a simple game app and keep running into this problem. I stopped programming in Lua for a few years so I don't exactly remember how to fix this. Anyway, my code is as follows:
EDIT: Here is the entire file. Still trying to figure out the formatting of Stack Overflow. Error occurs at line 76.
module(..., package.seeall)
-- Main function - MUST return a display.newGroup()
function new()
local localGroup = display.newGroup()
---------
local Rad = math.rad
local Sin = math.sin
local Cos = math.cos
local Pi = math.pi
local Atan2 = math.atan2
local radD = 180 / Pi
local DegR = Pi / 180
local touchPoint = display.newCircle(localGroup, -50, -50, 20)
touchPoint.isFocus = false
touchPoint.alpha = 0
function GetDistanceFromObjects(obj1, obj2)
local xDist = obj1.x - obj2.x
local yDist = obj1.y - obj2.y
local dist = Sqrt((xDist * xDist) + (yDist * yDist))
return dist
end
function getAngleDeg(inX1, inY1, inX2, inY2)
local xDist = inX2 - inX1
local yDist = inY2 - inY1
local angRad = Atan2(yDist, xDist)
return angRad * radD + 90
end
require "sprite"
function VectorFromAngle(inAngle, inVelocity)
local vx = Cos(Rad(inAngle-90))
local vy = Sin(Rad(inAngle-90))
if(inVelocity ~= nil)then
vx = vx * inVelocity
vy = vy * inVelocity
end
return vx,vy
end
require ( "physics" )
physics.start()
physics.setGravity( 1, 1 )
--( x, y )
--physics.setDrawMode ( "hybrid" )
math.randomseed(os.time())
local background = display.newImage("yazd.jpeg")
localGroup:insert(background)
--width of image divided by # of pics lined up from left to right (in the sprite) = the first #
--height of image divided by # of pics lined up from top to bottom (in the sprite) = the second #
local birdSheet = sprite.newSpriteSheet( "enemy.jpg", 59, 50 )
local birdSet = sprite.newSpriteSet(birdSheet, 1, 1)
-- images 1-14
sprite.add( birdSet, "bird", 1, 1, 200, 0 )
-- play 1-14, each image every 200 ms, 0 = loop count, which is infinite
local bird1 = sprite.newSprite( birdSet )
bird1.x = 40 -- starting point
bird1.y = 40 -- starting point
bird1.xScale = 0.5 --scale down x
bird1.yScale = 0.5 --scale down y
bird1:prepare("bird") --prepare sprite sequence
bird1:play() --play sprite
localGroup:insert(bird1)
--only local to this group
local killSheet = sprite.newSpriteSheet("explosion.png", 100, 100)
local killSet = sprite.newSpriteSet(killSheet, 1, 9)
sprite.add(killSet, "kill", 1, 9, 200, 1)
local birdCount = 1
local transDirection12
local function transDirection1()
bird1.xScale = 0.5
transition.to(bird1, {time=math.random(200,500), x = math.random(200,490), y = math.random(10,310), alpha = (math.random(9,100))/100, onComplete = transDirection12})
end
transDirection12 = function()
bird1.xScale = 0.5
transition.to(bird1, {time= math.random(200,500), x = math.random(200,490), y = math.random(10,310), alpha = (math.random(9,100))/100, onComplete = transDirection1})
end
transDirection1()
-- local transDirection1 declares what will be used (local function)
-- transDirection1 = function
-- following it are the function qualities
-- declares it will use object/image called bird1 and scales it to .5
-- time = ____ means it will take a certain time, between ____ and ____ to complete the transition
-- x=____ means that is where it will move to on the x axis
-- y=____ means that is where it will move to on the y axis
-- alpha = ___ means the is how transparent it will be
-- onComplete = ________ means that when the action is complete, it will call another function
-- The next function has the same qualities as transDirection1, but the onComplete part calls transDirection1 and they continue to loop
-- transDirection1() declares transDirection1 so the app knows about it and can use it
-- the other trans do not need to be declared because they are part of transDirection1, which is already declared
--(x, y, size.x, size.y)
local player = display.newImage( "mk11.png" )
player.x = 240
player.y = 260
player.xScale = .5
player.yScale = .5
localGroup:insert( player )
-- add physics to all the objects wanted: (object wanted, "static" or "dynamic")
physics.addBody(player, "static", {radius=30, isSensor = true})
physics.addBody(bird1, "static", {radius=23})
local function shoot(inPointX, inPointY)
-- (start at the x of the player + 10, also start at the y of the player, the radius of the circle is 5)
local bullet = display.newImage( "bullet2.png" )
bullet.x = player.x
bullet.y = player.y
-- add physics to the object, which is the bullet.
-- Make the bullet "dynamic" or moving
physics.addBody(bullet, "dynamic")
bullet.isFixedRotation = true
localGroup:insert( bullet )
local velocity = 300
local vx, vy = VectorFromAngle(player.rotation, velocity)
bullet.rotation = player.rotation
bullet:setLinearVelocity(vx, vy)
end
function RotateToTouchPoint(inPointX, inPointY)
local ang = getAngleDeg(player.x, player.y, inPointX, inPointY)
player.rotation = ang
end
local function ScreenTouchListener(event)
local phase = event.phase
if(phase == "began")then
if(touchPoint.isFocus == false)then
touchPoint.alpha = 1
touchPoint.x = event.x
touchPoint.y = event.y
display.getCurrentStage():setFocus(touchPoint, event.id)
touchPoint.isFocus = true
RotateToTouchPoint(event.x, event.y)
shoot(event.x, event.y)
end
elseif(touchPoint.isFocus)then
if(phase == "moved")then
touchPoint.x = event.x
touchPoint.y = event.y
RotateToTouchPoint(event.x, event.y)
elseif(phase == "ended" or phase == "cancelled")then
display.getCurrentStage():setFocus(touchPoint, nil)
touchPoint.isFocus = false
touchPoint.alpha = 0
end
end
return true
end
local function gotShot (event)
event.target:removeSelf()
event.other:removeSelf()
local explosion = sprite.newSprite(killSet)
explosion.x, explosion.y = event.target.x, event.target.y
explosion:prepare("kill")
explosion:play()
localGroup:insert( explosion )
birdCount = birdCount - 1
-- when there are no more birds, remove the runtime event listener and perform the
-- function with a delay of 500 m.s. The function changes the scene to test.lua
if "ended" then
if birdCount == 0 then
Runtime:removeEventListener("touch", ScreenTouchListener)
timer.performWithDelay(500, function()
director:changeScene("mainPage") end, 1)
end
end
end
bird1:addEventListener("collision", gotShot)
Runtime:addEventListener("touch", ScreenTouchListener)
---------
-- MUST return a display.newGroup()
return localGroup
end
Any help is appreciated!
The error message is perfectly clear -- the variable sprite used at this line:
local bird1 = sprite.birdSheet( birdSet )
has a nil value, meaning it has not been initialized or was set to nil. You need to show the earlier code where you should have set it up.
(After OP updates)
I think this line
require "sprite"
should actually be
sprite = require "sprite"
You can read more in modules tutorial here:
http://lua-users.org/wiki/ModulesTutorial
I need some help understanding how would I reset the score of numMiss, numHit, and numPercent back to 0 as soon as I tap the "reset.png" button and while doing so will also start the game from the beginning again.
Also, let me know if there are any corrections to be made within my code.
Heres what I have of the code so far
--width and height
WIDTH = display.contentWidth --320
HEIGHT = display.contentHeight --480
--display background
local p = display.newImageRect("park.png" ,500, 570)
p.x = WIDTH/2
p.y = HEIGHT/2
--display bouncing dog
local RADIUS = 5
local d = display.newImageRect("dogeball.png", 70, 70)
d.x = 50
d.y = 100
--display treat
local t = display.newImageRect("treat.png", 50, 50)
t.x = 245
t.y = math.random(HEIGHT)
--displays the reset button
local r = display.newImageRect("reset.png", 100,100)
r.x = 280
r.y = 480
--starting value of gravity and bounce(will change)
local GRAVITY = 0.3
local BOUNCE = 0.75
--downward force
local velocity = 0
--Tells the score to reset when true
local reset = false
--shows number of hits
local numHit = 0
--shows number of misses
local numMiss = 0
--Gets Percentage score
local numPercent = 0
--make hits and misses display
scoreHits = display.newText("Hits = " .. numHit, WIDTH/7, 1, native.systemFont, 18)
scoreMisses = display.newText("Misses = " .. numMiss, WIDTH/2.1, 1, native.systemFont, 18)
scorePercent = display.newText("Hit % = " .. numPercent, WIDTH/1.2, 1, native.systemFont, 18)
function enterFrame()
d.y = d.y + velocity
velocity = velocity + GRAVITY
local HIT_SLOP = RADIUS * 8 -- Adjust this to adjust game difficulty
if math.abs(t.x - d.x) <= HIT_SLOP
and math.abs(t.y - d.y) <= HIT_SLOP then
numHit = numHit + 1
scoreHits.text = "Hits = " .. numHit
--count 1 hit once dog and treat hit eachother
if (t.x - d.x) <= HIT_SLOP and (t.y - d.y) <= HIT_SLOP then
t.x = 400 --resets treat postioning
t.y = math.random(HEIGHT) --gives treat a random y coordinate
end
end
--puts the barrier at the bottom of the screen and tells dog to bounce from there
if (d.y > HEIGHT) then
d.y = HEIGHT
velocity = -velocity * BOUNCE
end
t.x = t.x - 5 --speed treat goes
if t.x < -350 then--position of the treat
t.x = 400
scoreMisses.text = "Misses = " .. numMiss
else if t.x < -100 then
t.y = math.random(HEIGHT) --random height after treat goes past dog
else if t.x < -99 then
numMiss = numMiss + 1 --calculates misses when goes past screen
scoreMisses.text = "Misses = " .. numMiss
end
end
end
--calculate percentage hits
numPercent = 100 * numHit / (numHit + numMiss)
scorePercent.text = "Hit % = " .. math.round(numPercent) --prints and rounds percentage
function tapped(event) --when tapped on reset, score gets reset
--reset function goes here
end
end
r:addEventListener( "tap", tapped )
end
function touched(event)
-- print(event.phase)
if event.phase == "began" then
velocity = velocity - 6 -- thrusts dog
end
return true
end
Runtime:addEventListener( "enterFrame" , enterFrame )
Runtime:addEventListener( "touch", touched )
To make your image a button you need to add an event listener that responds to touch or tap events.
see http://docs.coronalabs.com/api/event/touch/index.html
Or you use the widget library which gives you the possibility to use a blank button background and set only the label for each button what will be very handy when you include translations for other languages.
see http://docs.coronalabs.com/api/library/widget/newButton.html
In my game I have a function gameInit() that sets the hole game and all variables. This function is called when the game starts and also when the player wants to do a reset as it over writes the old variables. (there are other technics, depending on the complexity of your game and if you for example want to store the game settings for the next time the player starts the game)
How can i limit the movement on a accelerometer onTilt Events to 30 pixels left, right, up, down. This code allows it to move on accelerometer tilt but there is no limit on the movement distance.
local screenGroup = self.view
local bg2 = display.newImage ("bg2.png")
bg2.x = display.contentWidth / 2;
bg2.y = 200
local tiltSpeed = 30;
local motionx = 0;
local motiony = 0;
local rotation = 0;
delta = -50/180*math.pi
cos_delta, sin_delta = math.cos(delta), math.sin(delta)
local function onTilt(event)
motionx = tiltSpeed * event.xGravity
motiony = tiltSpeed * (cos_delta*event.yGravity + sin_delta*event.zGravity)
end
local function moveBg2 (event)
bg2.x = motionx + bg2.x ;
bg2.y = bg2.y - motiony;
end
Runtime:addEventListener("enterFrame", moveBg2)
Runtime:addEventListener("accelerometer", onTilt)
The question is not super clear, but I guess this could do:
local function onTilt(event)
motionx = tiltSpeed * event.xGravity
motiony = tiltSpeed * (cos_delta*event.yGravity + sin_delta*event.zGravity)
if motionx < -30 then
motionx = -30
elseif motionx > 30 then
motionx = 30
end
if motiony < -30 then
motiony = -30
elseif motiony > 30 then
motiony = 30
end
end