Last active
December 14, 2015 19:59
-
-
Save noway/5140455 to your computer and use it in GitHub Desktop.
Terminal arkanoid on coffeescript+node.js. Execute `coffee arkanoid.coffee` in terminal to run.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
if not process.stdout.isTTY | |
console.log 'To play game run it in terminal' | |
return | |
# terminal props | |
terminalBuffer = [] | |
terminalSize = [0, 0] | |
terminalCenter = [0, 0] | |
# plate props | |
plateX = 0 | |
plateSize = 5 | |
# global game props | |
firstTime = true | |
gameEnd = false | |
isGameOver = false | |
startScreen = true | |
score = 0 | |
level = 1 | |
# ball props | |
ball = [0, 0] | |
ballVel = [-1, -1] # horizontal, vertical | |
ballLaunched = false | |
# blocks props | |
blocks = [] | |
blockLeng = 4 | |
blocksOnLine = 0 | |
setSymbol = (x, y, symb = '_') -> | |
if x > terminalSize[0] or x < 0 or | |
y > terminalSize[1] or y < 0 | |
console.error x, y | |
if not terminalBuffer[y]? or not terminalBuffer[y][x]? | |
console.error x, y | |
terminalBuffer[y][x] = symb | |
resetBuffer = -> | |
terminalBuffer = [] | |
for i in [0...terminalSize[1]] | |
terminalBuffer[i] = [] | |
for j in [0...terminalSize[0]] | |
terminalBuffer[i][j] = ' ' | |
return | |
resetScreen = -> | |
if firstTime | |
process.stdout.write "\x1b[?25l" # hide cursor | |
firstTime = false | |
return | |
for i in [0...terminalSize[1]] | |
if i is terminalSize[1] - 1 | |
process.stdout.write "\x1b[2K\r" | |
break | |
process.stdout.write "\x1b[A" | |
return | |
render = -> | |
resetScreen() | |
for line, i in terminalBuffer | |
newLine = '\n' | |
if i is terminalBuffer.length - 1 | |
newLine = '' | |
process.stdout.write line.join('') + newLine | |
return | |
drawRect = (x, y, width, height) -> | |
for i in [y...y + height] | |
for j in [x...x + width] | |
symb = null | |
if i is y or i is y + height - 1 | |
if j isnt x and j isnt x + width - 1 | |
symb = '\u2550' | |
else | |
if j is x or j is x + width - 1 | |
symb = '\u2551' | |
if i is y and j is x | |
symb = '\u2554' | |
else if i is y and j is x + width - 1 | |
symb = '\u2557' | |
else if i is y + height - 1 and j is x | |
symb = '\u255A' | |
else if i is y + height - 1 and j is x + width - 1 | |
symb = '\u255D' | |
setSymbol j, i, symb if symb isnt null | |
return | |
drawPlate = -> | |
for i in [0...plateSize] | |
setSymbol plateX + i, terminalSize[1] - 3 , '\u2594' | |
return | |
drawText = (x, y, text, align = 0) -> | |
if align is 1 | |
x -= Math.round text.length / 2 | |
else if align is 2 | |
x -= text.length | |
for i in [0...text.length] | |
setSymbol x + i, y, (text.substr i, 1) | |
return | |
renderScene = -> | |
resetBuffer() | |
drawRect 1, 1, terminalSize[0] - 2, terminalSize[1] - 2 | |
if startScreen | |
drawText terminalCenter[0], terminalCenter[1] - 3, | |
"Controls:", 1 | |
drawText terminalCenter[0], terminalCenter[1] - 2, | |
"A for left, D for right", 1 | |
drawText terminalCenter[0], terminalCenter[1] - 1, | |
"Space for launch ball", 1 | |
drawText terminalCenter[0], terminalCenter[1] + 1, | |
"Press anykey to start", 1 | |
drawText terminalCenter[0], terminalCenter[1] + 3, | |
"Author: noway", 1 | |
render() | |
return | |
drawPlate() | |
for i in [0...blocks.length] | |
for j in [0...blocks[i].length] | |
if blocks[i][j] is true | |
for k in [0...blockLeng] | |
datSymb = '\u2586' | |
if k is 0 | |
datSymb = '[' | |
if k is blockLeng - 1 | |
datSymb = ']' | |
setSymbol (j * blockLeng) + k + 2, i + 2, datSymb | |
if not ballLaunched | |
setSymbol ball[0], terminalSize[1] - 4, 'O' | |
else | |
setSymbol ball[0], ball[1], 'O' | |
drawText terminalSize[0] - 1, 0, "Score: " + score, 2 | |
drawText 1, 0, "Level: " + level, 0 | |
if gameEnd | |
endText = if isGameOver then "GAME OVER" else "NEXT LEVEL" | |
drawText terminalCenter[0], terminalCenter[1], endText, 1 | |
render() | |
resetGame = -> | |
score = 0 | |
halfPlate = plateSize / 2 | |
plateX = Math.round terminalCenter[0] - halfPlate | |
ball = [Math.round(terminalCenter[0]), terminalSize[1] - 4] | |
ballVel = [-1, -1] | |
ballLaunched = false | |
blocksOnLine = Math.floor (terminalSize[0] - 4) / blockLeng | |
for i in [0...4] | |
blocks[i] = [] | |
for j in [0...blocksOnLine] | |
blocks[i][j] = true | |
return | |
endGame = (gameOver = false) -> | |
gameEnd = true | |
isGameOver = gameOver | |
renderScene() | |
setTimeout -> | |
if not isGameOver | |
level++ | |
else level = 0 | |
gameEnd = false | |
resetGame() | |
renderScene() | |
, 500 | |
onResize = -> | |
terminalSize = [process.stdout.columns, process.stdout.rows] | |
terminalCenter = [ | |
Math.round((terminalSize[0] - 4) / 2 + 2), | |
Math.round((terminalSize[1] - 4) / 2 + 2), | |
] | |
renderScene() | |
onKeyPress = (key) -> | |
if gameEnd | |
return | |
if key.toLowerCase() is 'a' | |
plateX-- | |
ball[0]-- if not ballLaunched | |
else if key.toLowerCase() is 'd' | |
plateX++ | |
ball[0]++ if not ballLaunched | |
else if key is ' ' | |
ball[1] = terminalSize[1] - 4 | |
ballLaunched = true | |
if plateX > terminalSize[0] - 3 - plateSize + 1 | |
plateX-- | |
ball[0]-- if not ballLaunched | |
else if plateX < 2 | |
plateX++ | |
ball[0]++ if not ballLaunched | |
renderScene() | |
ballPhisics = -> | |
for i of ball | |
ball[i] += ballVel[i] | |
if ball[0] >= terminalSize[0] - 3 then ballVel[0] = -1 | |
if ball[0] <= 2 then ballVel[0] = 1 | |
if ball[1] >= terminalSize[1] - 4 and ballVel[1] is 1 | |
if ball[1] >= terminalSize[1] - 3 | |
endGame(true) | |
else | |
if ball[0] == plateX - 1 and ballVel[0] is 1 | |
ballVel[0] = -1 | |
ballVel[1] = -1 | |
else if ball[0] == plateX + plateSize and ballVel[0] is -1 | |
ballVel[0] = 1 | |
ballVel[1] = -1 | |
else if ball[0] >= plateX and ball[0] < plateX + plateSize | |
ballVel[1] = -1 | |
if ball[1] <= 2 then ballVel[1] = 1 | |
currLine = ball[1] - 2 | |
if currLine <= blocks.length and currLine > 0 | |
currIndex = Math.floor ball[0] / blockLeng | |
if blocks[currLine - 1][currIndex] | |
blocks[currLine - 1][currIndex] = false | |
blocksDestroyed = true | |
for i in blocks | |
for j in i | |
if j | |
blocksDestroyed = false | |
break | |
if not blocksDestroyed | |
break | |
score++ | |
ballVel[1] *= -1 | |
process.stdout.write "\x07" # bell | |
if blocksDestroyed then endGame() | |
process.stdin.setRawMode true | |
process.stdin.resume() | |
process.stdin.setEncoding 'utf8' | |
process.stdin.on 'data', (key) -> | |
if startScreen | |
startScreen = false | |
resetGame() | |
renderScene() | |
if key is 'a' or key is 'd' or key is ' ' | |
onKeyPress key | |
else if key is '\u0003' | |
process.stdout.write "\x1b[?25h\n" # show cursor and make new line | |
process.exit() | |
process.stdout.on 'resize', onResize | |
setInterval -> | |
return if startScreen | |
return if gameEnd | |
return if not ballLaunched | |
ballPhisics() | |
renderScene() | |
, 100 | |
onResize() | |
renderScene() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment