Homebrew [Release] - LövePotion - LÖVE API for 3DS Homebrew - BETA

VideahGams

Well-Known Member
OP
Newcomer
Joined
Aug 29, 2015
Messages
91
Trophies
0
Age
25
Location
Glasgow, Scotland
Website
videah.xyz
XP
146
Country
In theory, couldn't one port Mari0 (Portal+Super Mario Bros. coded in LÖVE) to the 3DS?

If you go back a page, you'll see this was already talked about.
The answer was, in theory, kinda.
Not everything is implemented and Mari0 uses an old version of LÖVE.
 
  • Like
Reactions: pastaconsumer

Shadowtrance

Well-Known Member
Member
Joined
May 9, 2014
Messages
2,493
Trophies
0
Location
Hervey Bay, Queensland
XP
1,807
Country

TurtleP

Well-Known Member
Member
Joined
Oct 7, 2015
Messages
140
Trophies
0
Age
28
Website
TurtleP.github.io
XP
308
Country
United States
Having modded the game quite a lot in the old days of learning Löve, no. It's not that simple especially when porting something as big as Mari0. Löve Potion is meant for building from the ground up and not porting. Sure, you can port but it's a long process and for Mari0, won't be worth your time at all. On top of that, you'd have to somehow make the portal gun angle smoothly and not crazily (I've used 3DS Controller with it, not fun) which even then it's hard to aim and would not let puzzles or anything be easy.
 

CKlidify

Well-Known Member
Newcomer
Joined
May 31, 2015
Messages
70
Trophies
0
XP
208
Country
Canada
I'm trying to make a port of an already existing tetris game for Love2D and it's using functions supported by LovePotion so I was wondering why the game starts, freezes, but you can still pause and unpause:

Code:
--Global variables
screenX = 400
screenY = 240

boardX = 10
boardY = 15

tileX = 16
tileY = 16

cubes = {}
gray = 1
red = 2
orange = 3
yellow = 4
green = 5
cyan = 6
blue = 7
violet = 8

pieceI = 2
pieceJ = 3
pieceL = 4
pieceO = 5
pieceS = 6
pieceT = 7
pieceZ = 8

pieceCentering = {}
pieceCentering[pieceI] = 3
pieceCentering[pieceJ] = 3
pieceCentering[pieceL] = 4
pieceCentering[pieceO] = 4
pieceCentering[pieceS] = 4
pieceCentering[pieceT] = 3
pieceCentering[pieceZ] = 3

piece = 0
col = 1
row = 2
width = 3
height = 4
color = 5
rotation = 6

rotPressDelay = 0.2 --Amount of time between rotation key presses
keyPressDelay = 0.1 --Amount of time between non-rotation key presses
descentDelay = 1 --Amount of time for a piece to drop one square at game start
minDelay = 0.05 --Minimum descent delay (never gets faster than this)
scoreDelayThreshold = 10 --Score threshold for increase in descent speed
speedIncrease = 0.05 --Reduction in time for a piece to drop when threshold is hit
gameOverDelay = 3 --Amount of time between game over and ability to hit a key to continue

play = 0
pause = 1
menu = 2

--Create a board
function createBoard()
    myBoard = {}
  
    for i=1, boardX do
        myBoard[i] = {}
        for j=1, boardY do
            myBoard[i][j] = gray
        end
    end
  
    return myBoard
end

--Set up the pieces
function createPieces()
    pieces = {}
  
    for i=pieceI, pieceZ do
        pieces[i] = {}
    end
  
    createPieceI(pieceI)
    createPieceJ(pieceJ)
    createPieceL(pieceL)
    createPieceO(pieceO)
    createPieceS(pieceS)
    createPieceT(pieceT)
    createPieceZ(pieceZ)
end

function createPieceI(myPiece)
    for i=1,4 do
        pieces[myPiece][i] = {}
        pieces[myPiece][i][1] = true
    end
end

function createPieceJ(myPiece)
    for i=1,3 do
        pieces[myPiece][i] = {}
    end
    pieces[myPiece][1][1] = true
    pieces[myPiece][2][1] = false
    pieces[myPiece][3][1] = false
    pieces[myPiece][1][2] = true
    pieces[myPiece][2][2] = true
    pieces[myPiece][3][2] = true
end

function createPieceL(myPiece)
    for i=1,3 do
        pieces[myPiece][i] = {}
    end
    pieces[myPiece][1][1] = false
    pieces[myPiece][2][1] = false
    pieces[myPiece][3][1] = true
    pieces[myPiece][1][2] = true
    pieces[myPiece][2][2] = true
    pieces[myPiece][3][2] = true
end

function createPieceO(myPiece)
    for i=1,2 do
        pieces[myPiece][i] = {}
        for j=1,2 do
            pieces[myPiece][i][j] = true
        end
    end
end

function createPieceS(myPiece)
    for i=1,3 do
        pieces[myPiece][i] = {}
    end
    pieces[myPiece][1][1] = false
    pieces[myPiece][2][1] = true
    pieces[myPiece][3][1] = true
    pieces[myPiece][1][2] = true
    pieces[myPiece][2][2] = true
    pieces[myPiece][3][2] = false
end

function createPieceT(myPiece)
    for i=1,3 do
        pieces[myPiece][i] = {}
    end
    pieces[myPiece][1][1] = false
    pieces[myPiece][2][1] = true
    pieces[myPiece][3][1] = false
    pieces[myPiece][1][2] = true
    pieces[myPiece][2][2] = true
    pieces[myPiece][3][2] = true
end

function createPieceZ(myPiece)
    for i=1,3 do
        pieces[myPiece][i] = {}
    end
    pieces[myPiece][1][1] = true
    pieces[myPiece][2][1] = true
    pieces[myPiece][3][1] = false
    pieces[myPiece][1][2] = false
    pieces[myPiece][2][2] = true
    pieces[myPiece][3][2] = true
end

--Load the images
function createImages()
    cubes[gray] = love.graphics.newImage("images/cubeGray.png")
    cubes[red] = love.graphics.newImage("images/cubeRed.png")
    cubes[orange] = love.graphics.newImage("images/cubeOrange.png")
    cubes[yellow] = love.graphics.newImage("images/cubeYellow.png")
    cubes[green] = love.graphics.newImage("images/cubeGreen.png")
    cubes[cyan] = love.graphics.newImage("images/cubeCyan.png")
    cubes[blue] = love.graphics.newImage("images/cubeBlue.png")
    cubes[violet] = love.graphics.newImage("images/cubeViolet.png")
end

--Renders the current block to the screen
function renderBlock(blockToDraw)
    local pieceToDraw = blockToDraw[piece]
    local x = blockToDraw[col]
    local y = blockToDraw[row]

    for i=1,blockToDraw[width] do
        for j=1,blockToDraw[height] do
            if pieceToDraw[i][j] then
                love.graphics.draw(cubes[blockToDraw[color]], tileX*(x+i-2), tileY*(y+j-2))
            end
            j=j+1
        end
        i=i+1
    end
end

--Randomly chooses a new block to drop and returns it
function getNewBlock()
    math.random()
    math.random()
    math.random()
  
    local newPiece = math.random(pieceI, pieceZ)
    local newRow = 1
    local newCol = pieceCentering[newPiece] + 1
  
    local newBlock = {}
    newBlock[piece] = pieces[newPiece]
    newBlock[col] = newCol
    newBlock[row] = newRow
  
    local i=1
    local j=1
    while pieces[newPiece][i]~=nil do
            while pieces[newPiece][i][j]~=nil do
                j=j+1
            end
        i=i+1
    end
    newBlock[width] = i-1
    newBlock[height] = j-1
    newBlock[color] = newPiece
    newBlock[rotation] = 1
  
    return newBlock
end

--Draws to the screen, called continuously
function love.draw()
    if gameState == pause then
        renderPause()
        return
    end

    renderTitle()
    renderScore()
  
    if gameOver then
        renderGameOver()
        return
    end
  
    for i=1, boardX do
        for j=1, boardY do
            love.graphics.draw(cubes[board[i][j]], tileX * (i-1), tileY * (j-1))
        end
    end
  
    renderBlock(activeBlock)
    renderQueueBlock(queueBlock)
end

--Renders Game Over screen
function renderGameOver()
    local toPrintA = "Game Over"
    local textWidthA = medFont:getWidth(toPrintA)
    local boardWidth = boardX*tileX
  
    love.graphics.setFont(medFont)
    --love.graphics.setScreen("bottom")
    love.graphics.print(toPrintA, (boardWidth-textWidthA)/2, 100)
    --love.graphics.setScreen("top")
  
    if gameOverTimer > gameOverDelay then
        local toPrintB = "Press any key to play again"
        local textWidthB = smallFont:getWidth(toPrintB)
        love.graphics.setFont(smallFont)
        --love.graphics.setScreen("bottom")
        love.graphics.print(toPrintB, (boardWidth-textWidthB)/2, 200)
        --love.graphics.setScreen("top")
    end
end

--Draw the game title
function renderTitle()
    local toPrint = "Tetris"
    local textWidth = bigFont:getWidth(toPrint)
    local boardWidth = boardX*tileX
  
    love.graphics.setFont(bigFont)
    --love.graphics.setScreen("bottom")
    love.graphics.print(toPrint, (boardWidth+screenX-textWidth)/2, 50)
    --love.graphics.setScreen("top")
end

--Draw the pause screen
function renderPause()
    local toPrint = "Game Paused"
    local textWidth = medFont:getWidth(toPrint)
    local textHeight = medFont:getHeight()
  
    love.graphics.setFont(medFont)
    --love.graphics.setScreen("bottom")
    love.graphics.print(toPrint, (screenX-textWidth)/2, (screenY-textHeight)/2)
    --love.graphics.setScreen("top")
end

--Update function, handles teh logics
function love.update(dt)
    if gameOver then
        gameOverTimer = gameOverTimer + dt
        return
    end
  
    if gameState == pause then
        return
    end
  
    tryRemoveRows()
  
    keyPressTimerL = keyPressTimerL - dt
    keyPressTimerR = keyPressTimerR - dt
    keyPressTimerU = keyPressTimerU - dt
    keyPressTimerD = keyPressTimerD - dt
  
    if keyPressTimerU <= 0 then
        if love.keyboard.isDown("up") or love.keyboard.isDown("x") then
            attemptRotation()
            keyPressTimerU = rotPressDelay
        end
    end
      
    if keyPressTimerL <= 0 then
        if love.keyboard.isDown("left") then
            if checkBlockedLeft()==false then
                activeBlock[col] = activeBlock[col] - 1
            end
            keyPressTimerL = keyPressDelay
        end
    end

    if keyPressTimerR <= 0 then
        if love.keyboard.isDown("right") then
            if checkBlockedRight()==false then
                activeBlock[col] = activeBlock[col] + 1
            end
            keyPressTimerR = keyPressDelay
        end
    end
      
    if keyPressTimerD <= 0 then
        if love.keyboard.isDown("down") then
            if checkBlockedDown() then
                addBlockToBoard()
            else
                activeBlock[row] = activeBlock[row] + 1
            end
            keyPressTimerD = keyPressDelay
        end
    end
  
    --Keeping the check here allows for 'wall kicks'
    --Wall kicks are larger at slower descent speeds
    --Add a check before the key press checks to eliminate wall kicks
    descentTimer = descentTimer - dt
    if descentTimer <=0 then
        descentTimer = descentDelay
        if checkBlockedDown() then
            addBlockToBoard()
        else
            activeBlock[row] = activeBlock[row] + 1
        end
    end  
end

function love.keypressed(key)
    if gameOver then
        if gameOverTimer > gameOverDelay then
            beginGame()
            return
        end
    end

    if key == "start" then
        if gameState == play then
            gameState = pause
        elseif gameState == pause then
            gameState = play
        end
    end
  
    if key == "select" then
        love.event.quit()
    end
end

--Returns true if a block has 'landed'
function checkBlockedDown()
    if activeBlock[row] + activeBlock[height] > boardY then
        return true
    end
    for i=1,activeBlock[width] do
        for j=1, activeBlock[height] do
            if activeBlock[piece][i][j] then
                if board[activeBlock[col]+i-1]~=nil then
                    if board[activeBlock[col]+i-1][activeBlock[row]+j]~=nil then
                        if board[activeBlock[col]+i-1][activeBlock[row]+j]~=gray then
                            return true
                        end
                    end
                end
            end
        end
    end
    return false
end

--Returns true if a block can't slide to the left
function checkBlockedLeft()
    if activeBlock[col] < 2 then
        return true
    end
    for i=1,activeBlock[width] do
        for j=1,activeBlock[height] do
            if activeBlock[piece][i][j] then
                if board[activeBlock[col]+i-2]~=nil then
                    if board[activeBlock[col]+i-2][activeBlock[row]+j-1]~=nil then
                        if board[activeBlock[col]+i-2][activeBlock[row]+j-1]~=gray then
                            return true
                        end
                    end
                end
            end
        end
    end
    return false
end

--Returns true if a block can't slide to the right
function checkBlockedRight()
    if activeBlock[col] + activeBlock[width] > boardX then
        return true
    end
    for i=1,activeBlock[width] do
        for j=1,activeBlock[height] do
            if activeBlock[piece][i][j] then
                if board[activeBlock[col]+i]~=nil then
                    if board[activeBlock[col]+i][activeBlock[row]+j-1]~=nil then
                        if board[activeBlock[col]+i][activeBlock[row]+j-1]~=gray then
                            return true
                        end
                    end
                end
            end
        end
    end
    return false
end

--Returns true if a block is in a legal position
function checkLegal(blockToCheck)
    for i=1,blockToCheck[width] do
        for j=1,blockToCheck[height] do
            if blockToCheck[piece][i][j] then
                if board[blockToCheck[col]+i-1] == nil then
                    return false
                elseif board[blockToCheck[col]+i-1][blockToCheck[row]+j-1] == nil then
                    return false
                elseif board[blockToCheck[col]+i-1][blockToCheck[row]+j-1]~=gray then
                    return false
                end
            end
        end
    end
    return true
end

--Attempts to rotate a piece clockwise, does nothing if illegal
function attemptRotation()
    --No sense rotating the box piece
    if activeBlock[color] == pieceO then
        return
    end
  
    local newBlock = {}
    newBlock[piece] = {}
    newBlock[color] = activeBlock[color]
    newBlock[rotation] = activeBlock[rotation]+1
    if newBlock[rotation] == 5 then
        newBlock[rotation] = 1
    end

    if activeBlock[color] == pieceI or activeBlock[color] == pieceS or activeBlock[color] == pieceZ then
        if activeBlock[rotation] == 1 then
            newBlock[col] = activeBlock[col]-math.floor((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.ceil((activeBlock[width]-activeBlock[height])/2)
        elseif activeBlock[rotation] == 2 then
            newBlock[col] = activeBlock[col]-math.ceil((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.floor((activeBlock[width]-activeBlock[height])/2)
        elseif activeBlock[rotation] == 3 then
            newBlock[col] = activeBlock[col]-math.floor((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.ceil((activeBlock[width]-activeBlock[height])/2)
        elseif activeBlock[rotation] == 4 then
            newBlock[col] = activeBlock[col]-math.ceil((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.floor((activeBlock[width]-activeBlock[height])/2)
        end
    else
        if activeBlock[rotation] == 1 then
            newBlock[col] = activeBlock[col]-math.floor((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.floor((activeBlock[width]-activeBlock[height])/2)
        elseif activeBlock[rotation] == 2 then
            newBlock[col] = activeBlock[col]-math.ceil((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.floor((activeBlock[width]-activeBlock[height])/2)
        elseif activeBlock[rotation] == 3 then
            newBlock[col] = activeBlock[col]-math.ceil((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.ceil((activeBlock[width]-activeBlock[height])/2)
        elseif activeBlock[rotation] == 4 then
            newBlock[col] = activeBlock[col]-math.floor((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.ceil((activeBlock[width]-activeBlock[height])/2)
        end
    end
  
    newBlock[height] = activeBlock[width]
    newBlock[width] = activeBlock[height]
  
    for i=1,newBlock[width] do
        newBlock[piece][i] = {}
    end
  
    for i=1,activeBlock[width] do
        for j=1,activeBlock[height] do
            newBlock[piece][activeBlock[height]-j+1][i] = activeBlock[piece][i][j]
        end
    end
  
    if checkLegal(newBlock)==true then
        activeBlock = newBlock
    else
        bump(newBlock)
        if checkLegal(newBlock)==true then
            activeBlock = newBlock
        end
    end
end

--Attempts to 'bump' a piece back on to the board, to allow for more flexibility when rotating
function bump(blockToBump)
    if blockToBump[row] < 1 then
        blockToBump[row] = 1
    end
  
    if blockToBump[col] < 1 then
        blockToBump[col] = 1  
    elseif (blockToBump[col]+blockToBump[width]-1) > boardX then
        blockToBump[col] = boardX-blockToBump[width]+1
    end
end

--Puts a block on the board and gets a new block
function addBlockToBoard()
    for i=1,activeBlock[width] do
        for j=1,activeBlock[height] do
            if activeBlock[piece][i][j] then
                board[activeBlock[col]+i-1][activeBlock[row]+j-1] = activeBlock[color]
            end
        end
    end
  
    activeBlock = queueBlock
  
    --Check to see if game is over
    if checkLegal(activeBlock)==false then
        gameOver = true
    end
  
    queueBlock = getNewBlock()
end

--Attempt to remove completed rows
function tryRemoveRows()

    local completedRows = {}
    local numCompleted = 0
    local newBoard = createBoard()
  
    for j=boardY,1,-1 do
        completedRows[j] = true
        for i=1,boardX do
            if board[i][j] == gray then
                completedRows[j] = false
                break
            end
        end
    end
  
    for j=boardY,1,-1 do
        if completedRows[j] then
            numCompleted = numCompleted+1
        end
        for i=1,boardX do
            if j-numCompleted > 0 then
                newBoard[i][j] = board[i][j-numCompleted]
            end
        end
    end
  
    if numCompleted > 0 then
        addToScore(numCompleted)
    end
  
    board = newBoard
end

--Updates current score and increase speed if appropriate
function addToScore(lines)
    local scoreIncrease = (lines*(lines+1))/2
    score = score+scoreIncrease
  
    --If descentDelay isn't greater than minDelay, we're done increasing speed
    if descentDelay > minDelay then
        scoreThresholdTracker = scoreThresholdTracker+scoreIncrease
      
        --Increase speed
        while scoreThresholdTracker >= scoreDelayThreshold do
            scoreThresholdTracker = scoreThresholdTracker-scoreDelayThreshold
            descentDelay = descentDelay-speedIncrease
        end
    end
end

--Draws score to screen
function renderScore()
    local toPrint = "Score: " .. score
    local textWidth = medFont:getWidth(toPrint)
    local boardWidth = boardX*tileX
  
    love.graphics.setFont(medFont)
    --love.graphics.setScreen("bottom")
    love.graphics.print(toPrint, (boardWidth+screenX-textWidth)/2, 150)
    --love.graphics.setScreen("top")
end

--Draws upcoming block
function renderQueueBlock(blockToDraw)
    local toPrint = "Next Piece:"
    local textWidth = medFont:getWidth(toPrint)
    local boardWidth = boardX*tileX
  
    love.graphics.setFont(medFont)
    --love.graphics.setScreen("bottom")
    love.graphics.print(toPrint, (boardWidth+screenX-textWidth)/2, 250)
    --love.graphics.setScreen("top")
  
    local pieceToDraw = blockToDraw[piece]
    local x = blockToDraw[col] + 9
    local y = 12
  
    local centering = 0
    if blockToDraw[col] == 5 then
        if blockToDraw[width] > 2 then
            centering = -16
        end
    elseif blockToDraw[width] == 3 then
        centering = 16
    end

    for i=1,blockToDraw[width] do
        for j=1,blockToDraw[height] do
            if pieceToDraw[i][j] then
                love.graphics.draw(cubes[blockToDraw[color]], (tileX*(x+i-2))+centering, tileY*(y+j-2))
            end
            j=j+1
        end
        i=i+1
    end
end

--Run at the beginning of each game
function beginGame()
    board = createBoard()
    descentTimer = 0
    keyPressTimerL = 0
    keyPressTimerR = 0
    keyPressTimerU = 0
    keyPressTimerD = 0
    score = 0
    scoreThresholdTracker = 0
    gameOver = false
    gameState = play
    gameOverTimer = 0
  
    activeBlock = {}
    queueBlock = {}
    activeBlock = getNewBlock()
    queueBlock = getNewBlock()
end

--Run once at game start
function love.load()
    --love.graphics.setScreen("top")
    createImages()
    createPieces()
    math.randomseed(os.time())
    smallFont = love.graphics.newFont("fonts/BAUHS93.TTF", 24)
    medFont = love.graphics.newFont("fonts/BAUHS93.TTF", 36)
    bigFont = love.graphics.newFont("fonts/BAUHS93.TTF", 48)
  
    beginGame()
end

all image files are 16x16 squares of different colours
 
Last edited by CKlidify,

TurtleP

Well-Known Member
Member
Joined
Oct 7, 2015
Messages
140
Trophies
0
Age
28
Website
TurtleP.github.io
XP
308
Country
United States
love.window.getHeight is depreciated in this. He's following the 0.10.0 api for Löve if I remember correctly. I don't get why, but it was a choice the makers of Löve made.
 

VideahGams

Well-Known Member
OP
Newcomer
Joined
Aug 29, 2015
Messages
91
Trophies
0
Age
25
Location
Glasgow, Scotland
Website
videah.xyz
XP
146
Country
Will you soon implement the window.getHeight function? It would help a lot.

As TurtleP said, love.window.getHeight is depreciated. Use love.graphics.getHeight instead (exact same functionailty)

I'm trying to make a port of an already existing tetris game for Love2D and it's using functions supported by LovePotion so I was wondering why the game starts, freezes, but you can still pause and unpause:

Code:
--Global variables
screenX = 400
screenY = 240

boardX = 10
boardY = 15

tileX = 16
tileY = 16

cubes = {}
gray = 1
red = 2
orange = 3
yellow = 4
green = 5
cyan = 6
blue = 7
violet = 8

pieceI = 2
pieceJ = 3
pieceL = 4
pieceO = 5
pieceS = 6
pieceT = 7
pieceZ = 8

pieceCentering = {}
pieceCentering[pieceI] = 3
pieceCentering[pieceJ] = 3
pieceCentering[pieceL] = 4
pieceCentering[pieceO] = 4
pieceCentering[pieceS] = 4
pieceCentering[pieceT] = 3
pieceCentering[pieceZ] = 3

piece = 0
col = 1
row = 2
width = 3
height = 4
color = 5
rotation = 6

rotPressDelay = 0.2 --Amount of time between rotation key presses
keyPressDelay = 0.1 --Amount of time between non-rotation key presses
descentDelay = 1 --Amount of time for a piece to drop one square at game start
minDelay = 0.05 --Minimum descent delay (never gets faster than this)
scoreDelayThreshold = 10 --Score threshold for increase in descent speed
speedIncrease = 0.05 --Reduction in time for a piece to drop when threshold is hit
gameOverDelay = 3 --Amount of time between game over and ability to hit a key to continue

play = 0
pause = 1
menu = 2

--Create a board
function createBoard()
    myBoard = {}
 
    for i=1, boardX do
        myBoard[i] = {}
        for j=1, boardY do
            myBoard[i][j] = gray
        end
    end
 
    return myBoard
end

--Set up the pieces
function createPieces()
    pieces = {}
 
    for i=pieceI, pieceZ do
        pieces[i] = {}
    end
 
    createPieceI(pieceI)
    createPieceJ(pieceJ)
    createPieceL(pieceL)
    createPieceO(pieceO)
    createPieceS(pieceS)
    createPieceT(pieceT)
    createPieceZ(pieceZ)
end

function createPieceI(myPiece)
    for i=1,4 do
        pieces[myPiece][i] = {}
        pieces[myPiece][i][1] = true
    end
end

function createPieceJ(myPiece)
    for i=1,3 do
        pieces[myPiece][i] = {}
    end
    pieces[myPiece][1][1] = true
    pieces[myPiece][2][1] = false
    pieces[myPiece][3][1] = false
    pieces[myPiece][1][2] = true
    pieces[myPiece][2][2] = true
    pieces[myPiece][3][2] = true
end

function createPieceL(myPiece)
    for i=1,3 do
        pieces[myPiece][i] = {}
    end
    pieces[myPiece][1][1] = false
    pieces[myPiece][2][1] = false
    pieces[myPiece][3][1] = true
    pieces[myPiece][1][2] = true
    pieces[myPiece][2][2] = true
    pieces[myPiece][3][2] = true
end

function createPieceO(myPiece)
    for i=1,2 do
        pieces[myPiece][i] = {}
        for j=1,2 do
            pieces[myPiece][i][j] = true
        end
    end
end

function createPieceS(myPiece)
    for i=1,3 do
        pieces[myPiece][i] = {}
    end
    pieces[myPiece][1][1] = false
    pieces[myPiece][2][1] = true
    pieces[myPiece][3][1] = true
    pieces[myPiece][1][2] = true
    pieces[myPiece][2][2] = true
    pieces[myPiece][3][2] = false
end

function createPieceT(myPiece)
    for i=1,3 do
        pieces[myPiece][i] = {}
    end
    pieces[myPiece][1][1] = false
    pieces[myPiece][2][1] = true
    pieces[myPiece][3][1] = false
    pieces[myPiece][1][2] = true
    pieces[myPiece][2][2] = true
    pieces[myPiece][3][2] = true
end

function createPieceZ(myPiece)
    for i=1,3 do
        pieces[myPiece][i] = {}
    end
    pieces[myPiece][1][1] = true
    pieces[myPiece][2][1] = true
    pieces[myPiece][3][1] = false
    pieces[myPiece][1][2] = false
    pieces[myPiece][2][2] = true
    pieces[myPiece][3][2] = true
end

--Load the images
function createImages()
    cubes[gray] = love.graphics.newImage("images/cubeGray.png")
    cubes[red] = love.graphics.newImage("images/cubeRed.png")
    cubes[orange] = love.graphics.newImage("images/cubeOrange.png")
    cubes[yellow] = love.graphics.newImage("images/cubeYellow.png")
    cubes[green] = love.graphics.newImage("images/cubeGreen.png")
    cubes[cyan] = love.graphics.newImage("images/cubeCyan.png")
    cubes[blue] = love.graphics.newImage("images/cubeBlue.png")
    cubes[violet] = love.graphics.newImage("images/cubeViolet.png")
end

--Renders the current block to the screen
function renderBlock(blockToDraw)
    local pieceToDraw = blockToDraw[piece]
    local x = blockToDraw[col]
    local y = blockToDraw[row]

    for i=1,blockToDraw[width] do
        for j=1,blockToDraw[height] do
            if pieceToDraw[i][j] then
                love.graphics.draw(cubes[blockToDraw[color]], tileX*(x+i-2), tileY*(y+j-2))
            end
            j=j+1
        end
        i=i+1
    end
end

--Randomly chooses a new block to drop and returns it
function getNewBlock()
    math.random()
    math.random()
    math.random()
 
    local newPiece = math.random(pieceI, pieceZ)
    local newRow = 1
    local newCol = pieceCentering[newPiece] + 1
 
    local newBlock = {}
    newBlock[piece] = pieces[newPiece]
    newBlock[col] = newCol
    newBlock[row] = newRow
 
    local i=1
    local j=1
    while pieces[newPiece][i]~=nil do
            while pieces[newPiece][i][j]~=nil do
                j=j+1
            end
        i=i+1
    end
    newBlock[width] = i-1
    newBlock[height] = j-1
    newBlock[color] = newPiece
    newBlock[rotation] = 1
 
    return newBlock
end

--Draws to the screen, called continuously
function love.draw()
    if gameState == pause then
        renderPause()
        return
    end

    renderTitle()
    renderScore()
 
    if gameOver then
        renderGameOver()
        return
    end
 
    for i=1, boardX do
        for j=1, boardY do
            love.graphics.draw(cubes[board[i][j]], tileX * (i-1), tileY * (j-1))
        end
    end
 
    renderBlock(activeBlock)
    renderQueueBlock(queueBlock)
end

--Renders Game Over screen
function renderGameOver()
    local toPrintA = "Game Over"
    local textWidthA = medFont:getWidth(toPrintA)
    local boardWidth = boardX*tileX
 
    love.graphics.setFont(medFont)
    --love.graphics.setScreen("bottom")
    love.graphics.print(toPrintA, (boardWidth-textWidthA)/2, 100)
    --love.graphics.setScreen("top")
 
    if gameOverTimer > gameOverDelay then
        local toPrintB = "Press any key to play again"
        local textWidthB = smallFont:getWidth(toPrintB)
        love.graphics.setFont(smallFont)
        --love.graphics.setScreen("bottom")
        love.graphics.print(toPrintB, (boardWidth-textWidthB)/2, 200)
        --love.graphics.setScreen("top")
    end
end

--Draw the game title
function renderTitle()
    local toPrint = "Tetris"
    local textWidth = bigFont:getWidth(toPrint)
    local boardWidth = boardX*tileX
 
    love.graphics.setFont(bigFont)
    --love.graphics.setScreen("bottom")
    love.graphics.print(toPrint, (boardWidth+screenX-textWidth)/2, 50)
    --love.graphics.setScreen("top")
end

--Draw the pause screen
function renderPause()
    local toPrint = "Game Paused"
    local textWidth = medFont:getWidth(toPrint)
    local textHeight = medFont:getHeight()
 
    love.graphics.setFont(medFont)
    --love.graphics.setScreen("bottom")
    love.graphics.print(toPrint, (screenX-textWidth)/2, (screenY-textHeight)/2)
    --love.graphics.setScreen("top")
end

--Update function, handles teh logics
function love.update(dt)
    if gameOver then
        gameOverTimer = gameOverTimer + dt
        return
    end
 
    if gameState == pause then
        return
    end
 
    tryRemoveRows()
 
    keyPressTimerL = keyPressTimerL - dt
    keyPressTimerR = keyPressTimerR - dt
    keyPressTimerU = keyPressTimerU - dt
    keyPressTimerD = keyPressTimerD - dt
 
    if keyPressTimerU <= 0 then
        if love.keyboard.isDown("up") or love.keyboard.isDown("x") then
            attemptRotation()
            keyPressTimerU = rotPressDelay
        end
    end
     
    if keyPressTimerL <= 0 then
        if love.keyboard.isDown("left") then
            if checkBlockedLeft()==false then
                activeBlock[col] = activeBlock[col] - 1
            end
            keyPressTimerL = keyPressDelay
        end
    end

    if keyPressTimerR <= 0 then
        if love.keyboard.isDown("right") then
            if checkBlockedRight()==false then
                activeBlock[col] = activeBlock[col] + 1
            end
            keyPressTimerR = keyPressDelay
        end
    end
     
    if keyPressTimerD <= 0 then
        if love.keyboard.isDown("down") then
            if checkBlockedDown() then
                addBlockToBoard()
            else
                activeBlock[row] = activeBlock[row] + 1
            end
            keyPressTimerD = keyPressDelay
        end
    end
 
    --Keeping the check here allows for 'wall kicks'
    --Wall kicks are larger at slower descent speeds
    --Add a check before the key press checks to eliminate wall kicks
    descentTimer = descentTimer - dt
    if descentTimer <=0 then
        descentTimer = descentDelay
        if checkBlockedDown() then
            addBlockToBoard()
        else
            activeBlock[row] = activeBlock[row] + 1
        end
    end 
end

function love.keypressed(key)
    if gameOver then
        if gameOverTimer > gameOverDelay then
            beginGame()
            return
        end
    end

    if key == "start" then
        if gameState == play then
            gameState = pause
        elseif gameState == pause then
            gameState = play
        end
    end
 
    if key == "select" then
        love.event.quit()
    end
end

--Returns true if a block has 'landed'
function checkBlockedDown()
    if activeBlock[row] + activeBlock[height] > boardY then
        return true
    end
    for i=1,activeBlock[width] do
        for j=1, activeBlock[height] do
            if activeBlock[piece][i][j] then
                if board[activeBlock[col]+i-1]~=nil then
                    if board[activeBlock[col]+i-1][activeBlock[row]+j]~=nil then
                        if board[activeBlock[col]+i-1][activeBlock[row]+j]~=gray then
                            return true
                        end
                    end
                end
            end
        end
    end
    return false
end

--Returns true if a block can't slide to the left
function checkBlockedLeft()
    if activeBlock[col] < 2 then
        return true
    end
    for i=1,activeBlock[width] do
        for j=1,activeBlock[height] do
            if activeBlock[piece][i][j] then
                if board[activeBlock[col]+i-2]~=nil then
                    if board[activeBlock[col]+i-2][activeBlock[row]+j-1]~=nil then
                        if board[activeBlock[col]+i-2][activeBlock[row]+j-1]~=gray then
                            return true
                        end
                    end
                end
            end
        end
    end
    return false
end

--Returns true if a block can't slide to the right
function checkBlockedRight()
    if activeBlock[col] + activeBlock[width] > boardX then
        return true
    end
    for i=1,activeBlock[width] do
        for j=1,activeBlock[height] do
            if activeBlock[piece][i][j] then
                if board[activeBlock[col]+i]~=nil then
                    if board[activeBlock[col]+i][activeBlock[row]+j-1]~=nil then
                        if board[activeBlock[col]+i][activeBlock[row]+j-1]~=gray then
                            return true
                        end
                    end
                end
            end
        end
    end
    return false
end

--Returns true if a block is in a legal position
function checkLegal(blockToCheck)
    for i=1,blockToCheck[width] do
        for j=1,blockToCheck[height] do
            if blockToCheck[piece][i][j] then
                if board[blockToCheck[col]+i-1] == nil then
                    return false
                elseif board[blockToCheck[col]+i-1][blockToCheck[row]+j-1] == nil then
                    return false
                elseif board[blockToCheck[col]+i-1][blockToCheck[row]+j-1]~=gray then
                    return false
                end
            end
        end
    end
    return true
end

--Attempts to rotate a piece clockwise, does nothing if illegal
function attemptRotation()
    --No sense rotating the box piece
    if activeBlock[color] == pieceO then
        return
    end
 
    local newBlock = {}
    newBlock[piece] = {}
    newBlock[color] = activeBlock[color]
    newBlock[rotation] = activeBlock[rotation]+1
    if newBlock[rotation] == 5 then
        newBlock[rotation] = 1
    end

    if activeBlock[color] == pieceI or activeBlock[color] == pieceS or activeBlock[color] == pieceZ then
        if activeBlock[rotation] == 1 then
            newBlock[col] = activeBlock[col]-math.floor((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.ceil((activeBlock[width]-activeBlock[height])/2)
        elseif activeBlock[rotation] == 2 then
            newBlock[col] = activeBlock[col]-math.ceil((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.floor((activeBlock[width]-activeBlock[height])/2)
        elseif activeBlock[rotation] == 3 then
            newBlock[col] = activeBlock[col]-math.floor((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.ceil((activeBlock[width]-activeBlock[height])/2)
        elseif activeBlock[rotation] == 4 then
            newBlock[col] = activeBlock[col]-math.ceil((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.floor((activeBlock[width]-activeBlock[height])/2)
        end
    else
        if activeBlock[rotation] == 1 then
            newBlock[col] = activeBlock[col]-math.floor((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.floor((activeBlock[width]-activeBlock[height])/2)
        elseif activeBlock[rotation] == 2 then
            newBlock[col] = activeBlock[col]-math.ceil((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.floor((activeBlock[width]-activeBlock[height])/2)
        elseif activeBlock[rotation] == 3 then
            newBlock[col] = activeBlock[col]-math.ceil((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.ceil((activeBlock[width]-activeBlock[height])/2)
        elseif activeBlock[rotation] == 4 then
            newBlock[col] = activeBlock[col]-math.floor((activeBlock[height]-activeBlock[width])/2)
            newBlock[row] = activeBlock[row]-math.ceil((activeBlock[width]-activeBlock[height])/2)
        end
    end
 
    newBlock[height] = activeBlock[width]
    newBlock[width] = activeBlock[height]
 
    for i=1,newBlock[width] do
        newBlock[piece][i] = {}
    end
 
    for i=1,activeBlock[width] do
        for j=1,activeBlock[height] do
            newBlock[piece][activeBlock[height]-j+1][i] = activeBlock[piece][i][j]
        end
    end
 
    if checkLegal(newBlock)==true then
        activeBlock = newBlock
    else
        bump(newBlock)
        if checkLegal(newBlock)==true then
            activeBlock = newBlock
        end
    end
end

--Attempts to 'bump' a piece back on to the board, to allow for more flexibility when rotating
function bump(blockToBump)
    if blockToBump[row] < 1 then
        blockToBump[row] = 1
    end
 
    if blockToBump[col] < 1 then
        blockToBump[col] = 1 
    elseif (blockToBump[col]+blockToBump[width]-1) > boardX then
        blockToBump[col] = boardX-blockToBump[width]+1
    end
end

--Puts a block on the board and gets a new block
function addBlockToBoard()
    for i=1,activeBlock[width] do
        for j=1,activeBlock[height] do
            if activeBlock[piece][i][j] then
                board[activeBlock[col]+i-1][activeBlock[row]+j-1] = activeBlock[color]
            end
        end
    end
 
    activeBlock = queueBlock
 
    --Check to see if game is over
    if checkLegal(activeBlock)==false then
        gameOver = true
    end
 
    queueBlock = getNewBlock()
end

--Attempt to remove completed rows
function tryRemoveRows()

    local completedRows = {}
    local numCompleted = 0
    local newBoard = createBoard()
 
    for j=boardY,1,-1 do
        completedRows[j] = true
        for i=1,boardX do
            if board[i][j] == gray then
                completedRows[j] = false
                break
            end
        end
    end
 
    for j=boardY,1,-1 do
        if completedRows[j] then
            numCompleted = numCompleted+1
        end
        for i=1,boardX do
            if j-numCompleted > 0 then
                newBoard[i][j] = board[i][j-numCompleted]
            end
        end
    end
 
    if numCompleted > 0 then
        addToScore(numCompleted)
    end
 
    board = newBoard
end

--Updates current score and increase speed if appropriate
function addToScore(lines)
    local scoreIncrease = (lines*(lines+1))/2
    score = score+scoreIncrease
 
    --If descentDelay isn't greater than minDelay, we're done increasing speed
    if descentDelay > minDelay then
        scoreThresholdTracker = scoreThresholdTracker+scoreIncrease
     
        --Increase speed
        while scoreThresholdTracker >= scoreDelayThreshold do
            scoreThresholdTracker = scoreThresholdTracker-scoreDelayThreshold
            descentDelay = descentDelay-speedIncrease
        end
    end
end

--Draws score to screen
function renderScore()
    local toPrint = "Score: " .. score
    local textWidth = medFont:getWidth(toPrint)
    local boardWidth = boardX*tileX
 
    love.graphics.setFont(medFont)
    --love.graphics.setScreen("bottom")
    love.graphics.print(toPrint, (boardWidth+screenX-textWidth)/2, 150)
    --love.graphics.setScreen("top")
end

--Draws upcoming block
function renderQueueBlock(blockToDraw)
    local toPrint = "Next Piece:"
    local textWidth = medFont:getWidth(toPrint)
    local boardWidth = boardX*tileX
 
    love.graphics.setFont(medFont)
    --love.graphics.setScreen("bottom")
    love.graphics.print(toPrint, (boardWidth+screenX-textWidth)/2, 250)
    --love.graphics.setScreen("top")
 
    local pieceToDraw = blockToDraw[piece]
    local x = blockToDraw[col] + 9
    local y = 12
 
    local centering = 0
    if blockToDraw[col] == 5 then
        if blockToDraw[width] > 2 then
            centering = -16
        end
    elseif blockToDraw[width] == 3 then
        centering = 16
    end

    for i=1,blockToDraw[width] do
        for j=1,blockToDraw[height] do
            if pieceToDraw[i][j] then
                love.graphics.draw(cubes[blockToDraw[color]], (tileX*(x+i-2))+centering, tileY*(y+j-2))
            end
            j=j+1
        end
        i=i+1
    end
end

--Run at the beginning of each game
function beginGame()
    board = createBoard()
    descentTimer = 0
    keyPressTimerL = 0
    keyPressTimerR = 0
    keyPressTimerU = 0
    keyPressTimerD = 0
    score = 0
    scoreThresholdTracker = 0
    gameOver = false
    gameState = play
    gameOverTimer = 0
 
    activeBlock = {}
    queueBlock = {}
    activeBlock = getNewBlock()
    queueBlock = getNewBlock()
end

--Run once at game start
function love.load()
    --love.graphics.setScreen("top")
    createImages()
    createPieces()
    math.randomseed(os.time())
    smallFont = love.graphics.newFont("fonts/BAUHS93.TTF", 24)
    medFont = love.graphics.newFont("fonts/BAUHS93.TTF", 36)
    bigFont = love.graphics.newFont("fonts/BAUHS93.TTF", 48)
 
    beginGame()
end

all image files are 16x16 squares of different colours

I'll look over your code in a bit to see what's wrong.
 

VideahGams

Well-Known Member
OP
Newcomer
Joined
Aug 29, 2015
Messages
91
Trophies
0
Age
25
Location
Glasgow, Scotland
Website
videah.xyz
XP
146
Country
New release is out!
Sorry for the slow development, real life is catching up to me a little. I'll hopefully speed up development in the coming weeks.

New stuff includes:

3D Support!
You can now take advantage of the 3DS's, well, 3D!
To enable, just use love.graphics.set3D(true), and then set draw call depths with love.graphics.setDepth(insertDepthHere).
The slider is automatically managed by LövePotion, so no need to worry about it.

love.quit Callback
This callback is called when LövePotion is quitting, so you can put your cleanup code here.

Various Fixes
  • Fixed weird delta-timing bug (Which would mess with timers)
  • Added a font limit of 2 fonts to prevent crashes (For now at least)
  • love.graphics.setColor() now notifies you of unimplemented table argument feature
Current ToDo List:
  • Implement love.filesystem
  • Implement love.math
  • Implement love.audio
  • Implement console option for debugging
  • Fix font crash
  • Finish implementation of various small things
  • Sockets (?)
  • LuaJIT (?)
 

ketal

aiueo
Member
Joined
Aug 20, 2015
Messages
744
Trophies
0
XP
677
Country
Italy
3D Support!
You can now take advantage of the 3DS's, well, 3D!
To enable, just use love.graphics.set3D(true), and then set draw call depths with love.graphics.setDepth(insertDepthHere).
The slider is automatically managed by LövePotion, so no need to worry about it.
Oh my god this is awesome
 

VideahGams

Well-Known Member
OP
Newcomer
Joined
Aug 29, 2015
Messages
91
Trophies
0
Age
25
Location
Glasgow, Scotland
Website
videah.xyz
XP
146
Country
Did you ever have a chance to look over my tetris code?

I haven't been able to test it, but my theory of the crash is because you are creating 3 fonts.
Currently, LövePotion has some issues if more than 2 fonts are made (See here.)
Hopefully these will be fixed in the future when it is found out why this happens.

Of course, you can try on the latest build to see if things are fixed (It could have been the delta time bug that was causing the problem)
 
Last edited by VideahGams,

CKlidify

Well-Known Member
Newcomer
Joined
May 31, 2015
Messages
70
Trophies
0
XP
208
Country
Canada
I haven't been able to test it, but my theory of the crash is because you are creating 3 fonts.
Currently, LövePotion has some issues if more than 2 fonts are made (See here.)
Hopefully these will be fixed in the future when it is found out why this happens.

Of course, you can try on the latest build to see if things are fixed (It could have been the delta time bug that was causing the problem)
I changed it to use only 2 fonts but it still does the same thing. The block stays at the top of the screen and doesn't move down, but I can still press start to show the Game Paused screen and press select to end the application
 

VideahGams

Well-Known Member
OP
Newcomer
Joined
Aug 29, 2015
Messages
91
Trophies
0
Age
25
Location
Glasgow, Scotland
Website
videah.xyz
XP
146
Country
I changed it to use only 2 fonts but it still does the same thing. The block stays at the top of the screen and doesn't move down, but I can still press start to show the Game Paused screen and press select to end the application

Can you send me the code + graphics so I can test it myself and find whats wrong?
 

sweis12

Well-Known Member
Member
Joined
Oct 20, 2013
Messages
1,248
Trophies
0
Age
32
XP
1,368
Country
Saint Kitts and Nevis
So, If I want to release a game I created with this, do I just change the file name and make a custom smdh file for it?
 

sweis12

Well-Known Member
Member
Joined
Oct 20, 2013
Messages
1,248
Trophies
0
Age
32
XP
1,368
Country
Saint Kitts and Nevis
Hey, I am slightly confused. Anything I try to put into main.lua always spats out an error for me. Even the simplest stuff
Code:
function love.load()

end

function love.draw()
    love.graphics.print("Hello world")
end

That just spats out an error, and freezes the DS. Am I missing something?


Opps, a Lua error has occured
Press Start to quit

game/main.lua: bad argument #2 to 'print'
(number expected, got no value)
 

Shadowtrance

Well-Known Member
Member
Joined
May 9, 2014
Messages
2,493
Trophies
0
Location
Hervey Bay, Queensland
XP
1,807
Country
Hey, I am slightly confused. Anything I try to put into main.lua always spats out an error for me. Even the simplest stuff
Code:
function love.load()

end

function love.draw()
    love.graphics.print("Hello world")
end

That just spats out an error, and freezes the DS. Am I missing something?

Opps, a Lua error has occured
Press Start to quit

game/main.lua: bad argument #2 to 'print'
(number expected, got no value)
It needs something after the string you're printing to say WHERE you're printing it..

for example.
Code:
function love.draw()
    love.graphics.print("Hello World", 20, 20)
end
will print Hello World on the bottom screen 20 pixels in from the side and 20 pixels down from the top.

Not related to your problem...

But @VideahGams i noticed (don't know if it's just me) but when an error gets thrown like that and it says press start to quit, start doesn't quit...so it won't exit and you have to power off.
 
Last edited by Shadowtrance,

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
    LeoTCK @ LeoTCK: yes for nearly a month i was officially a wanted fugitive, until yesterday when it ended