▲ Hans-Christian Vortisch, "GURPS Modern Firepower", Steve Jackson Games, 2002
快速連結:0.5lbs彈幕系統:UI與API
0.5lbs彈幕系統(LUA-based Barrage System, ver.0.5)是一款使用OpenGL/GLUT為UI架構、並以lua內嵌語言為基礎的彈幕腳本描述系統。它允許使用者以物件導向的語言結構簡單地建立出……
事實證明我很不會寫正經八百的推薦/介紹文,而且現在還是禮拜天晚上,時間難得我們就稍微來聊一聊這小玩具的前因後果吧。
當年狂人在Tib的據點第一眼看到東方妖妖夢的演出時,每一個單獨的「彈」的屬性似乎簡單異常,可是利用周期函數配合起來的視覺效果卻是那麼的變幻無窮、風情萬種。從那個時候起,大概就下定了決心,某一天一定要用自己的手重現如此美麗的結構。
後來儘管很快的歸納出所需要的資料結構,但實作時卻在「如何描述動作」上栽了跟頭:當年天真地想要自己開發出一套專用的腳本語言,勉強完成設計,但在自由度與parsing方面的取捨始終不得要領,兩年後修了編譯器設計後更是正式放棄了這個念頭……
直到最近接觸到lua,這整個念頭才在狂人的腦海裡死灰復燃起來。
一開始只是因為這是魔獸世界裡使用者插件(Add-on)中所指定使用的腳本語言,在網路上看了幾篇教學,隨即找到半路前輩的推薦文章(好文推薦!),加上狂人自製3D引擎的計畫也卡在物件資料描述的瓶頸上,乾脆挑了一個主題實際邊看邊學。最後完成的東西便是0.5lbs了。
實際上這裡面的code亂糟糟,UI部分與彈幕驅動部分沒有分離的很乾淨,暫不考慮以引擎的方式釋出。總而言之就先來做點火力展示吧,API以及介面使用說明/程式本體的部分等過幾天有空再補。
媽媽說,火力展示最重要的第一要務,便是把自己火力最強大的東西抬出來。In this case,
Vocal Sign "Chorus Master" / 聲符「コーラスマスター」
(展開/收起原始碼)
-- Function fireSeq(): subroutine for ChorusMaster.actionCheck ----------------
function fireSeq()
for i = 0, 9, 3 do
child1 = {
type = "Direct";
speed = {'p', 15+i, 90};
accel = {'o', 0, 0};
dontCare = 4;
};
child2 = {
speed = {'p', 15+i, 100};
}
LBS_BATCHLAUNCH("ChorusLeft", 1, 36, child1, -36, child2);
child1 = {
type = "Direct";
speed = {'p', 20+i, 105};
accel = {'o', 0, 0};
dontCare = 4;
};
child2 = {
speed = {'p', 20+i, 95};
}
LBS_BATCHLAUNCH("ChorusRight", 1, 36, child1, -36, child2);
end
end
-- Chorus Master --------------------------------------------------------------
ChorusMaster = {
title = "Vocal Sign \"Chorus Master\"";
size = 15;
seg = 16;
color = {0.78, 0.55, 1.0};
actionCheck = function (bullet)
out = {}
if bullet.age == 0 then
out.type = "Direct";
out.speed = {'o', 0, 2};
out.accel = {'o', 0, 0};
out.dontCare = 49;
elseif bullet.age == 50 then
out.type = "Pause";
out.dontCare = 49;
fireSeq();
elseif bullet.age == 100 then
out.type = "Direct";
out.speed = {'o', -2, 0};
out.accel = {'o', 0.01, 0};
out.dontCare = 49;
out.counter = 4;
else
if bullet.counter == 1 then
out.type = "Direct";
out.speed = {'o', 4, 0};
out.accel = {'o', -0.02, 0};
out.dontCare = 50;
out.counter = 2;
fireSeq();
elseif bullet.counter == 2 then
out.type = "Pause";
out.dontCare = 80;
out.counter = 3;
elseif bullet.counter == 3 then
out.type = "Direct";
out.speed = {'o', -4, 0};
out.accel = {'o', 0.02, 0};
out.dontCare = 50;
out.counter = 1;
fireSeq();
out.counter = 4;
else
out.type = "Pause";
out.dontCare = 80;
out.counter = 1;
end
end
return out;
end
};
LBS_REGISTER("ChorusMaster");
-- Function chorus1(): subroutine for setting ChorusLeft & ChorusRight --------
function chorus1(bullet, angle)
out = {};
if bullet.age == 5 then
out.type = "Direct";
out.speed = {'o', bullet.speed[2]*0.01, bullet.speed[3]*0.01};
out.accel = {'o', 0, 0};
out.dontCare = 44;
elseif bullet.age >= 50 then
out.type = "Direct";
out.speed = {'o', bullet.speed[2]*20, bullet.speed[3]*20};
out.accel = {'p', 0.03, angle};
out.dontCare = -1;
end
return out;
end
-- ChorusLeft: Children of ChorusMaster, flying left direction ----------------
ChorusLeft = {
size = 8;
seg = 8;
color = {0, 0, 0.9};
actionCheck = function (bullet)
out = chorus1(bullet, -90);
return out;
end
};
LBS_REGISTER("ChorusLeft");
-- ChorusRight: Children of ChorusMaster, flying right direction --------------
ChorusRight = {
size = 8;
seg = 8;
color = {0.9, 0, 0};
actionCheck = function (bullet)
out = chorus1(bullet, 90);
return out;
end
};
LBS_REGISTER("ChorusRight");
為了達成比較複雜的花樣,code不免變得有點囉囉嗦嗦的,接下來就簡潔性而言,請各位看官觀賞的是這個,
Spell "Fire Ball" / 咒文「火球術」
(展開/收起原始碼)
-- Fireball -------------------------------------------------------------------
Fireball = {
title = "Spell \"Fire Ball\"";
size = 14;
seg = 12;
color = {1.0, 0.0, 0.0};
actionCheck = function (bullet)
out = {}
if bullet.age == 0 then
env = LBS_GETENV();
out.type = "Direct";
out.speed = {'o', (env.selfX - bullet.x)/50, (env.selfY - bullet.y)/50};
out.accel = {'o', 0, 0};
out.dontCare = 50;
end
if bullet.age > 50 then
for i = 1,60 do
bolt = {};
bolt.type = "Direct";
bolt.speed = {'p', math.random()*5.0, math.random()*360-180};
bolt.accel = {'o', 0, 0};
bolt.dontCare = 10+math.random()*20;
LBS_LAUNCH("Bolt", bolt);
end
out.type = "Removed";
end
return out;
end
};
LBS_REGISTER("Fireball");
-- Bolt: Children of fireball -------------------------------------------------
Bolt = {
size = 10;
seg = 8;
color = {1.0, 0.3, 0.0};
}
LBS_REGISTER("Bolt");
內建追尾彈
Technique "Arcade Missle" / テクニーク「アーケード・ミサイル」
(展開/收起原始碼)
-- ArcadeMissle ---------------------------------------------------------------
ArcadeMissle = {
title = "Technique \"Arcade Missle\"";
size = 12;
seg = 12;
color = { 0.78, 0.55, 1.0 };
actionCheck = function (bullet)
out = {};
if bullet.age == 0 then
out.type = "Direct";
out.speed = {'p', 1.2, 90 };
out.accel = {'o', 0, 0 };
out.dontCare = 3;
elseif (bullet.age % 50) == 1 then
missle1 = {
type = "Direct";
speed = {'p', 20.0, -50 };
accel = {'o', 0, 0 };
dontCare = 3;
};
missle2 = {
speed = {'p', 20.0, -55 };
};
LBS_BATCHLAUNCH("Missle1", 1, 18, missle1, 6, missle2);
missle1 = {
type = "Direct";
speed = {'p', 20.0, -130 };
accel = {'o', 0, 0 };
dontCare = 3;
};
missle2 = {
speed = {'p', 20.0, -125 };
};
LBS_BATCHLAUNCH("Missle1", 21, 38, missle1, 6, missle2);
out.dontCare = 100;
elseif bullet.age > 100 then
out.type = "Removed";
end
return out
end
};
LBS_REGISTER("ArcadeMissle");
-- Missle1: Childern of ArcadeMissle ------------------------------------------
Missle1 = {
size = 10;
seg = 8;
color = { 0.78, 0.55, 1.0 };
actionCheck = function (bullet)
out = {}
if bullet.age == 4 then
out.type = "Homing";
out.speed = {'o', bullet.speed[2]*0.05, bullet.speed[3]*0.05};
out.accel = {'o', 0, 0 };
out.target = {'o', 0, 0, 1, 2};
out.maxAngle = 10;
out.dontCare = 40;
elseif bullet.age > 40 then
out.type = "Direct";
out.speed = {'p', bullet.speed[2]*20, bullet.speed[3]};
out.dontCare = -1;
end
return out;
end
};
LBS_REGISTER("Missle1");
永遠的戴寶樂
Skill "Frozen Orb" / スキル「フローズン・オーブ」
(展開/收起原始碼)
-- Frozen Orb -----------------------------------------------------------------
FrozenOrb = {
title = "Skill \"Frozen Orb\"";
size = 14;
seg = 12;
color = { 0.0, 0.5, 1.0 };
actionCheck = function (bullet)
out = {};
if bullet.age == 0 then
out.type = "Direct";
out.speed = { 'p', 4.5, 90 }
out.accel = { 'p', -0.02, 0 }
out.dontCare = 4;
elseif (bullet.age % 5) == 1 then
orb = {
type = "Direct";
speed = { 'p', 5.0, math.random()*360-180 };
accel = { 'p', -0.05, 0 };
dontCare = 100;
};
LBS_LAUNCH("Orb1", orb);
elseif bullet.age > 200 then
out.type = "Removed";
end
return out;
end
};
LBS_REGISTER("FrozenOrb");
-- Orb1: Children of Frozen Orb -----------------------------------------------
Orb1 = {
size = 10;
seg = 8;
color = { 0.6, 0.8, 1.0 };
};
LBS_REGISTER("Orb1");
日文什麼的就不要太在意了,明天還是要上班,各位晚安~
0 意見:
張貼留言