Looking for a cleaner more efficient way - lua

function GetDamage(spell, unit)
if spell == _Q and (isReady(_Q) or qActive) and not HasItem(3025) and not HasItem(3100) and not HasItem(3057) and not HasItem(3078) then
return myHero:CalcDamage(unit, ((((myHero:GetSpellData(_Q).level * 20) + 10) + myHero.totalDamage) + qStacks))
elseif spell == _Q and (isReady(_Q) or qActive) and (HasItem(3057) or sheenActive) then
return myHero:CalcDamage(unit, myHero.damage) + myHero:CalcDamage(unit, ((((myHero:GetSpellData(_Q).level * 20) + 10) + myHero.totalDamage) + qStacks))
elseif spell == _Q and (isReady(_Q) or qActive) and (HasItem(3025) or fActive) then
return myHero:CalcDamage(unit, myHero.damage) + myHero:CalcDamage(unit, ((((myHero:GetSpellData(_Q).level * 20) + 10) + myHero.totalDamage) + qStacks))
elseif spell == _Q and (isReady(_Q) or qActive) and (HasItem(3100) or lActive) then
return myHero:CalcMagicDamage(unit, ((myHero.damage * 0.75) + (myHero.ap * 0.5))) + myHero:CalcDamage(unit, ((((myHero:GetSpellData(_Q).level * 20) + 10) + myHero.totalDamage) + qStacks))
elseif spell == _Q and (isReady(_Q) or qActive) and (HasItem(3078) or tActive) then
return myHero:CalcDamage(unit, (myHero.damage * 2)) + myHero:CalcDamage(unit, ((((myHero:GetSpellData(_Q).level * 20) + 10) + myHero.totalDamage) + qStacks))
elseif spell == _E and isReady(_E) then
return myHero:CalcMagicDamage(unit, (((myHero:GetSpellData(_E).level * 40) + 15) + (myHero.ap * 0.6)))
else
return 0
end
end
this is my code to return x spell damage to x enemy, however while it works as intended it seems inefficient and ugly also I would like it to work a little differently and I'm not sure how to code it as such.
What I would like it to do is if I do for example GetDamage(all) or something similiar I would like it to return total damage I can do given isReady(spell) returns true ie if spell q and e are ready it would return the total of q and e only or if all were ready then would return all, additionally if I only need to know r's damage I could still just do GetDamage(_R).
Is there a cleaner way to do this using a table or some more efficient manner to get the results I need? Because currently using GetDamage(spell) + GetDamage(spell2) + GetDamage(spell3) etc looks like very bad coding.

Introduce new spell "ALL"
function GetDamage(spell, unit)
local result = 0
if (spell == "ALL" or spell == _Q) and (isReady(_Q) or qActive) then
local bonus = 0
if (HasItem(3057) or sheenActive) then
bonus = myHero:CalcDamage(unit, myHero.damage)
elseif (HasItem(3025) or fActive) then
bonus = myHero:CalcDamage(unit, myHero.damage)
elseif (HasItem(3100) or lActive) then
bonus = myHero:CalcMagicDamage(unit, ((myHero.damage * 0.75) + (myHero.ap * 0.5)))
elseif (HasItem(3078) or tActive) then
bonus = myHero:CalcDamage(unit, (myHero.damage * 2))
end
result = result + bonus + myHero:CalcDamage(unit, ((((myHero:GetSpellData(_Q).level * 20) + 10) + myHero.totalDamage) + qStacks))
end
if (spell == "ALL" or spell == _E) and isReady(_E) then
result = result + myHero:CalcMagicDamage(unit, (((myHero:GetSpellData(_E).level * 40) + 15) + (myHero.ap * 0.6)))
end
return result
end
Usage examples:
dmg = GetDamage("ALL", unit)
dmg = GetDamage(_Q, unit)
dmg = GetDamage(_E, unit)
EDIT:
There is another way of implementing the same by using a table with spells as keys and functions as values:
spell_dmg_func = {
[_Q] =
function(unit)
if (isReady(_Q) or qActive) then
local bonus = 0
if (HasItem(3057) or sheenActive) then
bonus = myHero:CalcDamage(unit, myHero.damage)
elseif (HasItem(3025) or fActive) then
bonus = myHero:CalcDamage(unit, myHero.damage)
elseif (HasItem(3100) or lActive) then
bonus = myHero:CalcMagicDamage(unit, ((myHero.damage * 0.75) + (myHero.ap * 0.5)))
elseif (HasItem(3078) or tActive) then
bonus = myHero:CalcDamage(unit, (myHero.damage * 2))
end
return bonus + myHero:CalcDamage(unit, ((((myHero:GetSpellData(_Q).level * 20) + 10) + myHero.totalDamage) + qStacks))
end
end,
[_E] =
function(unit)
if isReady(_E) then
return myHero:CalcMagicDamage(unit, (((myHero:GetSpellData(_E).level * 40) + 15) + (myHero.ap * 0.6)))
end
end,
}
function GetDamage(spell, unit)
if spells == "ALL" then
local sum = 0
for spell, func in pairs(spell_dmg_func) do
sum = sum + (func(unit) or 0)
end
return sum
else
return spell_dmg_func[spell](unit) or 0
end
end

