LUA - LÖVE 2D - Sprite dying when hitting a box - lua

--Okay, basically I've set up pretty much everything i want in the game. All i have to do now is create the enemies. I've set up the spawning and movement but when the player hits the enemies, nothing happens. When the red ball hits the blocks i'd like the client to close. (i will obviously change this at a later date but its only temporary) I'd be very grateful if you could program the code that would interpret this within the game. I'm new to this programming language and I'm only 15 still learning how to code. I am more than happy to give you credit in the game.
Thank you - Olee
function love.load()
love.graphics.setBackgroundColor( 110, 110, 110 ) --Sets background colour
love.graphics.rectangle("fill",400,300,0,230,230) --Draws game background
print("Olee's Game") -- prints into the console
x=140 --x position of sprite
y=320 --y position of the sprite
swidth=20 --sprite width
sheight=20 --sprite height
evil=900 --red rectangular blocks x position
evilheight=64 --red rectangular block height
evilwidth=256 --red rectangular block width
points=0 --point system created variable
random1y=math.random(120,480) --creates y position of the first enemy block
random2y=math.random(120,480) --creates y position of the block
random3y=math.random(120,480) --creates y position of the block
random4y=math.random(120,480) --creates y position of the block
random5y=math.random(120,480) --creates y position of the block
random6y=math.random(120,480) --creates y position of the block
end
function love.update(dt)
--BOUNDRIES--(makes the sprite not go off the page)
if y<120 then
y=y+20
end
if y>520 then
y=y-20
end
if x<20 then
x=x+20
end
if x>780 then
x=x-20
end
--AI (sends the blocks back to the start)
evil=evil-400*dt
if evil<=(-400) then
evil=1100
random1y=math.random(120,480)
random2y=math.random(120,480)
random3y=math.random(120,480)
random4y=math.random(120,480)
random5y=math.random(120,480)
random6y=math.random(120,480)
end
--Points
points = love.timer.getTime()
points=math.floor(points)
end
function love.focus(bool)
end
function love.keypressed( key, unicode )
print("You just pressed "..key)
print("x="..x.."\ny="..y.."\n#########")
if key=="escape"then
print("Bye!")
os.exit(0)
end
if key == "down" then
y=y+20
end
if key == "left" then --A KEY (LEFT)
x=x-20
end
if key == "right" then --D KEY (RIGHT)
x=x+20
end
if key == "up" then --W KEY (UP)
y=y-20
end
end
function love.draw()
--Floor
love.graphics.setColor(127, 127, 127)
love.graphics.rectangle("fill",0,540,5000,100)
--Ceiling
love.graphics.setColor(127, 127, 127)
love.graphics.rectangle("fill", 0, 0, 5000, 100)
--Welcome Message
love.graphics.setColor(191, 0, 52)
love.graphics.print("Bonjourno and Welcome to Olee's Game",32,32,0,1,1)
--Welcome Message HUD Box
love.graphics.setColor(191, 0, 52)
love.graphics.rectangle("line",16,18,284,48)
--Circle (sprite)
love.graphics.setColor(191, 0, 52)
love.graphics.circle("fill",x,y,swidth,sheight)
--SCOREBOARD
love.graphics.setColor(191, 0, 52)
love.graphics.print("Score: "..points.."",620, 35)
--Evil 1
love.graphics.setColor(191, 0, 52)
love.graphics.rectangle("fill",evil,random1y,evilwidth,evilheight)
--Evil 2
love.graphics.setColor(191, 0, 52)
love.graphics.rectangle("fill",evil,random2y,evilwidth,evilheight)
--Evil 3
love.graphics.setColor(191, 0, 52)
love.graphics.rectangle("fill",evil,random3y,evilwidth,evilheight)
--Evil 4
love.graphics.setColor(191, 0, 52)
love.graphics.rectangle("fill",evil,random4y,evilwidth,evilheight)
--Evil 5
love.graphics.setColor(191, 0, 52)
love.graphics.rectangle("fill",evil,random5y,evilwidth,evilheight)
--Evil 6
love.graphics.setColor(191, 0, 52)
love.graphics.rectangle("fill",evil,random6y,evilwidth,evilheight)
--FPS
love.graphics.print("FPS: "..tostring(love.timer.getFPS( )), 735, 5)
end
function love.quit()
end
Just to let you guys know, I HAVE set up a conf.lua file. My game works perfectly but i would like to add this! :)
and i have a play.bat
conf.lua:
function love.conf(t)
t.modules.joystick = true -- Enable the joystick module (boolean)
t.modules.audio = true -- Enable the audio module (boolean)
t.modules.keyboard = true -- Enable the keyboard module (boolean)
t.modules.event = true -- Enable the event module (boolean)
t.modules.image = true -- Enable the image module (boolean)
t.modules.graphics = true -- Enable the graphics module (boolean)
t.modules.timer = true -- Enable the timer module (boolean)
t.modules.mouse = true -- Enable the mouse module (boolean)
t.modules.sound = true -- Enable the sound module (boolean)
t.modules.timer = true -- Enable the timer module (boolean)
t.modules.thread = true
t.modules.math = true -- Enable the math module (boolean)
t.modules.physics = true -- Enable the physics module (boolean)
t.console = true -- Attach a console (boolean, Windows only)
t.title = "Olee's Game" -- The title of the window the game is in (string)
t.author = "Olee" -- The author of the game (string)
t.screen.fullscreen = false -- Enable fullscreen (boolean)
t.screen.vsync = false -- Enable vertical sync (boolean)
t.screen.fsaa = 0 -- The number of FSAA-buffers (number)
t.screen.height = 600 -- The window height (number)
t.screen.width = 800 -- The window width (number)
end
play.bat:
#ECHO OFF
start "" "C:\Program Files (x86)\LOVE\love.exe" .

