Omnimaga

Calculator Community => Other Calc-Related Projects and Ideas => TI-Nspire => Topic started by: Chockosta on December 19, 2012, 02:48:52 pm

Title: [Lua] Unnamed danmaku
Post by: Chockosta 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.

(http://img.removedfromgame.com/imgs/ScreenShot188.png)
(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
Title: Re: [Lua] Unnamed danmaku
Post by: ElementCoder on December 19, 2012, 03:55:50 pm
Clicked download instantaneously when I saw dem pictures O_O This looks extremely awesome. I'm going to test it right now. I'll be back with a review!
[edit]well maybe not a fully fledged review, but just an how awesome post.
Title: Re: [Lua] Unnamed danmaku
Post by: Jim Bauwens on December 19, 2012, 03:57:14 pm
Looks fun :)
Tried it in PCspire and it seems to work :D
Title: Re: [Lua] Unnamed danmaku
Post by: Sorunome on December 19, 2012, 08:53:50 pm
Looks cool!
I maybe should get a nspire cx some time...
Title: Re: [Lua] Unnamed danmaku
Post by: blue_bear_94 on December 19, 2012, 08:56:36 pm
Or a Casio Prizm, if something similar comes to that platform.
Title: Re: [Lua] Unnamed danmaku
Post by: Yeong on December 24, 2012, 10:26:51 pm
Hey. I tried it and its awesome!The aimed shots and stuffs works well! I have few comments to make though.

1)hitbox for Reimu is kinda too big.
2) needs Marisa
3) the boss easily walls you
4) Marisaaaaaa
Title: Re: [Lua] Unnamed danmaku
Post by: Chockosta on December 27, 2012, 02:33:15 pm
Thanks for your feedback !

1) I agree, I will try to reduce that hitbox. But the stupid Nspire arrow detection only allows big steps, so with a smaller hitbox, it will be possible to go through the bullets without taking damage... I have to find a solution to avoid that.
2) Yes indeed, it definitely needs Marisa. I created Reimu first because she is my favorite character :)
3) I guess you think of the second spellcard of the boss. The trick is to go beyond the boss and go around it. But this spellcard is maybe a bit too hard.
4) Don't worry, she will be there in the next version :P

Unfortunately, I'm at my grandparents' for Christmas and I will stay here until january, and I can't program.
Title: Re: [Lua] Unnamed danmaku
Post by: DJ Omnimaga on December 27, 2012, 02:56:26 pm
I didn't have time to try it, but I was wondering how was the speed with 100-200 bullets on screen at once? :P
Title: Re: [Lua] Unnamed danmaku
Post by: Chockosta on December 27, 2012, 03:00:12 pm
It's pretty much good, because the only computations are circles drawings (not sprites), and two additions (X and Y coordinates) every frame.

You can feel some lags when there's more than 250 bullets, which is pretty rare...
Title: Re: [Lua] Unnamed danmaku
Post by: Nick on December 27, 2012, 03:03:02 pm
The stupid Nspire arrow detection only allows big steps, so with a smaller hitbox, it will be possible to go through the bullets without taking damage...

what do you mean by this? you don't use the physics engine, then what makes you say the nspire arrow detection?
Title: Re: [Lua] Unnamed danmaku
Post by: Chockosta on December 27, 2012, 03:09:53 pm
I mean, when you press an arrow key, it doesn't repeat without waiting 1 sec (which is a really bad idea in this game), so you have to press arrow keys repeatedly. To allow fast movement, I had to make the player move 8 pixels per arrow detection.
Title: Re: Re: [Lua] Unnamed danmaku
Post by: DJ Omnimaga on December 27, 2012, 03:11:16 pm
I think he means how like 83p BASIC getkey has no quick key repeat and only registers 10 keypresses per frame, so when you start holding down keys, you move once, then a delay occurs before you start moving continuously. Also the lack of multiple keypress support in Lua.

EDIT: ninja'd
Title: Re: [Lua] Unnamed danmaku
Post by: Nick on December 27, 2012, 04:10:03 pm
I mean, when you press an arrow key, it doesn't repeat without waiting 1 sec (which is a really bad idea in this game), so you have to press arrow keys repeatedly. To allow fast movement, I had to make the player move 8 pixels per arrow detection.
it works with the numpad, wouldn't that be an option?
Title: Re: Re: [Lua] Unnamed danmaku
Post by: DJ Omnimaga on December 28, 2012, 12:00:20 pm
Numpad has no key repeat, right? Also would it let you shoot and move simultaneously?
Title: Re: [Lua] Unnamed danmaku
Post by: Nick on December 28, 2012, 12:03:42 pm
Numpad has no key repeat, right? Also would it let you shoot and move simultaneously?
right, I was wrong.

I guess simultaneously shooting and moving is quite nessecairy, isn't it?