Related

Hi, I am creating a simpleplatformer game with love2d, I got a problem in the collisions

In my player script. I called a function to check is if a tile is collided with the player.
The basic tile collisions has been made, but I got some problems.
When the player jump while colliding with the wall, the player stop.
When the player is falling while colliding with the wall, the player stop.
I think the problem is in the Y collision checking part, but I can't figure out how to solve it.
--------------------- Collision Check ----------------------
local box = Vt2:new(self.pos.x + self.vel.x * dt * self.dirXTemp,
self.pos.y + self.vel.y * dt)
for i = 1, #collTile do
local tile = collTile[i]
local isColl = BdBoxCollision(box, self.size, tile.pos, tile.size)
if
isColl[1] == true and
isColl[2] == true and
isColl[3] == true and
isColl[4] == true then
local isOnWall = false
if self.pos.y + self.size.y > tile.pos.y then -- X Collision
if box.x + self.size.x / 2 < tile.pos.x + tile.size.x / 2 then
if box.x + self.size.x > tile.pos.x then
if self.dirX == 1 then
self.vel.x = 0
isOnWall = true
end
end
end
if box.x + self.size.x / 2 > tile.pos.x + tile.size.x / 2 then
if box.x < tile.pos.x + tile.size.x then
if self.dirX == -1 then
self.vel.x = 0
isOnWall = true
end
end
end
end
if box.y + self.size.y / 2 < tile.pos.y + tile.size.y / 2 then -- Y Collision
if box.y + self.size.y > tile.pos.y and
self.pos.y + self.size.y < tile.pos.y + 8 then
if isOnWall == false then
self.pos.y = tile.pos.y - self.size.y
self.vel.y = 0
end
end
elseif box.y + self.size.y / 2 > tile.pos.y + tile.size.y / 2 then
if box.y < tile.pos.y + tile.size.y then
self.vel.y = self.gravity
end
end
end
end
::skip::
self.pos.x = self.pos.x + self.vel.x * dt
self.pos.y = self.pos.y + self.vel.y * dt

Trying to add horizontal movement to my game in love2d