Well, you have two approaches here:
You can do advanced collision
You can do simple collision.
The second is simpler, but the first is much better for this sort of game.
First approach:
First, you need to know this code:
function circleAndRectangleOverlap( circleX, circleY, circleRadius, rectangleX, rectangleY, rectangleWidth, rectangleHeight )
local distanceX = math.abs( circleX - rectangleX - rectangleWidth / 2 )
local distanceY = math.abs( circleY - rectangleY - rectangleHeight / 2 )
if distanceX > ( rectangleWidth / 2 + circleRadius ) or distanceY > ( rectangleHeight /2 + circleRadius ) then
return false
elseif distanceX <= ( rectangleWidth / 2 ) or distanceY <= ( rectangleHeight / 2 ) then
return true
end
return ( math.pow( distanceX - rectangleWidth / 2, 2 ) + math.pow( distanceY - rectangleHeight / 2, 2 ) ) <= math.pow( circleRadius, 2 )
end
Then you can add this to the rest of this code.
function love.load()
love.graphics.setBackgroundColor( 110, 110, 110 ) --Sets background colour
love.graphics.rectangle("fill",400,300,0,230,230) --Draws game background
print("Olee's Game") -- prints into the console
x=140 --x position of sprite
y=320 --y position of the sprite
sradius=20 --sprite radius
evil=900 --red rectangular blocks x position
evilheight=64 --red rectangular block height
evilwidth=256 --red rectangular block width
points=0 --point system created variable
random1y=math.random(120,480) --creates y position of the first enemy block
random2y=math.random(120,480) --creates y position of the block
random3y=math.random(120,480) --creates y position of the block
random4y=math.random(120,480) --creates y position of the block
random5y=math.random(120,480) --creates y position of the block
random6y=math.random(120,480) --creates y position of the block
end
function love.update(dt)
--BOUNDRIES--(makes the sprite not go off the page)
if y<120 then
y=y+20
end
if y>520 then
y=y-20
end
if x<20 then
x=x+20
end
if x>780 then
x=x-20
end
--AI (sends the blocks back to the start)
evil=evil-400*dt
if evil<=(-400) then
evil=1100
random1y=math.random(120,480)
random2y=math.random(120,480)
random3y=math.random(120,480)
random4y=math.random(120,480)
random5y=math.random(120,480)
random6y=math.random(120,480)
end
--Points
points = love.timer.getTime()
points=math.floor(points)
-- Check collisions
if circleAndRectangleOverlap( x, y, sradius, evil, random1y, evilwidth, evilheight )
or circleAndRectangleOverlap( x, y, sradius, evil, random2y, evilwidth, evilheight )
or circleAndRectangleOverlap( x, y, sradius, evil, random3y, evilwidth, evilheight )
or circleAndRectangleOverlap( x, y, sradius, evil, random4y, evilwidth, evilheight )
or circleAndRectangleOverlap( x, y, sradius, evil, random5y, evilwidth, evilheight )
or circleAndRectangleOverlap( x, y, sradius, evil, random6y, evilwidth, evilheight ) then
love.event.quit()
end
end
function love.focus(bool)
end
function love.keypressed( key, unicode )
print("You just pressed "..key)
print("x="..x.."\ny="..y.."\n#########")
if key=="escape"then
print("Bye!")
love.event.quit()
end
if key == "down" then
y=y+20
end
if key == "left" then --A KEY (LEFT)
x=x-20
end
if key == "right" then --D KEY (RIGHT)
x=x+20
end
if key == "up" then --W KEY (UP)
y=y-20
end
end
function love.draw()
--Floor
love.graphics.setColor(127, 127, 127)
love.graphics.rectangle("fill",0,540,5000,100)
--Ceiling
love.graphics.setColor(127, 127, 127)
love.graphics.rectangle("fill", 0, 0, 5000, 100)
--Welcome Message
love.graphics.setColor(191, 0, 52)
love.graphics.print("Bonjourno and Welcome to Olee's Game",32,32,0,1,1)
--Welcome Message HUD Box
love.graphics.setColor(191, 0, 52)
love.graphics.rectangle("line",16,18,284,48)
--Circle (sprite)
love.graphics.setColor(191, 0, 52)
love.graphics.circle("fill",x,y,sradius)
--SCOREBOARD
love.graphics.setColor(191, 0, 52)
love.graphics.print("Score: "..points.."",620, 35)
--Evil 1
love.graphics.setColor(191, 0, 52)
love.graphics.rectangle("fill",evil,random1y,evilwidth,evilheight)
--Evil 2
love.graphics.setColor(191, 0, 52)
love.graphics.rectangle("fill",evil,random2y,evilwidth,evilheight)
--Evil 3
love.graphics.setColor(191, 0, 52)
love.graphics.rectangle("fill",evil,random3y,evilwidth,evilheight)
--Evil 4
love.graphics.setColor(191, 0, 52)
love.graphics.rectangle("fill",evil,random4y,evilwidth,evilheight)
--Evil 5
love.graphics.setColor(191, 0, 52)
love.graphics.rectangle("fill",evil,random5y,evilwidth,evilheight)
--Evil 6
love.graphics.setColor(191, 0, 52)
love.graphics.rectangle("fill",evil,random6y,evilwidth,evilheight)
--FPS
love.graphics.print("FPS: "..tostring(love.timer.getFPS( )), 735, 5)
end
function love.quit()
end
Second Approach
This uses the AABB aproach, which will be more useful if you use actual sprites in the future.
Just plug this in for the circleAndRectangleOverlap with this (and width and height arguments instead of radius):
function checkAABB( spriteX, spriteY, spriteWidth, spriteHeight, rectangleX, rectangleY, rectangleWidth, rectangleHeight )
if ( ( spriteX >= rectangleX + rectangleWidth)
or ( spriteX + spriteWidth <= rectangleX )
or ( spriteY >= rectangleY + rectangleHeight )
or ( spriteY + spriteHeight <= rectangleY ) ) then
return false
else return true
end
end
end

