Having an issue with grid-based movement in Love2D/Lua - 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

Related

how do I fix my script made in Roblox Lua?

I'm making my script and the Script Analysis tool says
Error: (54,2) Expected , got 'end'
I thought maybe you guys might help.
Here is the code
-- to be placed in StarterPlayer > StarterPlayerScripts
local Players = game:GetService("Players")
-- wait for local player PlayerGui
local LocalPlayer = Players.LocalPlayer
local playerGui = LocalPlayer:WaitForChild("PlayerGui")
-- create a ScreenGui
local screenGui = Instance.new("ScreenGui", playerGui)
-- create a holder for our bar
local frame = Instance.new("Frame", screenGui)
frame.AnchorPoint = Vector2.new(0.0, 0.0)
frame.Position = UDim2.new(0.0, 0, 0.0, 0)
frame.Size = UDim2.new(0.0, 0, 0.0, 0)
-- create a bar
local bar = Instance.new("Frame", frame)
bar.Position = UDim2.new(0, 0, 0, 0)
bar.Size = UDim2.new(1, 0, 1, 0)
bar.BackgroundColor3 = Color3.new(0, 1, 0)
-- create a sound
local sound = Instance.new("Sound", screenGui)
local lastLoudness = 0
sound.SoundId = "rbxassetid://697821987"
sound.Looped = true
sound:Play()
-- define a max loudness
local maxLoudness = 30
-- animate the amplitude bar
while true do
local amplitude = math.clamp(sound.PlaybackLoudness / maxLoudness, 0, 1)
print(80-(game.Workspace.CurrentCamera.FieldOfView))
bar.Size = UDim2.new(sound.PlaybackLoudness / maxLoudness, 0, 0, 0)
wait(0.00001)
local lastLoudness = 0
local PBS = ((sound.PlaybackLoudness/50)^(sound.PlaybackLoudness/50))
if lastLoudness~=0 then
local formula = math.abs((lastLoudness*15)) + ((lastLoudness+PBS)/1.9)
if (math.abs(PBS) > formula) == true then
game.Workspace.CurrentCamera.FieldOfView = (lastLoudness)
if game.Workspace.CurrentCamera.FieldOfView <= 10 then
print(formula, PBS)
else
game.Workspace.CurrentCamera.FieldOfView = 0
print(formula, PBS)
end
end
end
end
end
end
I genuinely Don't know how to fix the code, So...
Could you guys Help me?
I spent a long time (a couple of hours) on this and I'm legitimately stuck in the deepest pits of coding hell. And I want this fixed SO BADLY.
Also, Just To Clarify, The script is supposed to change FOV when sound.PlaybackLoudness ÷ 50 × sound.PlaybackLoudness ÷ 50 is over 0.
Egor Skriptunoff is right. Let me reformat your while-loop to show you why.
-- animate the amplitude bar
while true do
local amplitude = math.clamp(sound.PlaybackLoudness / maxLoudness, 0, 1)
print(80-(game.Workspace.CurrentCamera.FieldOfView))
bar.Size = UDim2.new(sound.PlaybackLoudness / maxLoudness, 0, 0, 0)
wait(0.00001)
local lastLoudness = 0
local PBS = ((sound.PlaybackLoudness/50)^(sound.PlaybackLoudness/50))
if lastLoudness~=0 then
local formula = math.abs((lastLoudness*15)) + ((lastLoudness+PBS)/1.9)
if (math.abs(PBS) > formula) == true then
game.Workspace.CurrentCamera.FieldOfView = (lastLoudness)
if game.Workspace.CurrentCamera.FieldOfView <= 10 then
print(formula, PBS)
else
game.Workspace.CurrentCamera.FieldOfView = 0
print(formula, PBS)
end
end
end
end
end -- <-- these bad boys don't go with anything
end -- <-- just remove them to get rid of the error
EDIT : Here's a more complete answer to help with your other script issues. You were resizing your animation stuff to 0 pixels tall, so you couldn't see anything.
-- to be placed in StarterPlayer > StarterPlayerScripts
local Players = game:GetService("Players")
-- wait for local player PlayerGui
local LocalPlayer = Players.LocalPlayer
local playerGui = LocalPlayer:WaitForChild("PlayerGui")
-- create a ScreenGui
local screenGui = Instance.new("ScreenGui", playerGui)
-- create a holder for our bar
local frame = Instance.new("Frame", screenGui)
frame.AnchorPoint = Vector2.new(0.0, 0.0)
frame.Position = UDim2.new(0.0, 0, 0.0, 0)
frame.Size = UDim2.new(1.0, 0, 0.0, 50) -- <-- this is no longer invisible
-- create a bar
local bar = Instance.new("Frame", frame)
bar.Position = UDim2.new(0, 0, 0, 0)
bar.Size = UDim2.new(1, 0, 1, 0)
bar.BackgroundColor3 = Color3.new(0, 1, 0)
-- create a sound
local sound = Instance.new("Sound", screenGui)
local lastLoudness = 0
sound.SoundId = "rbxassetid://697821987"
sound.Looped = true
sound:Play()
-- define a max loudness
local maxLoudness = 30.0 -- <-- this needed to be a decimal value
local lastLoudness = 0
-- animate the amplitude bar
while true do
-- PlaybackLoudness values range from 0 to 500, so downscale it
local sampledLoundness = (sound.PlaybackLoudness / 50)
local amplitude = math.clamp(sampledLoundness / maxLoudness, 0, 1)
print("sound values : ", sound.PlaybackLoudness, maxLoudness, amplitude)
-- animate the bar
bar.Size = UDim2.new(amplitude, 0, 1, 0) -- <-- this was squashed to 0 pixels
wait(0.00001)
-- create a camera shake effect
-- NOTE - not sure what the expected behavior is here, it just zooms in
local PBS = sampledLoundness ^ sampledLoundness
if lastLoudness ~=0 then
local formula = math.abs(lastLoudness * 15) + ((lastLoudness + PBS) / 1.9)
if (math.abs(PBS) > formula) == true then
game.Workspace.CurrentCamera.FieldOfView = lastLoudness
if game.Workspace.CurrentCamera.FieldOfView <= 10 then
print("FOV is less than 10 : ", formula, PBS)
else
game.Workspace.CurrentCamera.FieldOfView = 0
print("FOV forced to 0 : ", formula, PBS)
end
end
end
-- update lastLoudness and loop
lastLoudness = sampledLoundness
end

