Author Topic: [Lua] Unnamed danmaku  (Read 9941 times)

0 Members and 1 Guest are viewing this topic.

Offline Chockosta

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 447
  • Rating: +169/-6
    • View Profile
[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 :
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

Offline ElementCoder

  • LV7 Elite (Next: 700)
  • *******
  • Posts: 611
  • Rating: +42/-2
    • View Profile
Re: [Lua] Unnamed danmaku
« Reply #1 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.
« Last Edit: December 19, 2012, 04:14:00 pm by ElementCoder »

Some people need a high five in the face... with a chair.
~EC

Offline Jim Bauwens

  • Lua! Nspire! Linux!
  • Editor
  • LV10 31337 u53r (Next: 2000)
  • **********
  • Posts: 1881
  • Rating: +206/-7
  • Linux!
    • View Profile
    • nothing...
Re: [Lua] Unnamed danmaku
« Reply #2 on: December 19, 2012, 03:57:14 pm »
Looks fun :)
Tried it in PCspire and it seems to work :D

Offline Sorunome

  • Fox Fox Fox Fox Fox Fox Fox!
  • Support Staff
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 7920
  • Rating: +374/-13
  • Derpy Hooves
    • View Profile
    • My website! (You might lose the game)
Re: [Lua] Unnamed danmaku
« Reply #3 on: December 19, 2012, 08:53:50 pm »
Looks cool!
I maybe should get a nspire cx some time...

THE GAME
Also, check out my website
If OmnomIRC is screwed up, blame me!
Click here to give me an internet!

Offline blue_bear_94

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 801
  • Rating: +25/-35
  • Touhou Enthusiast / Former Troll / 68k Programmer
    • View Profile
Re: [Lua] Unnamed danmaku
« Reply #4 on: December 19, 2012, 08:56:36 pm »
Or a Casio Prizm, if something similar comes to that platform.
Due to dissatisfaction, I will be inactive on Omnimaga until further notice. (?? THP hasn't been much success and there's also the CE. I might possibly be here for a while.)
If you want to implore me to come back, or otherwise contact me, I can be found on GitHub (bluebear94), Twitter (@melranosF_), Reddit (/u/Fluffy8x), or e-mail (if you know my address). As a last resort, send me a PM on Cemetech (bluebear94) or join Touhou Prono (don't be fooled by the name). I've also enabled notifications for PMs on Omnimaga, but I don't advise using that since I might be banned.
Elvyna (Sunrise) 4 5%
TI-84+SE User (2.30 2.55 MP 2.43)
TI-89 Titanium User (3.10)
Casio Prizm User? (1.02)
Bag  東方ぷろの

Offline Yeong

  • Not a bridge
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 3739
  • Rating: +278/-12
  • Survivor of Apocalypse
    • View Profile
Re: [Lua] Unnamed danmaku
« Reply #5 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
Sig wipe!

Offline Chockosta

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 447
  • Rating: +169/-6
    • View Profile
Re: [Lua] Unnamed danmaku
« Reply #6 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.

Offline DJ Omnimaga

  • Clacualters are teh gr33t
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55942
  • Rating: +3154/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • Dream of Omnimaga Music
Re: [Lua] Unnamed danmaku
« Reply #7 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
Now active at https://discord.gg/cuZcfcF (CodeWalrus server)

Offline Chockosta

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 447
  • Rating: +169/-6
    • View Profile
Re: [Lua] Unnamed danmaku
« Reply #8 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...

Offline Nick

  • LV9 Veteran (Next: 1337)
  • *********
  • Posts: 1166
  • Rating: +161/-3
  • You just got omnom'd
    • View Profile
    • Nick Steen
Re: [Lua] Unnamed danmaku
« Reply #9 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?

Offline Chockosta

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 447
  • Rating: +169/-6
    • View Profile
Re: [Lua] Unnamed danmaku
« Reply #10 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.

Offline DJ Omnimaga

  • Clacualters are teh gr33t
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55942
  • Rating: +3154/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • Dream of Omnimaga Music
Re: Re: [Lua] Unnamed danmaku
« Reply #11 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
Now active at https://discord.gg/cuZcfcF (CodeWalrus server)

Offline Nick

  • LV9 Veteran (Next: 1337)
  • *********
  • Posts: 1166
  • Rating: +161/-3
  • You just got omnom'd
    • View Profile
    • Nick Steen
Re: [Lua] Unnamed danmaku
« Reply #12 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?

Offline DJ Omnimaga

  • Clacualters are teh gr33t
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55942
  • Rating: +3154/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • Dream of Omnimaga Music
Re: Re: [Lua] Unnamed danmaku
« Reply #13 on: December 28, 2012, 12:00:20 pm »
Numpad has no key repeat, right? Also would it let you shoot and move simultaneously?
Now active at https://discord.gg/cuZcfcF (CodeWalrus server)

Offline Nick

  • LV9 Veteran (Next: 1337)
  • *********
  • Posts: 1166
  • Rating: +161/-3
  • You just got omnom'd
    • View Profile
    • Nick Steen
Re: [Lua] Unnamed danmaku
« Reply #14 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?