Related

Lua Löve - anim8.lua:59: There is no frame for x=5, y=1

I wanted to create a simple game with my girlfriend, so I choose a lang that I don't even know. I like a challenge.
I am following this tutorial. (it's in portuguese bc it's my native idiom)
Well. I have no idea what's going on.
My code is that below. Thanks for everyone who can helps me <3
local anim = require 'anim8'
local image, inimation
local posX = 100
local direction = true
function love.load()
image = love.graphics.newImage('images/stickman-spritesheet.png')
local g = anim.newGrid(180, 340, image:getWidth(), image:getHeight())
animation = anim.newAnimation(g('1-9', 1, '1-9', 2, '1-9', 3, '1-9', 4, '1-9', 5, '1-9', 6, '1-9', 7, '1-7', 8), 0.01)
end
function love.update(dt)
if love.keyborad.isDown('left') then
posX = posX - 150 * dt
direction = false
animation:update(dt)
end
if love.keyborad.isDown('right') then
posX = posX + 150 * dt
direction = true
animation:update(dt)
end
end
function love.draw()
love.graphics.setBackgroundColor(255, 255, 255)
if direction then
animation:draw(image, posX, 50, 0, 1, 1, 90, 0)
elseif not direction then
animation:draw(image, posX, 50, 0, -1, -1, 90, 0)
end
end
There is no frame for x=5, y=1 happens when a frame is outside the provided image.
anim.newGrid(180, 340, image:getWidth(), image:getHeight()) means, that you have frames of size 180 by 340. Now if your image has the size 360 by 340 for example, you would have 2 by 1 frames.
In your case you expect a x of up to 9.
Double check the frame size and animation provided in g(...)
Read https://github.com/kikito/anim8 for more details.