Corona SDK / Lua : An table's property is nil, when accessed via event.other during collision event. But why?

So I have this module, where all of its activity during the game is in. In t.physics I add a collision event listener (differentiating if target is a group or a single object). When the concerning objects detect a collision though, the property col of the other object (event.other) seems to be nil, although I initially set it to a string representing a color in t.create. I just can't find the cause for that, can anyone?
Thanks for your help.
Greetings, Nils
local fence = require("lib.fence")
local physics = require("physics")
local t = {}
local stages = {yellow = 1, lila = 1, red = 1}
local sizes = {1, 3.625, 7.25}
t.colors = {"yellow", "lila", "red"}
t.growing = false
t.setSize = function(fill)
local tHeight = fill.contentHeight * sizes[stages[fill.col]]
local tScale = tHeight / fill.contentHeight
fill.yScale = tScale
end
t.grow = function(group, color, hero)
local counter = 0
stages[color] = stages[color] + 1
for i = 1, group.numChildren, 1 do
if group[i].col == color then
counter = counter + 1
local function newPhysics() t.physics(group) end
if counter == 1 then
local function reset() t.growing = false if stages[color] == 3 then stages[color] = 1; newPhysics(); end end
local function start() t.growing = true end
transition.to(group[i], {time = 260, yScale = sizes[stages[color]], onStart = start, onComplete = reset})
else
transition.to(group[i], {time = 250, yScale = sizes[stages[color]], onStart = start})
end
end
end
end
t.physics = function(target)
if target.numChildren == nil then
physics.removeBody(target)
local function add()
physics.addBody( target, "static", {isSensor = true} )
target.collision = function(self, event)
if event.phase == "began" then
target.count = target.count + 1
if target.count == 1 then
t.grow(target.parent, self.col, event.other)
end
elseif event.phase == "ended" then
target.count = 0
end
end
end
timer.performWithDelay(1, add, 1)
else
for i = 1, target.numChildren, 1 do
physics.removeBody( target[i] )
physics.addBody( target[i], "static", {isSensor = true} )
target[i].name = "fill"
local fill = target[i]
fill.count = 0
fill.collision = function(self, event)
if event.phase == "began" then
self.count = self.count + 1
if self.count == 1 and event.other.x ~= nil then
t.grow(target, self.col, event.other)
end
else
fill.count = 0
end
end
fill:addEventListener("collision")
end
end
end
t.setColor = function(fill)
local colors = {
{238 / 255, 228 / 255, 28 / 255},
{38 / 255, 33 / 255, 77 / 255},
{175 / 255, 24 / 255, 52 / 255},
}
local names = {"yellow", "lila", "red"}
local r = math.random(3)
fill.fill = colors[r]
fill.col = names[r]
end
t.create = function(fences, group, colors)
local fills = {}
for i = 1, #fences, 1 do
local rCol = math.random(3)
local col
if rCol == 1 then
col = colors.yellow
elseif rCol == 2 then
col = colors.lila
else
col = colors.red
end
fills[i] = display.newRect(
group, fences[i].x + fences[i].contentWidth * 0.125, fences[i].y,
fences[i].contentWidth * 0.9, (fences[i].contentHeight * 0.5 / 3)
)
fills[i].dPosX = fills[i].x
fills[i].y = display.contentHeight- fills[i].contentHeight / 2
fills[i].fill = col
fills[i].col = t.colors[rCol]
fills[i].increased = false
end
return fills
end
t.move = function(fills, fences, group)
for i = 1, #fills, 1 do
local fill = fills[i]
function fill:enterFrame()
self:translate(fence.speed, 0)
if t.growing == false then
t.setSize(self)
end
if self.x > display.contentWidth + 0.55 * fences[i].contentWidth then
local xT = {}
for i = 1, group.numChildren, 1 do
xT[i] = group[i].x
end
local function compare(a, b) return a < b end
table.sort(xT, compare)
self.x = xT[1] - fences[i].contentWidth * 0.98
t.setColor(self)
local function newPhysics() t.physics(self) end
timer.performWithDelay( 25, newPhysics, 1 )
self:toBack()
end
end
Runtime:addEventListener("enterFrame", fill)
end
end
return t
Solved. Ugh, sorry, I forgot to define the property on the other object involved (hero), that has its own module. What a stupid slip.
Thanks for your answers anyways!
You don't seem to have any dynamic bodies here. What is colliding with what? Could it be that the other object involved in the collision (the value of event.other) is not something initialized in t.create() and so doesn't have the col property?
From the Corona documentation on Collision Detection:
Some body types will — or will not — collide with other body types. In a collision between two physical objects, at least one of the objects must be dynamic, since this is the only body type which collides with any other type.
Also, in your fill.collision(), I think you want to pass event.target as the first argument to t.grow() rather than target. If you try things, please update the question with more information.

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! :)

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

