1
TI-Nspire / [Lua] Unnamed danmaku
« on: December 19, 2012, 02:48:52 pm »
Hello guys !
Lately, I've been quite addicted into Touhou (even if my gameplay is terrible )
So I tried to make a danmaku game for the TI-Nspire. (danmaku are also known as bullet hells)
For now, my engine works nicely with ennemies and bosses. It still lacks lasers, but it is almost complete.
There is one demo level if you want to try it.
It's very short and simple, but it shows the possibilities of this game.
(The sprites are from Touhou Danmakufu)
BTW, please don't play it with the TI Nspire computer software, it reacts weirdly.
Here is the source code, if you want to have a look :
Lately, I've been quite addicted into Touhou (even if my gameplay is terrible )
So I tried to make a danmaku game for the TI-Nspire. (danmaku are also known as bullet hells)
For now, my engine works nicely with ennemies and bosses. It still lacks lasers, but it is almost complete.
There is one demo level if you want to try it.
It's very short and simple, but it shows the possibilities of this game.
(The sprites are from Touhou Danmakufu)
BTW, please don't play it with the TI Nspire computer software, it reacts weirdly.
Here is the source code, if you want to have a look :
Code: [Select]
enemySprite={}
enemySprite[1]=image.new("\016\000\000\000\018\000\000\000\000\000\000\000 \000\000\000\016\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000d\136\198\144c\132\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000c\140\198\148\132\140c\136\231\148J\210\139\218j\218\232\144!\132c\136\165\144\165\144c\140\000\000!\000J\165\016\186\239\181\173\165L\202\219\255\255\255\151\255j\210J\157\172\1691\190\017\190K\165!\004!\000\140\169\247\210Z\227\024\211\229\242\238\242\138\226\013\243\228\246\178\206\024\219Z\227\214\210\173\173!\004\000\000J\161\214\210\156\235\156\235\005\255n\218\243\238/\214\229\2421\239{\235Z\227s\194)\161\000\000\000\000\165\144R\186Z\223\189\247,\251\241\234w\255\244\234)\239\185\251[\227\214\206\140\165\132\140\000\000\000\000\165\1442\1869\215\189\243\220\251\246\169\244\234R\165\189\219\255\255|\223\247\210J\161!\132\000\000\000\000\165\1441\186Z\223\028\207=\223\188\182\216\1659\174\159\223\219\206\183\177\023\215k\165c\136\000\000\000\000\132\136\140\165\213\202\213\144\249\177\252\202\252\202^\211~\227W\165\212\140\248\182\207\161&\165\163\144!\132g\173S\170=\171\025\166}\227\159\235\191\231\191\231\158\231\029\199\217\157\219\170\247\186i\218\229\156\230\148\167\226v\219\127\191\026\162\253\194\158\223\190\231\190\223\220\190\151\161:\1626\207P\235\148\186\198\144\198\144\242\226\020\199\188\174\026\158[\170\220\190\029\195\188\170\221\162\249\157\213\194p\2356\211\150\182\198\144\198\144Z\227\158\207\249\182\221\170\221\166\254\170\030\171\030\171>\171\210\202/\2278\203~\211\182\194\131\136!\000\181\206}\211\021\203>\183\029\171\248\1902\227\210\202\244\1942\215\023\195\159\199}\223\016\182\000\128\000\000\231\148\253\1708\195\019\211\022\1994\2159\1957\199\218\182}\195\159\199:\211k\157B\132\000\000\000\000c\136\140\157;\191\187\170\154\174\029\187\159\211\158\2159\174}\215Z\219s\194\198\144\000\000\000\000\000\000\000\000c\136(\153\021\1585\166u\182\214\210\182\194U\162\016\182(\153\132\140\000\000\000\000\000\000\000\000\000\000\000\000\000\000B\004\165\144\132\140c\136c\136!\132\000\000\000\000\000\000\000\000\000\000\000\000")
enemySprite[2]=image.new("\016\000\000\000\018\000\000\000\000\000\000\000 \000\000\000\016\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000D\140\134\148#\136\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000c\140\166\148d\144C\140\167\152J\210\139\218j\218\136\156!\132C\136\133\144\133\148c\140\000\000!\000*\165\208\189\175\185-\173L\202\219\255\255\255\151\255j\210\234\164M\173\241\193\241\193+\169!\004!\000L\173\151\218\026\231\152\218\229\242\238\242\138\226\013\243\228\246\178\206\216\222\026\231\150\214m\177!\004\000\000\010\165\150\214\092\239\092\243\005\255n\218\243\238/\214\229\2421\239[\239\026\231\019\202\009\161\000\000\000\000\133\148\210\193\250\230\189\247,\251\241\234w\255\244\234)\239\185\251\027\231v\210,\169d\140\000\000\000\000\133\148\210\193\185\222\157\247\220\251V\209\244\2342\201\221\230\255\255\252\234\151\214\010\165!\132\000\000\000\000\133\144\209\189\250\226|\230\253\242\188\2258\217y\217\255\246{\234\151\221\184\218+\169C\140\000\000\000\000D\140,\173V\206\149\208\153\225\092\234\092\234\158\238\030\2437\217t\208\184\205\015\177&\165\163\144!\132g\173S\189]\2179\217\029\239_\247?\247?\247>\243=\234\249\216[\217\215\201i\218\229\156\230\148\167\226v\219\255\233\026\217\029\234\254\242>\247\254\242\252\229\023\217\026\2176\207P\235\212\197\134\148\134\148\242\226\020\199|\225\250\216[\221\252\229\029\230\092\221\029\221\249\216\022\202p\2356\211\182\205\134\148\134\148\026\231~\234\185\213]\221=\221^\225^\225^\217^\217\210\202/\227Y\214\158\234\022\206D\140!\000u\210\157\234\021\203\190\225]\221\248\2052\227\210\202\244\1942\215\024\206?\234\253\234\176\185\000\128\000\000\167\152]\217\025\210\019\2118\2064\215\025\2149\210\186\217\029\226?\234\154\226\235\164\034\136\000\000\000\000C\140\236\168\251\221[\217z\213\221\225\159\238\190\238y\221\189\234\218\230\019\198\134\148\000\000\000\000\000\000\000\000C\140\201\156\245\1965\201\181\201\150\214\022\206\021\197\176\185\201\156d\140\000\000\000\000\000\000\000\000\000\000\000\000\000\000B\004\133\144d\144C\136C\136!\132\000\000\000\000\000\000\000\000\000\000\000\000")
bossSprite={}
bossSprite[1]=image.new("\028\000\000\000 \000\000\000\000\000\000\0008\000\000\000\016\000\001\000!\004!\004B\008B\008!\004B\008B\008B\008c\008c\008c\008c\008c\008\132\012\133\140\173\136\199\144\198\144\132\140c\008C\008B\008B\008B\008!\004!\004!\004!\004!\004!\004!\004B\008!\004!\004!\004!\004!\004!\004!\004!\004B\008c\012\199\144\188\128-\149\212\132\172\136\132\140B\008!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004B\008!\004!\004!\004!\004!\004!\004B\008B\008c\136\165\144\012\149\190\128W\145\223\128\186\128\165\144B\008!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004B\008B\008!\004!\004!\004!\004B\008c\136\132\140\199\148J\157T\149\223\132\223\128\223\128\014\149\165\140B\008!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004B\008c\140\198\144k\161R\190\214\202\029\170\031\133\255\128\028\137)\153\132\140B\008!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004B\008B\008c\136\198\144\016\182{\2319\223\255\255\223\247\255\210\255\206s\190)\153\132\140B\004!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004B\008B\136C\136\165\144\173\169{\235{\231\127\231_\182\127\145\158\202\191\243\156\235\173\165\198\148c\136B\136B\004!\004!\004!\004!\004!\004!\004!\004!\004!\004B\008B\008C\136\165\144)\157s\194\156\235\223\169u\128\184\128\186\128\149\128\127\141\127\1331\178)\153\198\144\132\140C\136B\008!\004!\004!\004!\004!\004B\008B\004B\004B\004B\008c\140\231\148\173\169\025\219\249\144\191\128\158\128\186\128\253\128Z\129t\128_\129Z\223{\235s\198J\161c\140B\008B\008B\008B\008B\008B\008B\008B\136c\140c\140\132\140\133\140\206\181\214\214t\194\028\137\191\132\027\129\156\129\127\1865\1299\129\029\129\025\219\189\243{\235\016\186\165\144\132\140\132\140\132\140\132\140B\008B\008\132\144\198\148\165\144\133\140\165\144\165\144\008\153\140\169\173\161\223\128\191\128\222\129\127\154\222\190Y\170\127\133\253\128s\186\181\202\016\182\140\161\008\149\008\149J\161k\169\198\148C\136B\008c\136\165\144)\157J\161\173\173J\161\008\149\008\149k\157\182\157\155\128\249\128\222\182\221\186\028\134\254\129\152\182\016\174\140\161k\157\206\173s\1989\227\024\223s\202\231\152B\136C\136\165\148)\161\206\181s\198\181\206\214\210\148\202\239\177\206\165\154\174\031\195\031\130\158\146\191\146_\130\159\154[\215R\186\148\194\024\2199\2279\227\148\202\206\173)\161\164\140B\136c\140\165\144\198\148*\161\239\177\247\214\247\2149\2239\219\024\211|\219\191\235\031\139\255\150\222\130\255\130~\203\158\235\214\2069\219\023\211R\190\239\173J\157\231\148\165\140c\136B\008B\008B\136c\136\132\140\231\148\173\173\017\182\214\206Z\2239\223\156\235\223\247_\187\255\129\255\129\031\151\190\239\223\239\247\218{\2319\219\181\2021\182\140\169)\157\230\148\132\140B\008B\008B\004B\008c\136\132\140\230\144k\161\148\194Z\223\024\223[\231\255\251\223\235\255\190\254\194\127\203\222\247|\227\023\211\023\215\247\214\248\218\024\219t\202\173\177k\169\165\144B\008!\004!\004B\008c\140\230\152\008\157\173\1699\223\156\239{\235Y\223\189\243\223\231\191\219\159\227\159\231|\231\181\198\017\170\173\165\173\169\173\173\239\181\206\181)\161\199\152\132\140B\008!\004!\004B\008c\140\231\152)\161\140\169s\202\148\198\181\198\150\182\250\178\127\219_\215\127\227\127\219\218\190\248\2023\166\240\169)\153\231\148\165\144\165\144\132\140c\136B\008B\004!\004!\004B\004B\136\132\144\198\148\166\144\231\148J\153\239\165\029\175>\175\159\166_\219?\207\191\174\253\198\159\223_\187^\199\150\182\008\149\132\140B\136B\008B\008B\008!\004!\004!\004B\008B\008B\136c\140c\136\165\144J\153\029\179\191\227\255\247\157\178\255\186\092\162\253\198\223\247\191\231?\179\191\227\158\227\140\165\165\140B\008!\004!\004!\004!\004!\004!\004!\004!\004B\004B\008\132\140\231\148\017\166_\187_\187\159\207?\187\029\207\220\198\255\247\223\235_\187\031\159\191\227\127\195T\170\231\144C\136!\004!\004!\004!\004!\004!\004!\004!\004B\008B\008\199\148\140\161[\207_\183?\179\127\191_\183\127\203\159\215\159\215_\187_\191\159\223?\203\191\150\187\138\009\145c\136!\004!\004!\004!\004!\004!\004!\004!\004B\008B\136\231\148\241\161_\195\127\219_\215_\207\191\231?\175_\187\127\203_\183\159\231\189\186=\154\159\130\222\134)\149c\140!\004!\004!\004!\004!\004!\004!\004!\004!\004c\136\008\149\154\138\026\130\253\137\188\129\187\129>\146\031\199\031\203\127\223>\207\029\150U\129\029\130\255\138\255\138)\153\132\140!\004!\004!\004!\004!\004!\004!\004!\004!\004\132\140K\153v\129\185\129\153\129\153\129\153\129\153\129\153\129w\129\253\133v\129\183\129\092\130[\130\191\130\255\134)\153\132\140!\004!\004!\004!\004!\004!\004!\004!\004!\004\132\140l\1533\129=\130\223\146]\130^\130^\130\026\130\150\129\026\130\092\130\158\130\223\1344\129\223\138\223\130\009\153c\140!\004!\004!\004!\004!\004!\004!\004!\004!\004\132\140)\153\216\129}\130\031\155\255\134\223\130\223\130\223\134}\130\223\130\255\134\255\134\223\138\220\129\031\167\188\142\231\148c\136!\004!\004!\004!\004!\004!\004!\004!\004!\004c\136\231\1448\134\223\130\223\130\223\130\223\130\223\130~\130\027\130\255\134\255\134\255\134\031\159?\155?\167\021\146\165\144C\136!\004!\004!\004!\004!\004!\004!\004!\004!\004B\008\132\140)\153\154\138\223\130\223\130\223\130\223\130\027\130\185\129\223\130\223\130\255\134\030\167\017\170\142\149\231\144c\140B\008!\004!\004!\004!\004!\004!\004!\004!\004!\004B\008c\136\166\144\242\141\255\130\255\138\255\146\223\138]\130\027\130\223\134\255\134\253\170\215\206k\161\166\144c\136B\008B\008!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004B\008c\136+\137\209\145\155\142\253\166>\183\255\166\127\130\218\166\150\1781\178\207\177\165\144c\136B\004!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004!\004B\008B\136c\140\165\144L\145J\153\140\153\241\157\173\161k\161)\153\231\144\165\144c\136B\008!\004!\004!\004!\004!\004!\004!\004")
playerSprite=image.new("\020\000\000\000\030\000\000\000\000\000\000\000(\000\000\000\016\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000J\241\140\241\240\245k\241\008\229\240\245\140\241J\241\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\008E\000\000\174\2451\250k\245)\2331\250\206\245\000\000\008E\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\166\160k\241)\237\198\172k\245k\241\198\220\199\164\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\173\205k\241\232\192\240\205J\221J\237\232\192\232\168\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000R\250\206\245\231\228l\189\016\210\009\181)\2171\250)\229\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\206\245\206\249\199\164\140\197*\185*\185)\177*\2292\250\206\245\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\239\245\215\254\198\168K\189\199\168)\181\198\164\008\177J\249K\237k\241k\241kq\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\250k\253\198\168\207\197*\181\141\193\207\233*\185\198\168\000\000\198\220\198\220\198\092\000\000\000\000\000\000\000\000\000\000\000\000\000\000\231\228\173\229Z\255\140\245k\245\231\228\165\220Z\255\255\255\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\241\217\238\241\140\241R\250\140\241k\241\231\228\008\225\248\250;\239\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000<\235\026\243\255\255\198\220\000\128\000\128\000\128\000\128\000\128\191\247\025\243]\235\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\190\251\024\251\247\246\000\128\255\255\255\255\255\255\255\255\255\255\000\128\247\250\190\251\000\000\000\000\000\000\000\000\000\000\000\000;o\027\235\223\255\223\255\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\255\255\027\235\000\000\000\000\000\000;o\000\000\027\235\190\251\255\255\250\234\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\222\251\190\251\027\235\000\000;o\000\000\027\235\223\255\255\255}\247U\222\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128]\239\222\251\223\255\027\235\000\000\216\238\181\250\255\255\158\247;\2393\218\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128\008\225<\235\255\255\181\250\216\238\217\226\024\247\255\255\141\233\150\226U\218\000\128\255\255\255\255\255\255\255\255\255\255\255\255\255\255\000\128k\241\140\225}\247\024\247\217\226\000\000v\218;\239;\239\184\222)\237\173\237\000\128\255\255\255\255\255\255\255\255\255\255\000\128\140\241\165\220S\234;\239;\239\000\000vZ\000\000;\239w\214\008\225\207\245\173\245\239\245\000\128\000\128\000\128\000\128\000\128l\237\198\220\198\220\164\220\151\218\000\000;o\000\000;o\000\000\000\000J\237R\250\173\241J\237J\237)\237J\237J\237J\237J\237J\237\198\220\198\220\198\220\000\000\000\000\000\000\000\000\000\000\000\1402\2501\2502\2501\250\173\241R\250k\241k\241J\237k\241k\241\198\224\198\220\198\220\198\220\000\000\000\000\000\000\000\000\132\216\239\2452\250R\250J\241\173\2452\250\017\250J\241\198\220k\241k\241J\237\198\220\198\220\198\220\000\000\000\000\000\000\000\000J\237\016\2501\250R\250k\241J\2332\2502\250\174\245\198\220k\241k\241k\241\008\229\198\220\198\220\000\000\000\000\000\000\000\000*\233\016\2502\250\173\241k\241J\2332\2502\250\173\241k\241\198\224J\241J\241\174\233\141\221\165\220\000\000\000\000\000\000\000\000\206\233\255\255\017\250\140\245k\241\231\228\240\2492\250\017\250J\241\165\2203\222\216\242)\229\009\221\198\220\000\000\000\000\000\000\000\000\140\241\239\249s\250\157\247k\241\141\225\223\255\017\250Z\255;\243\008\237\165\220\165\220\198\220\000\000\000\000\198\092\000\000\000\000\000\000\165\216)\237\008\229\008\229\008\233\165\224)\233k\237\173\249J\237\008\233\198\220\198\220\198\220\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\198`\000\000\198\168*\185*\185)\181\198\168\198\168\198\168\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\198\168\009\181*\185)\181\198\168\199\168\000\000\199(\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\198(\000\000\199\168\199\172\199\172C\152\000\000\198(\000\000\000\000\000\000\000\000\000\000\000\000")
function copyTable(t)
local t2={}
for i,e in pairs(t) do
t2[i]=e
end
return t2
end
function init()
menu=true
menuOptions={"Back to game",true,"Level 1",true,"Level 2",false,"Level 3",false,"Level 4",false,"Level 5",false,"Level 6",false,"Help",true}
cursor=1
level=1
initLevels()
end
function initLevelVars()
lives,bombs,dead,invincible=3,3,false,0
count,bombTime,transitionTime=0,0,0
xPlayer,yPlayer=160,183
wave=1
bossPhase=0
enemies=copyTable(levelEnemies[level][1])
explosion=false
explosionRay,explosionMaxRay=0,0
explosionX,explosionY=0,0
xBoss,yBoss=levelBoss[level][3],levelBoss[level][4]
bossHP=levelBoss[level][1]
maxBullets=copyTable(levelEnemiesMaxBullets[level])
bossFireRate=copyTable(levelBossFireRate[level][1])
initBullets()
end
function initLevels()
levelBoss,levelBossMaxBullets,levelEnemiesMaxBullets,levelBackground,levelBossFireRate,levelEnemies={},{},{},{},{},{}
levelEnemyFireRate={5}
levelEnemiesMaxBullets={{50,50,0,0,0}}
levelEnemies[1]={{1,15,-10,1,60,-10,1,120,-10},{1,295,-10,1,250,-10,1,200,-10},{2,160,-30,4,80,-30,4,240,-30},{1,30,-10,1,30,-40,1,30,-70,1,30,-100,1,30,-130},{1,290,-10,1,290,-40,1,290,-70,1,290,-100,1,290,-130},{4,160,-10,4,80,-10,4,240,-10,1,120,-10,1,120,-40,1,120,-70,1,200,-10,1,200,-40,1,200,-70}}
levelBackground[1]={0,0,0}
levelBoss[1]={100,2,160,90,{100,60,30}}
levelBossMaxBullets[1]={{25,25,25,25,0},{0,0,0,0,20},{0,0,10,50,0}}
levelBossFireRate[1]={{1,1,1,1,1},{20,10,10,10,1},{0,0,1,1,0}}
end
function initBullets()
x,y,cx,cy,px,py={},{},{},{},{},{}
for i=1,10 do px[i],py[i]=0,-10 end
for j=1,5 do
x[j],y[j]={},{}
cx[j],cy[j]={},{}
for i=1,50 do
x[j][i],y[j][i]=-10,-10
cx[j][i],cy[j][i]=0,0
end
end
bulletsSize={2,3,5,7,10}
bulletsSpeed={5,3,3,2,1}
bulletsColor={{255,255,0},{255,0,0},{0,255,0},{150,150,255},{255,255,255}}
end
--Bosses and enemies fires
bossFire,enemyFire={},{}
bossFire[1]={}
bossFire[1][1]=function(type,index)
local angle=math.random(0,628)/100
x[type][index],y[type][index]=xBoss,yBoss
cx[type][index],cy[type][index]=math.cos(angle)*5,math.sin(angle)*5
end
bossFire[1][2]=function(type,index)
x[type][index],y[type][index]=xBoss,yBoss
local dist=math.sqrt((xPlayer-xBoss)*(xPlayer-xBoss)+(yPlayer-yBoss)*(yPlayer-yBoss))
cx[type][index],cy[type][index]=(xBoss-xPlayer)/dist*math.random(-5,-2)+math.random(-10,10)/7,(yBoss-yPlayer)/dist*math.random(-5,-2)+math.random(-10,10)/7
end
bossFire[1][3]=function(type,index)
if type==4 then
local r=math.random(0,200)/100
if count%40==0 or count%40==20 then
local k=count%40+5
for i=1+k,25+k do
x[4][i],y[4][i],cx[4][i],cy[4][i]=xBoss,yBoss,math.cos(i*6.28/25+r)*8,math.sin(i*6.28/25+r)*8
end
if index>=1+k and index<=25+k then x[4][index],y[4][index]=x[4][index]+cx[4][index],y[4][index]+cy[4][index] end
end
elseif type==3 and count%6==0 then
x[type][index],y[type][index]=xBoss,yBoss
local dist=math.sqrt((xPlayer-xBoss)*(xPlayer-xBoss)+(yPlayer-yBoss)*(yPlayer-yBoss))
cx[3][index],cy[3][index]=(xBoss-xPlayer)/dist*-5,(yBoss-yPlayer)/dist*-5
end
end
enemyFire[1]=function(enemy,type,index)
if type==1 and (count+enemy)%levelEnemyFireRate[level]==0 and enemies[enemy*3]>5 and enemies[enemy*3]<200 then
local xe,ye=enemies[enemy*3-1],enemies[enemy*3]
x[type][index],y[type][index]=xe,ye
local dist=math.sqrt((xPlayer-xe)*(xPlayer-xe)+(yPlayer-ye)*(yPlayer-ye))
cx[type][index],cy[type][index]=(xPlayer-xe)/dist*5,(yPlayer-ye)/dist*5
end
end
enemyFire[2]=enemyFire[1]
enemyFire[4]=function(enemy,type,index)
if type==2 and count%50<30 and enemies[enemy*3]>29 and enemies[enemy*3]<200 then
x[type][index],y[type][index]=enemies[enemy*3-1],enemies[enemy*3]
local angle=4.71+(count%3-1)*0.8
cx[type][index],cy[type][index]=math.cos(angle)*-6,math.sin(angle)*-6
end
end
function updateBullets()
for j=1,5 do
local checkedEnemies=0
local size=bombTime==0 and bulletsSize[j] or bulletsSize[j]+10+bombTime*2.5
local bulletsFired=0
for i=1,maxBullets[j] do
local bx,by=x[j][i],y[j][i]
if bx>-10 and bx<330 and by>-10 and by<220 then
if (xPlayer-bx)*(xPlayer-bx)+(yPlayer-by)*(yPlayer-by)<size*size+25 then
if bombTime==0 then looseLife() end
x[j][i],y[j][i]=-10,-10
else
x[j][i],y[j][i]=bx+cx[j][i],by+cy[j][i]
end
elseif bossPhase==0 then
if checkedEnemies<#enemies/3 then
checkedEnemies=checkedEnemies+1
enemyFire[enemies[checkedEnemies*3-2]](checkedEnemies,j,i)
end
elseif bossPhase>0 and bulletsFired<bossFireRate[j] and bossHP>0 and transitionTime==0 then
bulletsFired=bulletsFired+1
bossFire[level][bossPhase](j,i)
end
end
end
end
function updatePlayerBullets()
local fired=false
for i=1,10 do
if py[i]>-5 then
py[i]=py[i]-8
if bossPhase>0 then
if math.abs(px[i]-xBoss)<10 and math.abs(py[i]-yBoss)<20 and bossHP>0 then
hitBoss()
py[i]=-10
end
elseif bossPhase==0 then
for e=1,#enemies/3 do
if math.abs(px[i]-enemies[e*3-1])<10 and math.abs(py[i]-enemies[e*3])<10 and py[i]>=0 then
enemies[e*3]=300
py[i]=-10
end
end
end
elseif count%3==0 and not fired and not dead and bossHP>0 then
px[i],py[i]=xPlayer,yPlayer-5
fired=true
end
end
end
function drawBullets(gc)
for j=1,5 do
local size=bulletsSize[j]
gc:setColorRGB(unpack(bulletsColor[j]))
for i=1,maxBullets[j] do
local bx,by=x[j][i],y[j][i]
if bx>-10 and bx<330 and by>-10 and by<220 then
gc:fillArc(bx-size,by-size,size*2,size*2,0,360)
end
end
end
end
function drawPlayerBullets(gc)
gc:setColorRGB(200,0,255)
for i=1,10 do
if py[i]>-5 then
gc:fillRect(px[i]-1,py[i]-8,3,10)
gc:fillRect(px[i]-5,py[i]-5,3,10)
gc:fillRect(px[i]+3,py[i]-5,3,10)
end
end
end
function updateBoss()
if bossHP>0 and bossPhase>0 and bossPhase<#levelBoss[level][5] then
if bossHP<=levelBoss[level][5][bossPhase+1] then
bossPhase=bossPhase+1
maxBullets=copyTable(levelBossMaxBullets[level][bossPhase])
bossFireRate=copyTable(levelBossFireRate[level][bossPhase])
transitionTime=15
initBullets()
end
end
end
function hitBoss()
if bossHP>1 and not dead and transitionTime==0 then
bossHP=bossHP-1
elseif bossHP>0 and not dead and transitionTime==0 then
bossHP=0
explosion=true
explosionRay=5
explosionX,explosionY=xBoss,yBoss
explosionMaxRay=200
end
end
function looseLife()
if invincible==0 and bossHP>0 then
explosion,dead=true,true
invincible=30
lives=lives-1
bombs=3
explosionRay=5
explosionX,explosionY=xPlayer,yPlayer
explosionMaxRay=35
end
end
function updateEnemies()
if bossPhase==0 then
local aliveEnemies=false
for i=1,#enemies/3 do
if enemies[i*3]<220 then
aliveEnemies=true
if enemies[i*3-2]%2==1 or enemies[i*3]<30 then enemies[i*3]=enemies[i*3]+2 end
end
end
if not aliveEnemies then
wave=wave+1
if wave>#levelEnemies[level] then
bossPhase=1
maxBullets=copyTable(levelBossMaxBullets[level][1])
bossFireRate=copyTable(levelBossFireRate[level][1])
transitionTime=15
initBullets()
else
enemies=copyTable(levelEnemies[level][wave])
end
end
end
end
function nextLevel()
wave=1
bossPhase=0
enemies=copyTable(levelEnemies[level][1])
maxBullets=copyTable(levelEnemiesMaxBullets[level])
bossFireRate=copyTable(levelBossFireRate[level][1])
initBullets()
end
function drawExplosion(gc)
gc:setColorRGB(255,255,255)
if explosionRay<explosionMaxRay then
explosionRay=explosionRay+4
gc:drawArc(explosionX-explosionRay,explosionY-explosionRay,explosionRay*2,explosionRay*2,0,360)
else
explosion=false
initBullets()
if dead then
dead=false
xPlayer,yPlayer=160,180
end
end
end
function drawPanel(gc)
gc:setColorRGB(200,200,200)
gc:setFont("sansserif","r",10)
local str1,str2="Lives : "..string.rep("o",lives),"Bombs : "..string.rep("o",bombs)
gc:drawString(str1,315-gc:getStringWidth(str1),5,"top")
gc:drawString(str2,315-gc:getStringWidth(str2),20,"top")
if bossPhase>0 then
gc:fillRect(2,2,bossHP*2,3)
for i,e in pairs(levelBoss[level][5]) do
if bossHP>e then gc:fillRect(e*2+2,1,1,5) end
end
end
if bossHP==0 and lives>0 and not explosion then
gc:setColorRGB(255,255,255)
gc:setFont("sansserif","b",12)
gc:drawString("Clear",30,30,"top")
gc:setFont("sansserif","r",12)
gc:drawString("Press enter to go to level "..tostring(level+1),30,60,"top")
end
end
function drawPentacle(gc,x,y,s)
gc:drawArc(x,y,s,s,0,360)
gc:drawArc(x+s/20,y+s/20,s-s/10,s-s/10,0,360)
local tx,ty={2.31*s/4+x,1.19*s/4+x,1.2*s/4+x,2.32*s/4+x,3*s/4+x},{2.95*s/4+y,2.58*s/4+y,1.4*s/4+y,1.05*s/4+y,2.02*s/4+y}
for i=1,5 do
gc:drawArc(tx[i]-s/4,ty[i]-s/4,s/2,s/2,0,360)
end
end
function drawBomb(gc)
if bombTime>0 then
gc:setColorRGB(200,0,255)
local size=20+bombTime*5
drawPentacle(gc,xPlayer-size/2,yPlayer-size/2,size)
end
end
function drawEnemies(gc)
if bossPhase==0 then
gc:setColorRGB(150,150,150)
for i=1,#enemies/3 do
if enemies[i*3]>-5 and enemies[i*3]<220 then
gc:drawImage(enemySprite[enemies[i*3-2]%2+1],enemies[i*3-1]-8,enemies[i*3]-9)
end
end
end
end
function drawTransition(gc)
if transitionTime>0 then
local size=(16-transitionTime)*10+10
gc:setColorRGB(255,255,255)
drawPentacle(gc,xBoss-size/2,yBoss-size/2,size)
end
end
init()
function drawGame(gc)
gc:setColorRGB(unpack(levelBackground[level]))
gc:fillRect(0,0,320,240)
updateBoss()
updateBullets()
updateEnemies()
updatePlayerBullets()
drawPlayerBullets(gc)
drawTransition(gc)
drawBomb(gc)
if explosion then
drawExplosion(gc)
end
if not dead and invincible%2==0 then
gc:drawImage(playerSprite,xPlayer-10,yPlayer-15)
end
drawBullets(gc)
drawEnemies(gc)
if bossHP>0 and bossPhase>0 then gc:drawImage(bossSprite[level],xBoss-14,yBoss-16) end
drawPanel(gc)
timer.start(0.08)
end
function drawMenu(gc)
menuOptions[2]=(lives and lives~=0)
gc:setFont("sansserif","b",12)
gc:setColorRGB(0,0,0)
gc:fillRect(0,0,320,240)
gc:setColorRGB(200,0,255)
drawPentacle(gc,-60,-60,360)
gc:drawLine(35,cursor*20+15,gc:getStringWidth(menuOptions[cursor*2-1])+35,cursor*20+15)
gc:drawLine(35,cursor*20+15+1,gc:getStringWidth(menuOptions[cursor*2-1])+35,cursor*20+15+1)
for i=1,#menuOptions/2 do
if menuOptions[i*2] then
gc:setColorRGB(250,250,250)
else
gc:setColorRGB(100,100,100)
end
gc:drawString(menuOptions[i*2-1],35,i*20+13,"baseline")
end
if cursor==8 then
local help={"You can control the red","character on the bottom","of the screen with the","arrows (or 8,4,2,6)","You start with 3 lives.","When you get hit, you","loose a life, so be careful !","You have 3 bombs per","live. When you press tab,","they make you invincible","for a few seconds. Use","them wisely."}
gc:setFont("sansserif","r",10)
gc:setColorRGB(255,255,255)
for i,e in pairs(help) do
gc:drawString(e,160,17*i-10,"top")
end
end
end
function drawGameOver(gc)
cursor=cursor>2 and 1 or cursor
gc:setColorRGB(0,0,0)
gc:fillRect(0,0,320,240)
gc:setColorRGB(200,0,255)
gc:setFont("sansserif","b",12)
drawPentacle(gc,-60,-60,360)
gc:fillRect(cursor==1 and 30 or gc:getStringWidth("Yes ")+30,152,cursor==1 and gc:getStringWidth("Yes") or gc:getStringWidth("No"),2)
gc:setColorRGB(255,255,255)
gc:drawString("Game over",30,50,"top")
gc:drawString("Try again ?",30,90,"top")
gc:drawString("Yes No",30,150,"baseline")
end
function on.paint(gc)
if menu then
drawMenu(gc)
elseif lives>0 or explosion then
drawGame(gc)
else
drawGameOver(gc)
end
gc:setColorRGB(75,75,75)
gc:setFont("sansserif","r",8)
gc:drawString("Lua Danmaku - By Loic Pujet",10,200,"top")
end
function on.timer()
timer.stop()
if not menu then
count=count+1
if invincible>0 then invincible=invincible-1 end
if bombTime>0 then bombTime=bombTime-1 end
if transitionTime>0 then transitionTime=transitionTime-1 end
platform.window:invalidate()
end
end
function on.arrowKey(a)
if menu then
cursor=a=="up" and cursor-1 or cursor
cursor=a=="down" and cursor+1 or cursor
cursor=(cursor-1)%(#menuOptions/2)+1
platform.window:invalidate()
elseif lives>0 then
xPlayer=(a=="right" and xPlayer<305) and xPlayer+8 or xPlayer
xPlayer=(a=="left" and xPlayer>8) and xPlayer-8 or xPlayer
yPlayer=(a=="down" and yPlayer<200) and yPlayer+8 or yPlayer
yPlayer=(a=="up"and yPlayer>5) and yPlayer-8 or yPlayer
else
cursor=cursor==1 and 2 or 1
platform.window:invalidate()
end
end
function on.tabKey()
if bombTime==0 and bossHP>0 and bombs>0 and not dead and not menu then
bombs=bombs-1
bombTime=20
end
end
function on.enterKey()
if menu and menuOptions[cursor*2] then
if cursor==1 and lives~=0 and lives then
menu=false
platform.window:invalidate()
elseif cursor>=2 and cursor<=7 then
level=cursor-1
menu=false
cursor=1
initLevelVars()
platform.window:invalidate()
end
elseif not menu and lives<=0 and not explosion then
if cursor==1 then initLevelVars() else menu=true end
platform.window:invalidate()
elseif not menu and lives>0 and bossHP==0 then
if level+1<=#levelBackground then
nextLevel()
else
menu=true
end
platform.window:invalidate()
end
end
function on.escapeKey()
if not menu then
menu=true
cursor=1
platform.window:invalidate()
end
end
function on.charIn(c)
if c=="8" then on.arrowKey("up") end
if c=="6" then on.arrowKey("right") end
if c=="4" then on.arrowKey("left") end
if c=="2" then on.arrowKey("down") end
end