Error main.lua:45: attempt to call global 'distanceFormula' (a nil value)

I keep getting this error, no matter what:
function love.load() -- love.load starts any command inthe beginning
--number = 0 (old code)
button = {}
button.x = 200
button.y = 200
button.size = 50
button.score = 0
button.time = 0
newFont = love.graphics.newFont(40)
end
end
function love.update(dt) -- changes code in delta time: every frame: love runs in 60 frames per second
--number = number + 1 (old code)
end
function love.draw() -- does anything on the screen
end
function love.draw()
--love.graphics.setColor(0, 0, 255, 5)
--love.graphics.rectangle("fill", 200, 400, 200, 100) --love.graphics.rectangle(mode, x, y, width, height) Y increases downwards;
-- width increases to the right and the height increases downward assuming positive numbers
love.graphics.setColor(255,0,0,5)
--love.graphics.print(number) (old code)
--love.graphics.circle("fill", 150, 350, 100)
--love.graphics.circle(mode, x, y, radius, segments)
love.graphics.circle("fill", button.x, button.y, button.size)
love.graphics.setFont(newFont)
love.graphics.setColor(255, 255, 255, 1)
love.graphics.print(button.score)
end
function love.mousepressed( x, y, b, isTouch)
if b == 1 then
-- use the distance formula to measure the distance/n!
if distanceFormula(button.x, button.y, love.mouse.getX(), love.mouse.getY()) < button.size then
--checks whether click is in circle.
score = score + 1
end
end
function distanceBetween(x1,y1,x2,y2)
return math.sqrt((y2-y1)^2 + (x2-x1)^2)
end
Can someone help me?
The error goes like this:
Error main.lua:45: attempt to call global 'distanceFormula' (a nil value)
Traceback
main.lua:45: in function <main.lua:42>
[C]: in function 'xpcall
I'm very sure that it probably has to do with the function place or something. Can someone help me?
Most importantly can someone please help me with preventing future errors like this??? Thank you.
It looks like you don't have a function called distanceFormula. Also I don't know why you are declaring your distanceBetween function inside of love.mousepressed. distanceFormula is "a nil value" because it doesn't exist. The error is referring to line 45 in your code
if distanceFormula(button.x, button.y, love.mouse.getX(), love.mouse.getY()) < button.size then
I changed your call to distanceFormula to be a call to distanceBetween and moved distance between to it's own function. I also had to move a few of your end around and got rid of your extra love.draw()
function love.load()
--number = 0 (old code)
button = {}
button.x = 200
button.y = 200
button.size = 50
button.score = 0
button.time = 0
newFont = love.graphics.newFont(40)
end
function love.update(dt) -- changes code in delta time: every frame: love runs in 60 frames per second
--number = number + 1 (old code)
end
function love.draw()
--love.graphics.setColor(0, 0, 255, 5)
--love.graphics.rectangle("fill", 200, 400, 200, 100) --love.graphics.rectangle(mode, x, y, width, height) Y increases downwards;
-- width increases to the right and the height increases downward assuming positive numbers
love.graphics.setColor(255,0,0,5)
--love.graphics.print(number) (old code)
--love.graphics.circle("fill", 150, 350, 100)
--love.graphics.circle(mode, x, y, radius, segments)
love.graphics.circle("fill", button.x, button.y, button.size)
love.graphics.setFont(newFont)
love.graphics.setColor(255, 255, 255, 1)
love.graphics.print(button.score)
end
function love.mousepressed(x, y, b, isTouch)
if b == 1 then
-- use the distance formula to measure the distance/n!
if distanceBetween(button.x, button.y, love.mouse.getX(), love.mouse.getY()) < button.size then
--checks whether click is in circle.
button.score = button.score + 1
end
end
end
function distanceBetween(x1,y1,x2,y2)
return math.sqrt((y2-y1)^2 + (x2-x1)^2)
end