--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

Lua Breakout Game Tutorial : Weird behavior of ball

I followed this tutorial to make a breakout game, but at some point, the ball keeps leaning on the top wall when the ball angle is too large ( too horizontal ). Is there any logic I can tune so that the ball can avoid this behavior?
Here is the screenshot :
The ball's related source code is:
local ballRadius = 10
ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, ballRadius )
physics.addBody(ball, "dynamic", {friction=0, bounce = 1, radius=ballRadius})
It is some kind of weird. But I've done once like this...
Create 3 variables/flags:
local horizontalMotionFlag,yPos_1,yPos_2 = 0,0,0
Then:
wall.type = "LeftWall" -- to the LeftWall
-- and --
wall.type = "RightWall" -- to the RightWall
Add the following lines inside event.phase == "ended"
------------------------------------------------------------------------------------------
if(event.other.type == "LeftWall") then
yPos_1 = ball.y
if(horizontalMotionFlag==0)then
horizontalMotionFlag = 1
else
if(math.abs(yPos_1-yPos_2) < 50)then
print("CoHorizontal motion detected. Change angle...1")
horizontalMotionFlag = 0
ball:applyForce( 0, 1, ball.x, ball.y ) -- apply a small downward force
ball:applyForce( 0, 0, ball.x, ball.y ) -- resetting the force
-- You can also check the direction of ball and apply force to -1(upwards) also --
end
end
end
if(event.other.type == "RightWall") then
yPos_2 = ball.y
if(horizontalMotionFlag==0)then
horizontalMotionFlag = 1
else
if(math.abs(yPos_1-yPos_2) < 50)then
print("CoHorizontal motion detected. Change angle...")
horizontalMotionFlag = 0
ball:applyForce( 0, 1, ball.x, ball.y ) -- apply a small downward force
ball:applyForce( 0, 0, ball.x, ball.y ) -- resetting the force
-- You can also check the direction of ball and apply force to -1(upwards) also --
end
end
end
------------------------------------------------------------------------------------------
Then add the following line inside event.other.type == "destructible" and event.other.type == "bottomWall" :
horizontalMotionFlag = 0;
Keep Coding............. :)

Resources