I have tried to add horizontal movement into my game in love, but I haven't found a way yet. This is my code.
PADDLE_SPEED = 200
player1 = Paddle(10, 30, 5, 20)
player1 = Paddle(10, 30, 5, 20)
player2 = Paddle(VIRTUAL_WIDTH - 15, VIRTUAL_HEIGHT - 30, 5, 20)
player3 = Paddle(30, 10, 20, 5)
player4 = Paddle(VIRTUAL_WIDTH - 30, VIRTUAL_HEIGHT - 15, 20, 5)
ball = Ball(VIRTUAL_WIDTH / 2 - 2, VIRTUAL_HEIGHT / 2 - 2, 4, 4)
if love.keyboard.isDown('w') then
player1.dy = -PADDLE_SPEED
elseif love.keyboard.isDown('s') then
player1.dy = PADDLE_SPEED
else
player1.dy = 0
end
if love.keyboard.isDown('a') then
player1.dx = PADDLE_SPEED
elseif love.keyboard.isDown('d') then
player1.dx = -PADDLE_SPEED
else
player1.dx = 0
end
if love.keyboard.isDown('a') then
player1.dx = -PADDLE_SPEED
elseif love.keyboard.isDown('d') then
player1.dy = PADDLE_SPEED
else
player1.dx = 0
end
if love.keyboard.isDown('up') then
player2.dy = -PADDLE_SPEED
elseif love.keyboard.isDown('down') then
player2.dy = PADDLE_SPEED
else
player2.dy = 0
end
if love.keyboard.isDown('i') then
player3.dy = -PADDLE_SPEED
elseif love.keyboard.isDown('k') then
player3.dy = PADDLE_SPEED
else
player3.dy = 0
end
if love.keyboard.isDown('g') then
player4.dy = -PADDLE_SPEED
elseif love.keyboard.isDown('b') then
player4.dy = PADDLE_SPEED
else
player4.dy = 0
end
This is my class that I call Paddle
Paddle = Class{}
function Paddle:init(x, y, width, height)
self.x = x
self.y = y
self.width = width
self.height = height
self.dy = 0
self.dx = 0
end
function Paddle:update(dt)
if self.dy < 0 then
self.y = math.max(0, self.y + self.dy * dt)
else
self.y = math.min(VIRTUAL_HEIGHT - self.height, self.y + self.dy * dt)
end
end
function Paddle:render()
love.graphics.rectangle('fill', self.x, self.y, self.width, self.height)
end
I would try drawing the rectangles individually, but I would have to remove all the code that includes player1-4. Is there any way that I can set a variable like PADDLE_SPEED to a number?
So your not quite instantiating your Paddle class correctly. Based on Lua's documentation, I changed some things in your paddle class.
Paddle.lua
Paddle={x=0,y=0,width=0,height=0}
function Paddle:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function Paddle:update(dt)
if self.dy < 0 then
self.y = math.max(0, self.y + self.dy * dt)
else
self.y = math.min(VIRTUAL_HEIGHT - self.height, self.y + self.dy * dt)
end
end
function Paddle:render()
love.graphics.rectangle('fill', self.x, self.y, self.width, self.height)
end
Also I'm not sure what you just didn't include in you question, but I set up your core 3 functions (love.load(), love.update(dt), and love.draw()), set values for VIRTUAL_WIDTH AND VIRTUAL_HEIGHT, and instantiated your player classes according to how the Lua documentation specifies
The main thing that might be your problem is that your assigning the speeds to your player objects dy and dx values. These are made up values that you've created for your player object. They don't do anything unless you later access them and use them somehow. I think what you are trying to do is change the x and y position of your player objects. You can do this by taking the players current x or y position and adding or subtracting the PADDLE_SPEED * dt(the number of seconds that have passed since the last execution of love.update(dt)
main.lua
require('Paddle')
function love.load()
--initial graphics setup
love.graphics.setBackgroundColor(0.41, 0.53, 0.97)
love.window.setMode(1000, 600)
PADDLE_SPEED = 200
VIRTUAL_WIDTH = 30
VIRTUAL_HEIGHT = 30
player1 = Paddle:new{x=10, y=30, width=5, height=20}
player2 = Paddle:new{x=VIRTUAL_WIDTH-15, y=VIRTUAL_HEIGHT-30, width=5, height=20}
player3 = Paddle:new{x=30, y=10, width=20, height=5}
player4 = Paddle:new{x=VIRTUAL_WIDTH-30, y=VIRTUAL_HEIGHT-15, width=20, height=5}
-- ball = Ball(VIRTUAL_WIDTH / 2 - 2, VIRTUAL_HEIGHT / 2 - 2, 4, 4)
end
function love.update(dt)
if love.keyboard.isDown('w') then
player1.y = player1.y + PADDLE_SPEED * dt
elseif love.keyboard.isDown('s') then
player1.y = player1.y - PADDLE_SPEED * dt
end
if love.keyboard.isDown('a') then
player1.x = player1.x + PADDLE_SPEED * dt
elseif love.keyboard.isDown('d') then
player1.x = player1.x - PADDLE_SPEED * dt
end
if love.keyboard.isDown('a') then
player2.x = player2.x - PADDLE_SPEED * dt
elseif love.keyboard.isDown('d') then
player2.x = player2.x + PADDLE_SPEED * dt
end
if love.keyboard.isDown('up') then
player2.y = player2.y - PADDLE_SPEED * dt
elseif love.keyboard.isDown('down') then
player2.y = player2.y + PADDLE_SPEED * dt
end
if love.keyboard.isDown('i') then
player3.y = player3.y - PADDLE_SPEED * dt
elseif love.keyboard.isDown('k') then
player3.y = player3.y + PADDLE_SPEED * dt
end
if love.keyboard.isDown('g') then
player4.y = player4.y - PADDLE_SPEED * dt
elseif love.keyboard.isDown('b') then
player4.y = player4.y + PADDLE_SPEED * dt
end
end
function love.draw()
player1:render()
player2:render()
player3:render()
player4:render()
end
So your ball won't work, because I don't know exactly what you want with it, and your Paddle:update(dt) still won't work because I don't know exactly what you want. When you do get Paddle:update(dt) working make sure you include player1:update(dt), player2:update(dt) ... inside your love:update(dt) function or else none of your players will update.
You should get horizontal and vertical movement of your blocks though
P.S. If you post a question a again, you should make sure that you specify exactly what isn't working. Some of your details were missing, and I wasn't sure if that was the part you were asking about, or you had those details in your original code and were asking about something else.
It seems like you probably want to deal with collisions. Here's another answer where i kind of explain collisions, but I would probably recommend love.physics for this type of scenario

ERROR: "attempt to index global 'self' (a nil value)

I'm very slowly working my way through the games track of cs50, and I am stuck on Mario3. In the video he just talks about the code, but I wanted to write it into my own that I am writing alongside the video. I have the exact same code that he does, but I keep getting this error and I cannot figure out why. I will post the code below, but as far as I can tell, I have already assigned self.mapWidth = 30, so I don't know why it keeps saying that it is a nil value.
Here is the error
Error code
Here is the map.lua code
require 'Util'
Map = Class{}
TILE_BRICK = 1
TILE_EMPTY = 4
--cloud tiles
CLOUD_LEFT = 6
CLOUD_RIGHT = 7
SCROLL_SPEED = 62
function Map:init()
self.spritesheet = love.graphics.newImage('graphics/spritesheet.png')
self.tileWidth = 16
self.tileHeight = 16
self.mapWidth = 30
self.mapHeight = 28
self.tiles = {}
self.camX = 0
self.camY = 0
self.mapWidthPixels = self.mapWidth * self.tileWidth
self.mapHeightPixels = self.mapHeight * self.tileHeight
self.tileSprites = generateQuads(self.spritesheet, self.tileWidth, self.tileHeight)
--fill map with empty tiles--
for y = 1, self.mapHeight do
for x = 1, self.mapWidth do
self:setTile(x, y, TILE_EMPTY)
end
end
for y =self.mapHeight / 2, self.mapHeight do
for x = 1, self.mapWidth do
self:setTile(x, y, TILE_BRICK)
end
end
end
function Map:setTile(x, y, tile)
self.tiles[(y - 1) * self.mapWidth + x] = tile
end
function Map:getTile(x, y)
return self.tiles[(y -1) * self.mapWidth + x]
end
local x = 1
while x < self.mapWidth do
if math.random(20) == 1 then
local cloudStart = math.random(self.mapHeight / 2 -6)
self.setTile(x, cloudStart, CLOUD_LEFT)
self:setTile(x + 1, cloudStart, CLOUD_RIGHT)
end
end
function Map:update(dt)
if love.keyboard.isDown('w') then
self.camY = math.max(0, math.floor(self.camY - SCROLL_SPEED * dt))
elseif love.keyboard.isDown('s') then
self.camY = math.min(self.mapHeightPixels - VIRTUAL_HEIGHT, math.floor(self.camY + SCROLL_SPEED * dt))
elseif love.keyboard.isDown('a') then
self.camX = math.max(0, math.floor(self.camX - SCROLL_SPEED *dt))
elseif love.keyboard.isDown('d') then
self.camX = math.min(self.mapWidthPixels - VIRTUAL_WIDTH, math.floor(self.camX + SCROLL_SPEED * dt))
end
end
function Map:render()
for y = 1, self.mapHeight do
for x = 1, self.mapWidth do
love.graphics.draw(self.spritesheet, self.tileSprites[self:getTile(x, y)],
(x - 1) * self.tileWidth, (y - 1) * self.tileHeight)
end
end
end
and in case you need it, here is my main.lua code
WINDOW_WIDTH = 1200
WINDOW_HEIGHT = 720
VIRTUAL_WIDTH = 432
VIRTUAL_HEIGHT = 243
Class = require 'class'
push = require 'push'
require 'Util'
require 'Map'
function love.load()
map = Map()
love.graphics.setDefaultFilter('nearest', 'nearest')
push:setupScreen(VIRTUAL_WIDTH,VIRTUAL_HEIGHT,WINDOW_WIDTH,WINDOW_HEIGHT, {
fullscreen = false,
resizable = false,
vsync = true
})
end
function love.update(dt)
map:update(dt)
if love.keyboard.isDown('escape') then
love.event.quit()
end
end
function love.draw()
push:apply('start')
love.graphics.translate(math.floor(-map.camX),math.floor(-map.camY))
love.graphics.clear(108/255, 140/255, 1, 1)
map:render()
push:apply('end')
end
Thanks in advance for any and all help.
function Map:SomeFunction() end is syntactic sugar for Map["SomeFunction"] = function(self) end
Therefor you can use self inside a function defined with the colon syntax.
Outside of such a function self is nil.
Yet you index self several times in this while loop where self is nil.
local x = 1
while x < self.mapWidth do
if math.random(20) == 1 then
local cloudStart = math.random(self.mapHeight / 2 -6)
self.setTile(x, cloudStart, CLOUD_LEFT)
self:setTile(x + 1, cloudStart, CLOUD_RIGHT)
end
end
which is an infinite loop btw.

RoR: Method to return a statement in a json format?

I'm looking for a method that will return this statement in a JSON format.
def statement
total = 0
bonus points = 0
result = 'Car rental for #{#name.to_s}\n'
for r in #rentals
this_amount = 0
case r.car.style
when Car::SUV
this_amount += r.days_rented * 30
when Car::HATCHBACK
this_amount += 15
if r.days_rented > 3
this_amount += (r.days_rented - 3) * 15
end
when Car::SALOON
this_amount += 20
if r.days_rented > 2
this_amount += (r.days_rented - 2) * 15
end
else
end
if this_amount < 0
bonus_points -= 10
end
bonus_points = bonus_points + 1
if r.car.style == Car::SUV && r.days_rented > 1
bonus_points = bonus_points + 1
end
result += r.car.title.to_s + "," + this_amount.to_s + "\n"
total += this_amount
end
result += "Amount owed is " + "#{total.to_s}" + "\n"
result +="Earned bonus points: " + bonus_points.to_s
result
end
What method would I need to add to my class to return this statement in a JSON format? Thank you.
Simplest way to do that
return {:result => result}
at the end of your method.
But if you are using controller to show data to user, I would prefer using .to_json in my controller method

Check Collision Between Ball And Array Of Bricks

Since I have a collision check function in Lua:
function onCollision(obj1,obj2)
obj1x = obj1.left
obj1y = obj1.top
obj1w = obj1.width
obj1h = obj1.height
obj2x = obj2.left
obj2y = obj2.top
obj2w = obj2.width
obj2h = obj2.height
if obj2x + obj2w >= obj1x and obj2y + obj2h >= obj1y and obj2y <= obj1y + obj1h and obj2x <= obj1x + obj1w then
return true
end
end
And I did make some panels as bricks using array table on my form, with this function, I did collision check between ball with each form sides without problems.
function createBricks()
for row = 1, brickRows do
bricks[row] = {}
for col = 1, brickColumns do
local x = (col - 1) * (width + gap) -- x offset
local y = (row - 1) * (height + gap) -- y offset
local newBrick = createPanel(gamePanel)
newBrick.width = brickWidth
newBrick.height = brickHeight
newBrick.top = y + 15
newBrick.left = x + 15
newBrick.BorderStyle = 'bsNone'
if level == 1 then newBrick.color = '65407' -- green
elseif level == 2 then newBrick.color = '858083' -- red
elseif level == 3 then newBrick.color = '9125192' -- brown
elseif level == 4 then newBrick.color = math.random(8,65255) end
bricks[row][col] = newBrick
end
end
end
Next how to detect if the ball collided with the bricks?. So far I did:
for row = 1, brickRows do
bricks[row] = {}
for col = 1, brickColumns do
dBrick = bricks[row][col]
if onCollision(gameBall,dBrick) then
dBrick.destroy() -- destroy the collided brick
end
end
end
I want to learn how to implement this collision logic in VB Net script which VB script easier for me, I did the whole game project using VB Net, now I try to re-write the project using CE Lua.
Private brickArray(brickRows, brickColumns) As Rectangle
Private isBrickEnabled(brickRows, brickColumns) As Boolean
For rows As Integer = 0 To brickRows
For columns As Integer = 0 To brickColumns
If Not isBrickEnabled(rows, columns) Then Continue For
If gameBall.IntersectsWith(brickArray(rows, columns)) Then
isBrickEnabled(rows, columns) = False
If gameBall.X + 10 < brickArray(rows, columns).X Or _
gameBall.X > brickArray(rows, columns).X + brickArray(rows, columns).Width _
Then
xVel = -xVel
Else
yVel = -yVel
End If
End If
Next
Next
And also this private sub, how to write it CE Lua?
Sub loadBricks()
Dim xOffset As Integer = 75, yOffset As Integer = 100
For row As Integer = 0 To brickRows
For column As Integer = 0 To brickColumns
brickArray(row, column) = New Rectangle(xOffset, yOffset, brickWidth, brickHeight)
xOffset += brickWidth + 10
isBrickEnabled(row, column) = True
Next
yOffset += brickHeight + 10
xOffset = 75
Next
End Sub
Function getBrickCount() As Integer
Dim Count As Integer = 0
For Each brick As Boolean In isBrickEnabled
If brick = True Then Count += 1
Next
Return Count
End Function
function onCollision(obj1,obj2)
obj1x = obj1.left
obj1y = obj1.top
obj1w = obj1.width
obj1h = obj1.height
obj2x = obj2.left
obj2y = obj2.top
obj2w = obj2.width
obj2h = obj2.height
if obj2x + obj2w >= obj1x and obj2y + obj2h >= obj1y and obj2y <= obj1y + obj1h and obj2x <= obj1x + obj1w then
return true
end
end
Then to detect collision the collision and remove from the table:
-- Drawback table
local function tcount( t )
local c = 0
for k,v in pairs(t) do
c = c + 1
end
return c
end
local count = #brickArray
for x = 1, count do
if onCollision(gameBall, brickArray[x]) then
if gameBall.Left + 10 < brickArray[x].Left or gameBall.Left > brickArray[x].Left + brickArray[x].Width then
xVel = -xVel else yVel = -yVel
end
playSound(findTableFile('strikeball.wav'))
brickArray[x] = brickArray[count]
brickArray[x] = x
brickArray[count] = nil
brickArray[x].Visible = false
tcount(brickArray)
end
end
The code above detected the collision and remove the object from the table, but that is not removed from display. How to remove the bricks from the table and display, using Cheat Engine Lua script?.

Resources