How to use bounding box in Love2d?

I've been using some extremely bulky code to detect collision between simple objects, and I've heard about bounding boxes. I can't find any tutorials on how to use it, so I'm asking about how to use it. Here is how I detect collision:
function platform.collision()
if player.x + player.width / 2 <= platform.x + platform.width and
player.x + player.width / 2 >= platform.x and
player.y + player.height <= platform.y + platform.height and
player.y + player.height >= platform.y then
The MDN has a rather concise article on 2D collision detection. Being the MDN, the examples are in javascript, but are easily translated to, and applicable in, any language - including Lua.
Let's take a look:
Axis-Aligned Bounding Box
One of the simpler forms of collision detection is between two rectangles that are axis aligned — meaning no rotation. The algorithm works by ensuring there is no gap between any of the 4 sides of the rectangles. Any gap means a collision does not exist.
Their example, translated to Lua:
local rect1 = { x = 5, y = 5, width = 50, height = 50 }
local rect2 = { x = 20, y = 10, width = 10, height = 10 }
if
rect1.x < rect2.x + rect2.width and
rect1.x + rect1.width > rect2.x and
rect1.y < rect2.y + rect2.height and
rect1.height + rect1.y > rect2.y
then
-- collision detected!
end
-- filling in the values =>
if
5 < 30 and
55 > 20 and
5 < 20 and
55 > 10
then
-- collision detected!
end
A live example, again in JavaScript, demonstrates this well.
Here's a quick (and imperfect) Love2D example you can throw into a main.lua and play around with.
local function rect (x, y, w, h, color)
return { x = x, y = y, width = w, height = h, color = color }
end
local function draw_rect (rect)
love.graphics.setColor(unpack(rect.color))
love.graphics.rectangle('fill', rect.x, rect.y,
rect.width, rect.height)
end
local function collides (one, two)
return (
one.x < two.x + two.width and
one.x + one.width > two.x and
one.y < two.y + two.height and
one.y + one.height > two.y
)
end
local kp = love.keyboard.isDown
local red = { 255, 0, 0, 255 }
local green = { 0, 255, 0, 255 }
local blue = { 0, 0, 255, 255 }
local dim1 = rect(5, 5, 50, 50, red)
local dim2 = rect(20, 10, 60, 40, green)
function love.update ()
if kp('up') then
dim2.y = dim2.y - 1
end
if kp('down') then
dim2.y = dim2.y + 1
end
if kp('left') then
dim2.x = dim2.x - 1
end
if kp('right') then
dim2.x = dim2.x + 1
end
dim2.color = collides(dim1, dim2) and green or blue
end
function love.draw ()
draw_rect(dim1)
draw_rect(dim2)
end
Oka explained it very well. This works for everything rectangular, not rotated and axis aligned. And you even already did it that way. This is great for buttons and the like!
But what I like doing is using (invisible) circles around objects and see if these collide. This works for everything where height is about the same as the width (which is the case for many sidescrolling platformers or top-down RPGs).
It's quite handy if you want to have the object centered at the current position. And it's especially helpful to simulate a finger on a touchscreen device, because a finger is quite a bit bigger than a mouse cursor. ;)
Here's an example on how to use this method. You can copy it as an actual game, it'll work.
--[[ Some initial default settings. ]]
function love.load()
settings = {
mouseHitbox = 5, -- A diameter around the mouse cursor.
-- For a finger (thouchscreen) this could be bigger!
}
objects = {
[1] = {
x = 250, -- Initial X position of object.
y = 200, -- Initial Y position of object.
hitbox = 100, -- A diameter around the CENTER of the object.
isHit = false -- A flag for when the object has been hit.
},
[2] = {
x = 400,
y = 250,
hitbox = 250,
isHit = false
}
}
end
--[[ This is the actual function to detect collision between two objects. ]]
function collisionDetected(x1,y1,x2,y2,d1,d2)
-- Uses the x and y coordinates of two different points along with a diameter around them.
-- As long as these two diameters collide/overlap, this function returns true!
-- If d1 and/or d2 is missing, use the a default diameter of 1 instead.
local d1 = d1 or 1
local d2 = d2 or 1
local delta_x = x2 - x1
local delta_y = y2 - y1
local delta_d = (d1 / 2) + (d2 / 2)
if ( delta_x^2 + delta_y^2 < delta_d^2 ) then
return true
end
end
--[[ Now, some LÖVE functions to give the collisionDetection() some context. ]]
function love.draw()
for i=1,#objects do -- Loop through all objects and draw them.
if ( objects[i].isHit ) then
love.graphics.setColor(255, 0, 0) -- If an object is hit, it will flash red for a frame.
objects[i].isHit = false
else
love.graphics.setColor(255, 255, 255)
end
love.graphics.circle("line", objects[i].x, objects[i].y, objects[i].hitbox/2)
end
end
-- You can use the following to check, if any object has been clicked on (or tapped on a touch screen device).
function love.mousepressed(x,y,button)
if ( button == 1 ) then
local i = objectIsHit(x,y) -- Check, if an object has been hit.
if ( i ) then
-- The object number 'i' has been hit. Do something with this information!
objects[i].isHit = true
end
end
end
function objectIsHit(x,y)
for i=1,#objects do -- Loop through all objects and see, if one of them has been hit.
if ( collisionDetected(x, y, objects[i].x, objects[i].y, settings.mouseHitbox, objects[i].hitbox) ) then
return i -- This object has been hit!
end
end
end
-- For the sake of completeness: You can use something like the following to check, if the objects themselves collide.
-- This would come in handy, if the objects would move around the screen and then bounce from each other, for example.
function love.update(dt)
if ( collisionDetected(objects[1].x, objects[1].y, objects[2].x, objects[2].y, objects[1].hitbox, objects[2].hitbox) ) then
-- The objects collided. Do something with this information!
end
end
As you can see, the collisionDetection() function is quite easy and intuitive to use.
Hopefully I could give you some more insight. And have fun with LÖVE 2D! :)

Having an issue with grid-based movement in Love2D/Lua

Using the Love2D Lua framework, I am trying to program a very basic game much like Nintendo-era RPGs where the heroes' and NPCs' movement was restricted to a tiled grid. So far I've found my past any problems, until I hit this tricky error where the player movement isn't functioning correctly.
function love.load()
love.graphics.setDefaultFilter('nearest', 'nearest', 1)
love.keyboard.setKeyRepeat(true)
font = love.graphics.newFont(14) -- the number denotes the font size
win_size = 6
love.window.setMode(160 * win_size, 144 * win_size)
true_sfc = love.graphics.newCanvas(160,144)
view_sfc = love.graphics.newCanvas(160 * win_size, 144 * win_size)
player = {
grid_x = 3,
grid_y = 3,
act_x = 48,
act_y = 48,
transit = false,
direction = {0, 0}
}
end
function love.update(dt)
if player.transit == true then
-- The idea is that if the player selects a direction, the player will walk in that direction until it stops on the grid.
-- When I press left or right, the movements works as intended- the player square walks until it stops on the grid.
-- However, when I press up or down, the player only moves a single pixel, despite having the same instructions
player.act_x = player.act_x + player.direction[1]
player.act_y = player.act_y + player.direction[2]
if player.act_x == player.grid_x * 16 then
player.direction[1] = 0
player.transit = false
end
if player.act_y == player.grid_y * 16 then
player.direction[2] = 0
player.transit = false
end
-- Now in this if-statement, if I have the program compare the player's y-coordinates before comparing the x coordinates,
-- the program will move the player on the y-axis correctly, with it locking to the 16 pixel grid, while the x coordinates
-- will starts to have the single-pixel movement issue.
end
end
function love.draw()
love.graphics.setCanvas(true_sfc)
love.graphics.setColor( 0, 0, 0)
love.graphics.rectangle("fill", 0, 0, 256, 224)
love.graphics.setColor(255,255,255)
love.graphics.rectangle("fill", player.act_x, player.act_y, 16, 16)
love.graphics.print(player.direction[1], 100, 100)
love.graphics.print(player.direction[2], 100, 120)
love.graphics.setCanvas()
love.graphics.draw(true_sfc, 0, 0, 0, win_size, win_size)
end
function love.keypressed(key)
if player.transit == false then
if key == "up" then
player.grid_y = player.grid_y - 1
player.direction = {0, -1}
player.transit = true
elseif key == "down" then
player.grid_y = player.grid_y + 1
-- press down, the player's map position goes down one tile
player.direction = {0, 1}
player.transit = true
elseif key == "left" then
player.grid_x = player.grid_x - 1
player.direction = {-1, 0}
player.transit = true
elseif key == "right" then
player.grid_x = player.grid_x + 1
player.direction = {1, 0}
player.transit = true
end
end
end
Admittedly I'm pretty new to Lua so I don't understand how it uses variables very well. And I realize that my code isn't very effecient, but that's something I planned on improving over time anyway.
The problem here is that you check if the vertical movement lines up, see that it does, and then you set self.transit to false, preventing any future checks.
You want to also check that you are moving in that direction, before checking if you're lined up:
if player.direction[1] ~= 0 and player.act_x == player.grid_x * 16 then
player.direction[1] = 0
player.transit = false
end
if player.direction[2] ~= 0 and player.act_y == player.grid_y * 16 then
player.direction[2] = 0
player.transit = false
end

Corona SDK - frame-by-frame animation and accelerometer problem

we are doing a game with moving objects around frame-by-frame and also using accelerometer.
We have hooked on two events - about drawing the frame and for the acc.
The problem is, after we receive the acc event, we immediately put the x value in a variable.
Then we use this variable to move an object on the screen, but there is CONSIDERABLE slow down. ( I turn the phone, and after a second the object is moving properly, but a second is just way too much for a game, I expect immediate response).
What am I doing wrong? Is there another workaround to do this, or can I give some params to the accelerometer?
Unfortunately this is a serious problem - a real blocker. If this does not work, I have to find another solution (not Corona) for implementing the game.
Thanks in advance!!!
Danail
PS: here's some source:
local lastXGravity = 0
local function move(event)
eventTime=event.time
elapsedTime = eventTime - lastDrawTime
lastDrawTime = eventTime
xSpeed = lastXGravity
local xMoved = xSpeed * elapsedTime
object.x= object.x + xMoved
end
function acc(event)
lastXGravity = event.xGravity
end
Runtime:addEventListener("accelerometer", acc)
Runtime:addEventListener( "enterFrame", move )
I don't know anything about Corona development, but there are some general issues. First what is gravity containing? Just the gravity vector or total acceleration = gravity + userAcceleration? You will need to get userAcceleration = totalAcceleration - gravity or some member from event providing it directly, otherwise there is no chance.
If you have user acceleration, you need to integrate twice to get the position. See Equations of motion. In your case the code will be like:
velocity = userAcceleration * elapsedTime
position = 0.5*userAcceleration * elapsedTime^2
In general precise position detection by accelerometer and gyroscope is still an unresolved problem, so don't expect precise results. But if you are interested in just evaluating that there is an impulse in one direction, it might work. See for example Getting displacement from accelerometer data with Core Motion
The guys at Ansca's forum just got this out:
system.setAccelerometerInterval( 50 )
This didn't quite actually did the trick, but
system.setAccelerometerInterval( 100 ) -- warning - battery drainer!!
did it :)
I open-sourced my first Corona SDK-made game (which actually did really well) which uses Tilting in the same manner you describe (the more the tilt, the faster the movement and vice-versa).
It's called 'Tilt Monster' and you can download it here:
http://developer.anscamobile.com/code/tilt-monster
local isSimulator = "simulator" == system.getInfo("environment")
-- Accelerator is not supported on Simulator
if isSimulator then
-- Please display an Alert Box
end
-- Text parameters
local labelx = 50
local x = 220
local y = 95
local fontSize = 24
local frameUpdate = false
local xglabel = display.newText( "gravity x = ", labelx, y, native.systemFont, fontSize )
xglabel:setTextColor(255,255,255)
local xg = display.newText( "0.0", x, y, native.systemFont, fontSize )
xg:setTextColor(255,255,255)
y = y + 25
local yglabel = display.newText( "gravity y = ", labelx, y, native.systemFont, fontSize )
local yg = display.newText( "0.0", x, y, native.systemFont, fontSize )
yglabel:setTextColor(255,255,255)
yg:setTextColor(255,255,255)
y = y + 25
local zglabel = display.newText( "gravity z = ", labelx, y, native.systemFont, fontSize )
local zg = display.newText( "0.0", x, y, native.systemFont, fontSize )
zglabel:setTextColor(255,255,255)
zg:setTextColor(255,255,255)
y = y + 50
local xilabel = display.newText( "instant x = ", labelx, y, native.systemFont, fontSize )
local xi = display.newText( "0.0", x, y, native.systemFont, fontSize )
xilabel:setTextColor(255,255,255)
xi:setTextColor(255,255,255)
y = y + 25
local yilabel = display.newText( "instant y = ", labelx, y, native.systemFont, fontSize )
local yi = display.newText( "0.0", x, y, native.systemFont, fontSize )
yilabel:setTextColor(255,255,255)
yi:setTextColor(255,255,255)
y = y + 25
local zilabel = display.newText( "instant z = ", labelx, y, native.systemFont, fontSize )
local zi = display.newText( "0.0", x, y, native.systemFont, fontSize )
zilabel:setTextColor(255,255,255)
zi:setTextColor(255,255,255)
-- Create a circle that moves with Accelerator events
local centerX = display.contentWidth / 2
local centerY = display.contentHeight / 2
Circle = display.newCircle(0, 0, 20)
Circle.x = centerX
Circle.y = centerY
Circle:setFillColor( 0, 0, 255 ) -- blue
local textMessage = function( str, location, scrTime, size, color, font )
local x, t
size = tonumber(size) or 24
color = color or {255, 255, 255}
font = font or "Helvetica"
if "string" == type(location) then
if "Top" == location then
x = display.contentHeight/4
elseif "Bottom" == location then
x = (display.contentHeight/4)*3
else
-- Assume middle location
x = display.contentHeight/2
end
else
-- Assume it's a number -- default to Middle if not
x = tonumber(location) or display.contentHeight/2
end
scrTime = (tonumber(scrTime) or 3) * 1000 -- default to 3 seconds (3000) if no time given
t = display.newText(str, 0, 0, font, size )
t.x = display.contentWidth/2
t.y = x
t:setTextColor( color[1], color[2], color[3] )
-- Time of 0 = keeps on screen forever (unless removed by calling routine)
if scrTime ~= 0 then
-- Function called after screen delay to fade out and remove text message object
local textMsgTimerEnd = function()
transition.to( t, {time = 500, alpha = 0},
function() t.removeSelf() end )
end
-- Keep the message on the screen for the specified time delay
timer.performWithDelay( scrTime, textMsgTimerEnd )
end
return t -- return our text object in case it's needed
end -- textMessage()
local function xyzFormat( obj, value)
obj.text = string.format( "%1.3f", value )
-- Exit if not time to update text color
if not frameUpdate then return end
if value < 0.0 then
-- Only update the text color if the value has changed
if obj.positive ~= false then
obj:setTextColor( 255, 0, 0 ) -- red if negative
obj.positive = false
print("[---]")
end
else
if obj.positive ~= true then
obj:setTextColor( 255, 255, 255) -- white if postive
obj.positive = true
print("+++")
end
end
end
local function onAccelerate( event )
xyzFormat( xg, event.xGravity)
xyzFormat( yg, event.yGravity)
xyzFormat( zg, event.zGravity)
xyzFormat( xi, event.xInstant)
xyzFormat( yi, event.yInstant)
xyzFormat( zi, event.zInstant)
frameUpdate = false -- update done
-- Move our object based on the accelerator values
Circle.x = centerX + (centerX * event.xGravity)
Circle.y = centerY + (centerY * event.yGravity * -1)
-- Display message and sound beep if Shake'n
if event.isShake == true then
-- str, location, scrTime, size, color, font
textMessage( "Shake!", 400, 3, 52, {255, 255, 0} )
end
end
local function onFrame()
frameUpdate = true
end
-- Add runtime listeners
Runtime:addEventListener ("accelerometer", onAccelerate);
Runtime:addEventListener ("enterFrame", onFrame);
I hope, this code will help you.

Resources