2008年8月22日 星期五

啥?SL—【關於俺們的專題】

  本來土地都設定為開放,但因為Second Life的開放限制太寬,無法對特定的人做一些很明確的權限,很多人不是亂移動就是亂把東西拿走,搞得遊戲有一段時間無法進行,所以我程式碼和物件都鎖住了,雖然我是覺得應該沒有半個人會去看啦,但我還是想秉持著創作共享、天下為公的精神來分享。

  因此真的有哪個人那麼有興趣,就只能從下載文件去看。

  還有,目前遊戲地點已改為http://slurl.com/secondlife/Jelloab/71/6/695

2008年4月8日 星期二

啥?Web—【X3D入門】

VRML/X3D的相關連結

  這篇文章是為了方便研究X3D而有的入門,希望各組員或有興趣的同學研究了什麼樣的心得,儘量po在xml板,畢竟po文也有算分數的,就算只是單純的心得,應該也是有分。

什麼是X3D?X3D有以下相關連結,在這邊就不多加敘述了:

  基本上這篇教學會以EasyVR論壇裡的有一位會員"雪碧+可樂"發表的12篇"X3D實戰基礎講座"文章為輔,因此我在這邊放上連結(http://www.easyvr.org/archiver/?fid-4-page-5.html),從裡面的文章列表就可以看到,不過內文的自訂語法已經失效,所以看圖會非常麻煩,所以我就私自修改他那12篇文章,並把他用成繁體,放在這邊以供下載(如原作者看到,不妥請告知)。不過蠻遺憾的是,在他那幾篇教學,最後面好幾章的圖片是沒有被貼上的……

哪裡可以看見X3D?

 首先,第一個最重要的問題,就是解決,要在哪看到X3D……因為,X3D還不是很普及,不像flash的嵌入已經是隨處可見,因此他也要像下載flash外掛一樣,去下載一個可以看X3D或VRML的瀏覽器。在上面的X3D plugin連結中有介紹很多,在這邊也不介紹了。本人是用Xj3D單獨觀看,Flux player當作firefox或ie的plugin(此處下載),讓我的瀏覽器可以看到X3D或VRML,當你灌好了Flux player後,以後開啟X3D或VRML檔案,就會像以下的圖示:



  當然你也可以在你的瀏覽器看到,只要你想辦法像flash那樣嵌入就可以了(可到此處觀看是否可以在你的瀏覽器看到VRML/X3D)。

  至於我為何還灌了Xj3D呢……這個東西既然不是瀏覽器的外掛,也沒有什麼特別的功能,那為何還要灌?主要是因為我在X3D-Edit看到的3D影像都無法即時更新我修改好的X3D程式,而Flux player也沒有看到重整的按鈕,因為XJ3D有Reload的按鈕,所以我在寫程式看結果時,比較喜歡用這個,以下是XJ3D瀏覽器所看到的圖示:



  而X3D實戰基礎講座之一裡用的是另一種瀏覽器,或許也可以參考參考該篇文章(注意,該文提供的X3D-Edit連結已經失效)。

X3D-Edit

  X3D-Edit是X3D的編輯器,這裡是X3D3.2的下載處(https://savage.nps.edu/X3D-Edit/)(下載點),要注意的是這個軟體是綠色軟體,解壓縮後點選runX3dEditWin.bat即可(這個檔案不在資料夾內)。

 以下為X3D_Edit3.2的圖示:




程式碼入門

  其實X3D的架構很單純,就是要有x3d的宣告、head element所需要的宣告、再來才是最重要的內容 Scene這個element,只要你用了X3D-Edit,new一個物件,他就會幫你產生一個以上所提到的X3D所需基本element(可參考X3D實戰基礎講座之二)。

  而所有的3D物件,都是被放在Scene這個Element下的,而不只是3D物件,可能你要敘述瀏覽者的觀賞方式(可參考X3D實戰基礎講座之六)(NavigationInfo Element),或著顯示3D物件的背景顏色(Background Element),或著顯示文字(可參考X3D實戰基礎講座之二),顯示點線面(可參考X3D實戰講座之三),顯示方塊、球或著圓錐(可參考X3D實戰講座之四),改變物件位置、旋轉角度(可參考X3D實戰講座之五),顯示燈光來源(可參考X3D實戰講座之七),顯示基本的Texture(可參考X3D實戰講座之八),顯示多媒體相關:如顯示影片、音樂……等(可參考X3D實戰講座之九),動畫事件、時間事件(可參考X3D實戰講座之十),使用者互動事件(可參考X3D實戰講座之十一)。而X3D實戰講座的最後一章本來應該有個很不錯腳本嵌入範例,可惜他的圖檔都沒有了,所以那個網頁應該幫助不大。

 由於X3D實戰講座都只是貼貼圖,沒有直接貼上xml程式碼,所以我這邊講解一下那個樹狀結構是怎麼看的,假若是長這樣的樹狀結構:



  而這個x3d程式就是代表,有一個大小為2*2*2的方塊(Box),其外表(Appearance)顏色為紅色(RGB為1,0,0)(他以半形空白區格,不是逗號區格),被放在<0,2,0>的位置(Transform)。而他的樣貌如以下圖示:






  那他的程式碼如下(P.s上上面的圖隱藏了head底下的資訊):


<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.1//EN" "http://www.web3d.org/specifications/x3d-3.1.dtd">

<X3D

profile='Immersive' version='3.1'

xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance'

xsd:noNamespaceSchemaLocation='http://www.web3d.org/specifications/x3d-3.1.xsd'>

  <head>

    <meta content='*enter FileNameWithNoAbbreviations.x3d here*' name='title'/>


    <meta content='*enter description here, short-sentence summaries preferred*' name='description'/>

    <meta content='*enter name of original author here*' name='creator'/>

    <meta content='*if manually translating VRML-to-X3D, enter name of person translating here*' name='translator'/>

    <meta content='*enter date of initial version here*' name='created'/>

    <meta content='*enter date of translation here*' name='translated'/>

    <meta content='*enter date of latest revision here*' name='modified'/>


    <meta content='*enter version here, if any*' name='version'/>

    <meta content='*enter reference citation or relative/online url here*' name='reference'/>

    <meta content='*enter additional url/bibliographic reference information here*' name='reference'/>

   

<meta content='*enter reference resource here if required to support

function, delivery, or coherence of content*' name='requires'/>

    <meta content='*enter copyright information here* Example: Copyright (c) Web3D Consortium Inc. 2008' name='rights'/>


    <meta content='*enter drawing filename/url here*' name='drawing'/>

    <meta content='*enter image filename/url here*' name='image'/>

    <meta content='*enter movie filename/url here*' name='MovingImage'/>

    <meta content='*enter photo filename/url here*' name='photo'/>

    <meta content='*enter subject keywords here*' name='subject'/>

    <meta content='*enter permission statements or url here*' name='accessRights'/>


    <meta content='*insert any known warnings, bugs or errors here*' name='warning'/>

   

<meta content='*enter online Uniform Resource Identifier (URI) or

Uniform Resource Locator (URL) address for this file here*'

name='identifier'/>

    <meta content='X3D-Edit, https://savage.nps.edu/X3D-Edit' name='generator'/>

    <meta content='../../license.html' name='license'/>

   


<!-- Additional authoring resources for meta-tags:

http://www.dublincore.org/documents/dcmi-terms

http://www.dublincore.org/documents/dces

http://www.w3.org/TR/html4/struct/global.html#h-7.4.4

http://vancouver-webpages.com/META

http://vancouver-webpages.com/META/about-mk-metas2.html Additional

authoring resources for language codes:

ftp://ftp.isi.edu/in-notes/bcp/bcp47.txt


http://www.loc.gov/standards/iso639-2/langhome.html

http://www.iana.org/numbers.html#L -->

  </head>

  <Scene>

     <Transform translation="0 2 0">

      <Shape>


         <Appearance>

             <Material diffuseColor="1.0 0.0 0.0"/>

            

<!--Add ImageTexture, MovieTexture, PixelTexture, TextureTransform,

FillProperties, and/or LineProperties nodes here-->

         </Appearance>

          <Box size="2 2 2"/>


      </Shape><!-- Scene graph nodes are added here -->

      </Transform>

  </Scene>

</X3D>

如何讓3D美工軟體變成X3D

  使用maya的朋友可以使用這個外掛(http://rawkee.sourceforge.net/)

  而使用3ds max的朋友,我目前找到的Octaga似乎只能把它轉成wrl檔,而wrl檔並不是xml
base的檔案,他是VRML時代的檔案,因此不是我們要的,而且最重要的是,3ds max9就可以自己轉成wrl檔了。雖然我上網看都說wrl檔算是X3D檔案格式,但打開來後明明就不是xml base。而我後來是利用了在這邊(http://www.pinecoast.com/download.htm)下載的SwirlX3D讀進我3ds max9轉成的wrl檔,再將其另存為X3D,才可行的,不然我網路上找了好久,都沒有wrl直接變成x3D檔或著直接將3ds max做好的3D轉成x3D(找到的都無法如願達成)。

  沒記錯的話,去年的學弟就是利用了maya做好的模型,將其佈置好房間後觀看的(好像有影片、網址連結……等)。

2008年3月31日 星期一

啥SL—【如何讓字元顯示在Texture上做留言板】


  相信有研究過LSL一段時間的人都會知道,想在Second Life搞出動態的2D圖片,能用到的大概只有llSetTexture之類修改表面材質的method。而想要輸出動態更改的文字,所能用的大概也只有llSetText。因此,我這圖上的Weco Borad Beta,到底是如何做到的呢?

  如果仔細將我上面所提到的東西思考,我想大家應該都想得到原理,那就是準備所有字元的Texture,然後當使用者想要什麼字時,就顯示該Texture。

  可是問題是這要實在是太花錢了,所以在Sloodle(Second Life+Moodle)所提供免費的物件當中,你會發現,他們用了一個非常棒的方法。事實上,每一個被上傳的Texture都會有自己的id值,你只要知道其id值,你就可以利用llSetTexture拿來引用到你的物件上(eg.llSetTexture("701917a8-d614-471f-13dd-5f4644e36e3c", 0);//這個就是將index為0那一面材質設為透明,如何得知該面的index值,可以參考這個影片)。

  而Sloodel很聰明地將ASCII可顯現的95個字元上五個他們自訂的字元用成一個10*10的Texture,如圖:


  然後利用llSetPrimitiveParams一一取出每個字元,看到這裡會不會覺得發明這個的人很屌?他厲害的可還不只這裡,他並不是每一個字元一個Box,他是每五個字元一個Prism,利用參數修改,將五個面呈現在正面,並利用LSL將每個顯示的字元平均顯示在五個面。如圖:

  他的參數是將Prism的Patch Cut Begin and End 的B設為0.199,E設為0.800,Hollow設為68,如此一來,正面就會有五個面,他就利用了一個物件顯示五個字元,大大節省了物件成本(畢竟一個土地的物件量有限)。


  而由於中間的Texture所站的大小和其他Texture顯示不一樣,他還特地利用了llSetPrimitiveParams寫死,取出適當的大小。
  
  簡單來講原理就是這個樣子,而他所寫的程式碼如下:


////////////////////////////////////////////
// XyText v1.2 Script (5 Face, Single Texture)
//
// Written by Xylor Baysklef
//
// Modified by Kermitt Quirk 19/01/2006
// To add support for 5 face prim instead of 3
//
////////////////////////////////////////////

/////////////// CONSTANTS ///////////////////
// XyText Message Map.
integer DISPLAY_STRING = 204000;
integer DISPLAY_EXTENDED = 204001;
integer REMAP_INDICES = 204002;
integer RESET_INDICES = 204003;
integer SET_CELL_INFO = 204004;
integer SET_FONT_TEXTURE = 204005;
integer SET_THICKNESS = 204006;
integer SET_COLOR = 204007;

// This is an extended character escape sequence.
string ESCAPE_SEQUENCE = "\\e";

// This is used to get an index for the extended character.
string EXTENDED_INDEX = "12345";

// Face numbers.
integer FACE_1 = 3;
integer FACE_2 = 7;
integer FACE_3 = 4;
integer FACE_4 = 6;
integer FACE_5 = 1;

// Used to hide the text after a fade-out.
key TRANSPARENT = "701917a8-d614-471f-13dd-5f4644e36e3c";
///////////// END CONSTANTS ////////////////

///////////// GLOBAL VARIABLES ///////////////
// This is the key of the font we are displaying.
key gFontTexture = "b2e7394f-5e54-aa12-6e1c-ef327b6bed9e";
// All displayable characters. Default to ASCII order.
string gCharIndex;
// This is the channel to listen on while acting
// as a cell in a larger display.
integer gCellChannel = 1;
// This is the starting character position in the cell channel message
// to render.
integer gCellCharPosition = 0;
// This is whether or not to use the fade in/out special effect.
integer gCellUseFading = FALSE;
// This is how long to display the text before fading out (if using
// fading special effect).
// Note: < 0 means don't fade out.
float gCellHoldDelay = 1.0;
/////////// END GLOBAL VARIABLES ////////////

ResetCharIndex() {
gCharIndex = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`";
// \" <-- Fixes LSL syntax highlighting bug.
gCharIndex += "abcdefghijklmnopqrstuvwxyz{|}~";
gCharIndex += "\n\n\n\n\n";
}

vector GetGridOffset(integer index) {
// Calculate the offset needed to display this character.
integer Row = index / 10;
integer Col = index % 10;

// Return the offset in the texture.
return <-0.45 + 0.1 * Col, 0.45 - 0.1 * Row, 0.0>;
}

ShowChars(vector grid_offset1, vector grid_offset2, vector grid_offset3, vector grid_offset4, vector grid_offset5) {
// Set the primitive textures directly.

// <-0.256, 0, 0>
// <0, 0, 0>
// <0.130, 0, 0>
// <0, 0, 0>
// <-0.74, 0, 0>

llSetPrimitiveParams( [
PRIM_TEXTURE, FACE_1, (string)gFontTexture, <0.12, 0.1, 0>, grid_offset1 + <0.037, 0, 0>, 0.0,
PRIM_TEXTURE, FACE_2, (string)gFontTexture, <0.05, 0.1, 0>, grid_offset2, 0.0,
PRIM_TEXTURE, FACE_3, (string)gFontTexture, <-0.74, 0.1, 0>, grid_offset3 - <0.244, 0, 0>, 0.0,
PRIM_TEXTURE, FACE_4, (string)gFontTexture, <0.05, 0.1, 0>, grid_offset4, 0.0,
PRIM_TEXTURE, FACE_5, (string)gFontTexture, <0.12, 0.1, 0>, grid_offset5 - <0.037, 0, 0>, 0.0
]);
}

RenderString(string str) {
// Get the grid positions for each pair of characters.
vector GridOffset1 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 0, 0)) );
vector GridOffset2 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 1, 1)) );
vector GridOffset3 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 2, 2)) );
vector GridOffset4 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 3, 3)) );
vector GridOffset5 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 4, 4)) );

// Use these grid positions to display the correct textures/offsets.
ShowChars(GridOffset1, GridOffset2, GridOffset3, GridOffset4, GridOffset5);
}

RenderWithEffects(string str) {
// Get the grid positions for each pair of characters.
vector GridOffset1 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 0, 0)) );
vector GridOffset2 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 1, 1)) );
vector GridOffset3 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 2, 2)) );
vector GridOffset4 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 3, 3)) );
vector GridOffset5 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 4, 4)) );

// First set the alpha to the lowest possible.
llSetAlpha(0.05, ALL_SIDES);

// Use these grid positions to display the correct textures/offsets.
ShowChars(GridOffset1, GridOffset2, GridOffset3, GridOffset4, GridOffset5); // Now turn up the alpha until it is at full strength.
float Alpha;
for (Alpha = 0.10; Alpha <= 1.0; Alpha += 0.05)
llSetAlpha(Alpha, ALL_SIDES);
// See if we want to fade out as well.
if (gCellHoldDelay < 0.0)
// No, bail out. (Just keep showing the string at full strength).
return;
// Hold the text for a while.
llSleep(gCellHoldDelay);
// Now fade out.
for (Alpha = 0.95; Alpha >= 0.05; Alpha -= 0.05)
llSetAlpha(Alpha, ALL_SIDES);
// Make the text transparent to fully hide it.
llSetTexture(TRANSPARENT, ALL_SIDES);
}

RenderExtended(string str) {
// Look for escape sequences.
list Parsed = llParseString2List(str, [], [ESCAPE_SEQUENCE]);
integer ParsedLen = llGetListLength(Parsed);

// Create a list of index values to work with.
list Indices;
// We start with room for 5 indices.
integer IndicesLeft = 5;

integer i;
string Token;
integer Clipped;
integer LastWasEscapeSequence = FALSE;
// Work from left to right.
for (i = 0; i < ParsedLen && IndicesLeft > 0; i++) {
Token = llList2String(Parsed, i);

// If this is an escape sequence, just set the flag and move on.
if (Token == ESCAPE_SEQUENCE) {
LastWasEscapeSequence = TRUE;
}
else { // Token != ESCAPE_SEQUENCE
// Otherwise this is a normal token. Check its length.
Clipped = FALSE;
integer TokenLength = llStringLength(Token);
// Clip if necessary.
if (TokenLength > IndicesLeft) {
Token = llGetSubString(Token, 0, IndicesLeft - 1);
TokenLength = llStringLength(Token);
IndicesLeft = 0;
Clipped = TRUE;
}
else
IndicesLeft -= TokenLength;

// Was the previous token an escape sequence?
if (LastWasEscapeSequence) {
// Yes, the first character is an escape character, the rest are normal.

// This is the extended character.
Indices += [llSubStringIndex(EXTENDED_INDEX, llGetSubString(Token, 0, 0)) + 95];

// These are the normal characters.
integer j;
for (j = 1; j < TokenLength; j++)
Indices += [llSubStringIndex(gCharIndex, llGetSubString(Token, j, j))];
}
else { // Normal string.
// Just add the characters normally.
integer j;
for (j = 0; j < TokenLength; j++)
Indices += [llSubStringIndex(gCharIndex, llGetSubString(Token, j, j))];
}

// Unset this flag, since this was not an escape sequence.
LastWasEscapeSequence = FALSE;
}
}

// Use the indices to create grid positions.
vector GridOffset1 = GetGridOffset( llList2Integer(Indices, 0));
vector GridOffset2 = GetGridOffset( llList2Integer(Indices, 1) );
vector GridOffset3 = GetGridOffset( llList2Integer(Indices, 2) );
vector GridOffset4 = GetGridOffset( llList2Integer(Indices, 3) );
vector GridOffset5 = GetGridOffset( llList2Integer(Indices, 4) );

// Use these grid positions to display the correct textures/offsets.
ShowChars(GridOffset1, GridOffset2, GridOffset3, GridOffset4, GridOffset5);
}

integer ConvertIndex(integer index) {
// This converts from an ASCII based index to our indexing scheme.
if (index >= 32) // ' ' or higher
index -= 32;
else { // index < 32
// Quick bounds check.
if (index > 15)
index = 15;

index += 94; // extended characters
}

return index;
}


  上面這個程式碼只是他在全域函式的程式碼,並不是完整的LSL code,而你只要把物件調好,在default前放入這個Script,就可以直接利用他寫的RenderString(string str)將五個字元顯示在一個物件之上。

  那本人那個留言板,就是將每個物件編上名字(Mx-y),代表他是顯示留言內容(以M代表)的第x行第y列,而NameX-Y就是顯示名字的第X行第Y列。將好幾個物件組成並改寫他們的名字,之後Link起來,利用llMessageLinked傳送,而這時每個物件就會因為他們的位置不同而取得適當的文字,並將他顯示出來。

  原理大概就是這個樣子,我那個留言板的功能只有當某人點Touch,說話後,他就會顯示是誰在那個板子說了什麼話。我列一下程式碼:
母物件程式碼(只是單純的一個白色板子):

integer listenHandle;

string message1="Please leave one message.There is 200 charactors that you can leave.(only English)";

integer oneLineLimit=20;// a line just has 20 charactors
integer messageLimit=200;//all message just has 200 charactors.

string guestName;
integer LM_NAME=100;
integer LM_MESSAGE=101;

default
{
state_entry()
{
llSetText("WECO Board Beta",<0,1,1>,1);

}

touch_start(integer total)
{
guestName=llDetectedName(0);

listenHandle=llListen(0,guestName,"","");

llSay(0,message1);//tell user leave message.

}

listen(integer ch,string name,key id, string str )
{
//llSay(0,guestName);//for test
//llSay(0,(string)llStringLength(guestName));

if( llStringLength(guestName) <= (oneLineLimit-6) )//because " said:"has 5 charactors
{
llMessageLinked(LINK_SET,LM_NAME,guestName,"");
}

else
{

}

if( llStringLength(str) <= messageLimit )
{
llMessageLinked(LINK_SET,LM_MESSAGE,str,"");

}

else
{
llSay(0,"OOPS!!Your message's charactors are over 200.Please reduce your message and say it again.Thanks!!");
}

llResetScript();

}
}

顯示字元的物件(這個有分顯示Name和訊息,但程式碼幾乎一模一樣,只是物件名稱不太一樣而已,該程式是顯示名字的,所以在Default那的截取是Name,不是M):

////////////////////////////////////////////
// XyText v1.2 Script (5 Face, Single Texture)
//
// Written by Xylor Baysklef
//
// Modified by Kermitt Quirk 19/01/2006
// To add support for 5 face prim instead of 3
//
////////////////////////////////////////////

/////////////// CONSTANTS ///////////////////
// XyText Message Map.
integer DISPLAY_STRING = 204000;
integer DISPLAY_EXTENDED = 204001;
integer REMAP_INDICES = 204002;
integer RESET_INDICES = 204003;
integer SET_CELL_INFO = 204004;
integer SET_FONT_TEXTURE = 204005;
integer SET_THICKNESS = 204006;
integer SET_COLOR = 204007;

// This is an extended character escape sequence.
string ESCAPE_SEQUENCE = "\\e";

// This is used to get an index for the extended character.
string EXTENDED_INDEX = "12345";

// Face numbers.
integer FACE_1 = 3;
integer FACE_2 = 7;
integer FACE_3 = 4;
integer FACE_4 = 6;
integer FACE_5 = 1;

// Used to hide the text after a fade-out.
key TRANSPARENT = "701917a8-d614-471f-13dd-5f4644e36e3c";
///////////// END CONSTANTS ////////////////

///////////// GLOBAL VARIABLES ///////////////
// This is the key of the font we are displaying.
key gFontTexture = "b2e7394f-5e54-aa12-6e1c-ef327b6bed9e";
// All displayable characters. Default to ASCII order.
string gCharIndex;
// This is the channel to listen on while acting
// as a cell in a larger display.
integer gCellChannel = 1;
// This is the starting character position in the cell channel message
// to render.
integer gCellCharPosition = 0;
// This is whether or not to use the fade in/out special effect.
integer gCellUseFading = FALSE;
// This is how long to display the text before fading out (if using
// fading special effect).
// Note: < 0 means don't fade out.
float gCellHoldDelay = 1.0;
/////////// END GLOBAL VARIABLES ////////////

ResetCharIndex() {
gCharIndex = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`";
// \" <-- Fixes LSL syntax highlighting bug.
gCharIndex += "abcdefghijklmnopqrstuvwxyz{|}~";
gCharIndex += "\n\n\n\n\n";
}

vector GetGridOffset(integer index) {
// Calculate the offset needed to display this character.
integer Row = index / 10;
integer Col = index % 10;

// Return the offset in the texture.
return <-0.45 + 0.1 * Col, 0.45 - 0.1 * Row, 0.0>;
}

ShowChars(vector grid_offset1, vector grid_offset2, vector grid_offset3, vector grid_offset4, vector grid_offset5) {
// Set the primitive textures directly.

// <-0.256, 0, 0>
// <0, 0, 0>
// <0.130, 0, 0>
// <0, 0, 0>
// <-0.74, 0, 0>

llSetPrimitiveParams( [
PRIM_TEXTURE, FACE_1, (string)gFontTexture, <0.12, 0.1, 0>, grid_offset1 + <0.037, 0, 0>, 0.0,
PRIM_TEXTURE, FACE_2, (string)gFontTexture, <0.05, 0.1, 0>, grid_offset2, 0.0,
PRIM_TEXTURE, FACE_3, (string)gFontTexture, <-0.74, 0.1, 0>, grid_offset3 - <0.244, 0, 0>, 0.0,
PRIM_TEXTURE, FACE_4, (string)gFontTexture, <0.05, 0.1, 0>, grid_offset4, 0.0,
PRIM_TEXTURE, FACE_5, (string)gFontTexture, <0.12, 0.1, 0>, grid_offset5 - <0.037, 0, 0>, 0.0
]);
}

RenderString(string str) {
// Get the grid positions for each pair of characters.
vector GridOffset1 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 0, 0)) );
vector GridOffset2 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 1, 1)) );
vector GridOffset3 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 2, 2)) );
vector GridOffset4 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 3, 3)) );
vector GridOffset5 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 4, 4)) );

// Use these grid positions to display the correct textures/offsets.
ShowChars(GridOffset1, GridOffset2, GridOffset3, GridOffset4, GridOffset5);
}

RenderWithEffects(string str) {
// Get the grid positions for each pair of characters.
vector GridOffset1 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 0, 0)) );
vector GridOffset2 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 1, 1)) );
vector GridOffset3 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 2, 2)) );
vector GridOffset4 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 3, 3)) );
vector GridOffset5 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 4, 4)) );

// First set the alpha to the lowest possible.
llSetAlpha(0.05, ALL_SIDES);

// Use these grid positions to display the correct textures/offsets.
ShowChars(GridOffset1, GridOffset2, GridOffset3, GridOffset4, GridOffset5); // Now turn up the alpha until it is at full strength.
float Alpha;
for (Alpha = 0.10; Alpha <= 1.0; Alpha += 0.05)
llSetAlpha(Alpha, ALL_SIDES);
// See if we want to fade out as well.
if (gCellHoldDelay < 0.0)
// No, bail out. (Just keep showing the string at full strength).
return;
// Hold the text for a while.
llSleep(gCellHoldDelay);
// Now fade out.
for (Alpha = 0.95; Alpha >= 0.05; Alpha -= 0.05)
llSetAlpha(Alpha, ALL_SIDES);
// Make the text transparent to fully hide it.
llSetTexture(TRANSPARENT, ALL_SIDES);
}

RenderExtended(string str) {
// Look for escape sequences.
list Parsed = llParseString2List(str, [], [ESCAPE_SEQUENCE]);
integer ParsedLen = llGetListLength(Parsed);

// Create a list of index values to work with.
list Indices;
// We start with room for 5 indices.
integer IndicesLeft = 5;

integer i;
string Token;
integer Clipped;
integer LastWasEscapeSequence = FALSE;
// Work from left to right.
for (i = 0; i < ParsedLen && IndicesLeft > 0; i++) {
Token = llList2String(Parsed, i);

// If this is an escape sequence, just set the flag and move on.
if (Token == ESCAPE_SEQUENCE) {
LastWasEscapeSequence = TRUE;
}
else { // Token != ESCAPE_SEQUENCE
// Otherwise this is a normal token. Check its length.
Clipped = FALSE;
integer TokenLength = llStringLength(Token);
// Clip if necessary.
if (TokenLength > IndicesLeft) {
Token = llGetSubString(Token, 0, IndicesLeft - 1);
TokenLength = llStringLength(Token);
IndicesLeft = 0;
Clipped = TRUE;
}
else
IndicesLeft -= TokenLength;

// Was the previous token an escape sequence?
if (LastWasEscapeSequence) {
// Yes, the first character is an escape character, the rest are normal.

// This is the extended character.
Indices += [llSubStringIndex(EXTENDED_INDEX, llGetSubString(Token, 0, 0)) + 95];

// These are the normal characters.
integer j;
for (j = 1; j < TokenLength; j++)
Indices += [llSubStringIndex(gCharIndex, llGetSubString(Token, j, j))];
}
else { // Normal string.
// Just add the characters normally.
integer j;
for (j = 0; j < TokenLength; j++)
Indices += [llSubStringIndex(gCharIndex, llGetSubString(Token, j, j))];
}

// Unset this flag, since this was not an escape sequence.
LastWasEscapeSequence = FALSE;
}
}

// Use the indices to create grid positions.
vector GridOffset1 = GetGridOffset( llList2Integer(Indices, 0));
vector GridOffset2 = GetGridOffset( llList2Integer(Indices, 1) );
vector GridOffset3 = GetGridOffset( llList2Integer(Indices, 2) );
vector GridOffset4 = GetGridOffset( llList2Integer(Indices, 3) );
vector GridOffset5 = GetGridOffset( llList2Integer(Indices, 4) );

// Use these grid positions to display the correct textures/offsets.
ShowChars(GridOffset1, GridOffset2, GridOffset3, GridOffset4, GridOffset5);
}

integer ConvertIndex(integer index) {
// This converts from an ASCII based index to our indexing scheme.
if (index >= 32) // ' ' or higher
index -= 32;
else { // index < 32
// Quick bounds check.
if (index > 15)
index = 15;

index += 94; // extended characters
}

return index;
}

integer LM_NAME=100;
integer LM_MESSAGE=101;

default
{
state_entry()
{
// Initialize the character index.
ResetCharIndex();

}

link_message(integer linknum, integer num, string str, key id)
{
//llSay(0,str);//for test
//llSay(0,(string)num);//for test

if(num==LM_MESSAGE)
{
//llSay(0,str);//for test

//llSay(0,llList2String( llParseString2List( llGetObjectName(),[],["Name"] ) ,1));//for test

integer x= (integer)llList2String( llParseString2List( llList2String( llParseString2List( llGetObjectName(),[],["M"] ) ,1),["-"],[]) ,0);

integer y=(integer)llList2String( llParseString2List( llList2String( llParseString2List( llGetObjectName(),[],["M"] ) ,1) ,["-"],[]) ,1);

//llSay(0,"x="+(string)x+",y="+(string)y);//for test

integer indexHead=(x-1)*5+(y-1)*20;
integer indexTail=indexHead+4;

RenderString( llGetSubString(str,indexHead,indexTail) );

}
}
}


  總之,差不多就是這樣,我有在Sand Box同學做的妙手回春那裡放置,我想有興趣的同學應該可以直接買來修改。而這程式碼最重要的功能是由Sloode提供的SloodleToolbar裡我抓出來的程式寫成的。所以並不完全是我做的,只是他開放大家可以修改而已……

  我想這個做出來後,想必有非常多的應用,比如把網頁上留言板的留言利用HTTPRequest傳進Second Life,並顯示,當然也可以做更多比我做的留言板還要好的功能,比如記錄每個留言者的內容寫入notecard(對於notecard程式我還沒碰過,不過我想應該可以),然後還有換頁功能……等

  當然類似的想法可能還有小畫家(利用touch event和更改texture畫出直線)……等,或許各位專題要是想不到做什麼,可以往這些方向去想……

這就是Sloodle提供的Sloodle Toolbar

2008年3月28日 星期五

啥SL—【利用llGetObjectDetails得知物件相關訊息】

  list llGetObjectDetails(key id, list params)這個method可以得知一個物件以下訊息:

1.物件或人物名稱

2.物件或人物位置

3.物件或人物的角度

4.物件或人物的速度

5.物件的擁有者

6.物件的Group

7.物件的創造者

8.物件的敘述

  這個method是會回傳一個list屬性,而你必須輸入一個key值的參數和一個list的參數。key值的參數就是一個物件或人物的id,在Second Life裡面每個人事物都有個id,其實也就是老師上課提到的UUID。而另一個list是要輸入什麼呢?就是你想要知道的 資訊,比如說,你想要知道該key值為"00000000-0000-0000-0000-000000000000"的物件名稱,你可以寫:


key id= "00000000-0000-0000-0000-000000000000";

list testList=llGetObjectDetails( id,[OBJECT_NAME]);


  他就會把這個key值名稱放入testList了,而想要say出來變成字串,只要多多利用List的llList2String(list src, integer index)(或llList2Key、llList2Rot、llList2Float、llList2Vector、llList2Integer),總之相當於get(index)取LinkedList裡面的東西就是了,只是LSL這個list他裡面能放的東西屬性不唯一。

所有的參數如下表格:

參數 變數型態 如果key值為物件 如果key值為人
OBJECT_NAME string

回傳物件名稱,有一點像 llKey2Name

這個method。

回傳該key值的人物名稱。
OBJECT_DESC string 回傳該物件敘述 回傳空字串
OBJECT_POS vector 回傳該物件位置 回傳該人物位置
OBJECT_ROT rotation 回傳該物件角度 回傳該人物角度
OBJECT_VELOCITY vector 回傳該物件的速度 Returns agent velocity.
OBJECT_OWNER key 回傳擁有者的key值

如果該物件被Deed給某Grouo的話,回傳NULL_KEY

回傳該人的key值
OBJECT_GROUP key 回傳該物件的Group 回傳NULL_KEY
OBJECT_CREATOR key 回傳該物件的創造者 回傳NULL_KEY

  其實和這個類似的method有:llGetKey、llGetCreator、llGetObjectName……等,但是這些都是只能得知該Script的物件相關訊息而已。 並不像我現在介紹的llGetObjectDetails那麼廣。

  而得知這些訊息有什麼用?像是llGetCreator我就認為超有用的,這個在我們專題開發時並沒有這個method,害我們不能百分之百過濾不是我們 的武器打到怪物不會損血(我們是判斷物件名字與物件的Group)。而像是得知一個人的位置,我也可以寫一個一直追你的Robot。

2008年3月2日 星期日

啥?【慶祝電腦玩家創刊200期!!】


  我還記得……我第一本電腦玩家…是怎麼來的。

  1992年11月第16期,這是,我的第一本電腦玩家。

  那個時候,我還只是幼稚園大班呢。我從來沒有忘記,那天的情境……就跟我是如何拿到我人生第一款正版電腦遊戲"聖域傳說"……一樣清楚,我還記得我當年一直把它念成聖"城"傳說呢……雖然到現在仍然沒破關,但是,那個遊戲畫面,我一直沒有忘記……不過,這是題外話了。

  我記得那天我一如往常地和老爸在賣電腦遊戲的地方看著許許多多的遊戲。當時,我看到了火箭人的畫面……超帥……

  小時候我都不敢跟我爸說,我要買哪個玩具,或我要買哪個遊戲……不是因為老爸太嚴,而是自己很扭扭捏捏,自己想要的東西,都不敢說……每次都是老爸問起,我才敢講……雖然,我不確定那個時候是不是也是這樣。但我一直記得我想要玩這款遊戲的渴望……

  可是問題是,我那時才幼稚園,ABCD都不認識了,更何況要玩這款國外遊戲?所以老爸當時就買了另一款大宇出的遊戲—"激鬥戰士"來替代它。

  其實當時我是很沮喪的……我還記得那天老爸和我坐在台電大樓前面,有個很高台階的地方……(那地方還在呢……而且一點都沒有變……),他告訴我說火箭人是英文的,我不會懂。之後,就拿出
1992年11月第16期電腦玩家的雜誌,指著當時的評析,告訴我說"激鬥戰士"應該也不錯玩。
  小時候我是不看文章的,根本也不知道這個到底哪裡好玩。不過,我完全沒想到,後來我和我姊姊竟然也曾為了玩它而沉浸過好幾天。我還記得當時,看到每個角色全破畫面的莫名感動。嗯?我有那麼厲害?小時候就會玩這種格鬥遊戲?我還記得我應該不會招式表上的任何一招呀……後來我仔細回想,那時候的電腦玩家是有附秘技的……看了一下,是直接看結局……

  嗯……好像也不是這麼回事。不過我依稀記得當年的確有輸入秘技,然後我一路亂按按得很爽,就破關了。印象中不是直接看結局呀……這是和我回憶產生矛盾的地方……不過不管是怎樣的秘技,我一直記得當時我對著旁邊的方向鍵亂按,然後按到每個角色都破關……看著每個角色的結局……

  其實我現在仔細想想,那時候老爸買給我激鬥戰士不是沒有原因的……因為小時候,我其實最常玩的是紅白機。只愛玩動作遊戲,而電腦遊戲大部分都是要花腦筋思考的,只有動作遊戲是不必花腦筋的……只是這種動作遊戲,我覺得比一般一路砍到底,也就是瑪利兄弟那種ACT相比,難太多了……
  現在覺得蠻遺憾的就是,當年所有買的電腦遊戲,大部分的盒子封面都被我爸丟了。就連這款激鬥戰士,也不例外。(因為太大太站位了……我爸只好把所有遊戲集起來放在一個盒子)

  呵,這就是我第一本電腦玩家得手的經過,雖然中間廢話了不少……

  後來沒有繼續訂,但到了國小一年級的時候。我忘了是什麼原因,我爸問我要不要訂電腦玩家……那一期,是1993年9月號第26期。相隔10個月,我又再度看到了它。不過,我只訂了12期就沒續訂了。其實我爸訂電腦玩家給我的用意,是希望我能夠藉著遊戲學電腦,但我根本沒興趣,只想玩遊戲。而雜誌內的文章,我也都沒興趣,我只看圖和先賭為快看看會有什麼新遊戲,所以評析什麼的我都快速翻過,然後再看我最喜歡看的漫畫街。所以到現在如果講起什麼骨灰遊戲,不管我有沒有玩過,或我有沒有破關,我第一印象就是電腦玩家的圖……像是朱學恒先生的炎龍騎士團二評析,那下面一橫排的圖片,就是我對炎龍騎士團二的另一個印象。

炎龍騎士團的遊戲開頭

當年朱學恒對炎龍2的評析

  耶,你或許會覺得奇怪,炎龍騎士團二評析不是應該在1995年才可能出的嗎?嗯,這評析是在1995年9月號第50期所刊登的,在這之前,我雖然都沒有訂電腦玩家,但我爸都有零星幫我買了幾份……大概是和他逛電腦店買的。

  之後,或許是因為我爸有訂PC Office的關係,所以從電腦玩家1996年11月第64期也開始幫我訂(那時我小四),這一訂,除了中間漏掉的77、78期,就一直看到現在……(後來聽說在7-11買比較能幫助電腦玩家業務,所以不再續訂,都跑去7-11買了XD)

  我一直沒有忘記,我會一直在遊戲基地發言,和大家參與討論。不知不覺增進我寫作實力,讓我看到網路世界的寬廣,就是看到有一次遊戲基地在電腦玩家打的廣告……拉霸可以抽ps2XD~

  雖然我沒有因此一直發言賺G幣,因為我也不喜歡為了這種事而亂灌水。所以只拉了幾次霸,就放棄了……而也讓我一待基地,就待了七年,這是另一個故事了……

  嗯,這真的是陪伴我長大的一本好雜誌。雖然我承認在我高中以前,我都只看圖片還有漫畫街!上高中後才慢慢地去看徐社長講了什麼、後面的專欄講了什麼。這時候我開始注意到了朱學恒的奇幻專欄……不過,這又是另一個故事了……

  後來真正跑去仔細看以前那些評析在講什麼,那些編輯在講什麼的時候,是在我大二時,想要整理電腦玩家的時候。那時候看了以前的雜誌,真的覺得,難怪他們能夠撐那麼久,因為,真的好有內容呀!

  而且,我開始從遊戲基地的電腦玩家板與社長說的話注意到一個很有意思的讀者—秋風。他的文章也有在骨灰集散地精華區裡被集結在一起,叫秋風雜談。

  我特地把那幾段文章掃瞄起來(123)(如電腦玩家或當事者認為不妥,請告知)……再看看遊戲基地裡,電腦玩家板裡當年徐社長和這位讀者的回應……我不知道有沒有人會像我一樣,有種莫名的感動……(雖然基地的搜尋並不完全,但還是可以利用"guan0000"關鍵字看得到一些秋風先生的文章)

  你可以看到,當一個雜誌在轉變時,一個死忠讀者的不捨;也看到他的支持,隨著徐社長的離開,也開始放棄。但你回頭看看這幾篇文章的時候,你又會覺得,這些,曾經是很溫暖的……

  我不知道有多少人能夠這樣把他們的故事看完,但是,我相信,只要是有看完的朋友們,只要你也是個老骨灰,你絕對、絕對,會有所感動的。你會看到徐社長當年創下ACE的精神,也會看到遇到市場轉變的衝擊,更會看到那些死忠讀者面對轉變的無奈,那種情感,是我這邊說再多,也無法表達的……

  而現在看到徐社長還在為台灣的電玩奮鬥、努力,真的是……又有種莫名的感動……從徐社長在之前電玩展演講中留下的個人資料(雖然應該要叫他徐總,但我還是習慣叫他社長……)可以看到,他目前正在努力推廣台灣電子競技,而這是台灣電競官網。我有去聽該場演講,目前社長想要做的是,將玩遊戲變成和打籃球與棒球一樣的理念轉為現實。也就是說,他希望台灣也能有夠像韓國一樣的職業團隊,而這些職業團隊就像是NBA一樣(沒騙你,看了該演講的介紹,韓國的職業玩家就像是NBA球星一樣……)……都有舉辦季賽之類的……雖然台灣目前規模不大,但這是徐社長為台灣遊戲界,所踏出的第一步……

  嗯,好像又扯遠離電腦玩家了……不過,也正是因為電腦玩家,才讓我了解更多的世界……遊戲基地、OOPS、遊戲的製作……等……很多……很多……還有,我要感謝電腦玩家在玩家論壇裡錄取了我七篇文章……真的,當我得知我的文章刊登在影響我這輩子最重要的一本雜誌時,我高興到在床上跳來跳去……這也是,讓我寫作,開始有自信的一步……真的,很謝謝你—電腦玩家

  題外話,電腦玩家的官網雖然找不到以前的的網頁。但我從google裡找到官網其實還保留一些老遊戲的秘技唷。

  在這邊說一下我因為對電腦玩家的感謝而製作的仿第一期偽封面……如有不妥請告知呢。我本來是想在旁邊文章的標題打上什麼三國志100之類的,總之就是希望電腦玩家能夠持續為我們報導遊戲,不過感覺好像會被認為幫三國志打廣告,所以就算了XD~總之,恭喜電腦玩家創刊200期!

  最後,贈詩一首!下台一鞠躬<(__)>

雷風火半片天,四面楚歌唯人強,
穿肚破誰知曉?把酒開懷笑四方。
世不恭且莫取,便化青史讓人賞,
家戶戶都能瞭,字字汗青留今朝!

2008年2月3日 星期日

啥?遊戲剖析—【軒轅劍外傳—漢之雲】


  基本上,這個類別是記錄我對一款遊戲的剖析,而一款遊戲的剖析可以分成很多面,所以每一篇文章都會非常地雜亂。

  OK,進入正題,這款遊戲名稱為:【軒轅劍外傳—漢之雲】,以一款國產遊戲來說,是少數值得一玩的大作。雖然我在我模仿電腦玩家試做的評析給的分數並不高(8分),主要是因為整體內容會讓人覺得有一些可惜之處,但以一款遊戲想要表達的故事內容來說,其實算是值得推薦的。

劇本剖析

  這段剖析有主劇情剖析、要素剖析、人物剖析。

有秘密的女人最美麗
 女主角橫艾的這一句話"有秘密的女人最美麗"貫穿了整個漢之雲的故事
  
  嗯,有咪咪的女人最美麗Zzzz。其實"有秘密的女人最美麗"這句話在故事中橫艾很常說出口,往往都是在要說一些可能是關鍵時刻而提的,這不僅加深了對於女主角的神秘感,也恰到好處地賣玩家關子,讓玩家一直想玩下去。

英雄恨死得不得其所,不得其時

  應該說,橫艾的這一句話貫穿了漢之雲整個故事架構,因為不只是橫艾,就連飛羽部隊這個組織,也讓人好奇,雖然如果你是三國迷,你玩到中間大概就會猜到持國使就是趙雲,還有增長使就是魏延。不過對於一般玩家來說,他們的身份成謎,故事中也故意替他們想要做的事埋伏筆,這樣的安排之下,也會讓玩家想玩下去,想進一步了解"為什麼"。所以在主要劇情安排上,吸引玩家繼續玩下去的這一點,漢之雲算是成功的……

雖然故事到了這裡沒講他是誰,但我認為如果是三國迷應該猜得到。
而這畫面的下一幕,便是一片漆黑,是很典型的—【欲知後事,請待下回分解。】


大義蒼生或許是敗筆!?

  我想,在故事中有一句話應該會引起玩家的省思,就是"大義和蒼生你選擇什麼?"這一句話……

鞠躬盡瘁,死而後已

  其實我第一眼看到這一句話,就知道這種選擇題是給為了限制讀者的觀點所問的。最後的結局多少都會洋洋灑灑地說自己是為了蒼生或為了大義……有一點像投名狀那種感覺。

  該怎麼說呢,其實隨著我看的故事越多,我越來越討厭創作者使用這種手法……不,應該說,很多創作者都會用這種手法,用一種催眠讀者的方式來限制讀者的觀點。簡單來說,像是螢之光裡面一開始會刻意把乾物女塑造成很糟糕的,但隨著故事後面的發展,會發現,其實也沒什麼嘛。而這種將某種極端觀點先帶入給讀者印象的手法就是我剛講的限制讀者的觀點。再舉個例子,水手服與機關槍也是用這種手法,逼得女主角最後只能用暴力解決……主要的原因在於一開始,像是一點都不像黑道的目高組只是因為是黑道所以無法報警方保護,這點就是利用了壞人無法被好人保護的鳥觀點而下去限制讀者的觀點,進而寫出後面的故事。

橫艾是第n代壺中仙

  基本上,其實很多故事都會用這種手法,我討厭的其實不是用這種手法,而是用了這種手法,有兩種走向是我最討厭的了……

  第一種最常發生在勇者與魔王那種很古早時期的遊戲。就是從頭到尾極端的想法都不改變……更討人厭的是還要讓那種人死得很慘或死得一點價值都沒有。最簡單的例子就是,我認為你是壞人,所以你一輩子都是壞人,而壞人不管做什麼,都是壞人……其實這樣的走向有一點像士氣論,就是要殺敵,總要有個理由,不然殺起來不會殺得徹底,我想這也是打戰時高層玩弄士兵的手段,因為上層都是有頭腦的,沒有頭腦的上層通常不會活太久。

  而第二種呢,就是一樣是極端的限制觀點,但是其論點總是用在戰爭上……就像是投名狀那樣,我為了讓老百姓過得好一點,所以我要爭到某個位置,但我不得不殺了某個人……老實說我們看故事通常都是看幾位上位腦袋瓜在想什麼的,所以老實說如果你上位者有崇高的理想,可是一直把大義和蒼生掛在嘴邊但卻一直拼命地殺人,卻會讓我覺得一點也不實際……

  這可是在打戰耶!?你趙雲打了那麼多次的戰,難道士兵就不曾是老百姓嗎?難道你行軍時沒看過老百姓嗎?又不是養尊處優的死貴族,竟然還會到現在才了解,原來打戰打了那麼多年,苦的是這些老百姓這種想法。最後更扯的是想殺了孔明,認為殺一人能夠救蒼生……如果你是說兩兵對恃,擒賊先擒王我能夠認同,因為這是讓對方士氣大亂的一種手段。可是和為了和平的理想相比,是不能混著談的……

最後還是要讓魏延把七星燈踢倒的典故放了進去(茶)

  這時候就不得不把火鳳燎原搬出來了,張飛說”殺人就是殺人,哪來那麼多的理由?”這點一語道破那些只是一味地認為自己才是崇高理想的極端主義者但又得殺人的矛盾想法……

雖然這句話是郭嘉先說的,但是同樣都是智者,我比較喜歡張飛呀……

  所以在漢之雲中,趙雲真的不像是打過戰的人,比較像是養尊處優,不知道打戰本來就會勞民傷財的貴族……所以他一直抱著這種什麼為了蒼生的想法,從頭到尾只會說一句要為了蒼生……還真的是讓我想打人……

  火鳳中都可以從故事中看到劉備矛盾的掙扎,但也有自我的堅持……所以重點是故事……而這故事包含了挫折的衝擊自我的想法,還有畫面的振憾

壺中仙就是在戰亂的環境下,寫下這首詩的……

  但漢之雲只想用文字敘述,且敘述得非常簡單,這點是讓我所不能茍同的,而且後來趙雲又搬出要誓死消滅曹賊……讓我覺得很無言呀……這豈不是又要打戰了嗎……

結果你還是把沒悟懂戰爭嘛……冏rz……

  你要殺孔明也得提出一個完整的計劃,不能只是一味地用一個理由而想殺了他,應該還要想,殺了他之後該怎麼做?是要投降魏國呢?還是要只堅守邊界維持國內的和平就好?而且也沒想過殺了孔明後會造成士氣大傷,魏軍可能會趁勝追擊,除非你投降,不然到時候還不是要打戰?

  也因為漢之雲總是用文字敘述大義和蒼生,所以常常會看到一長串啦哩啦渣的對話,老實說,我不是說有理想不好,但一篇故事看到一直在說理,是很無趣的……如果你要說理,要簡短一點,或直接一點,畫面要恰到某個好景點……所以我不得不再度提起火鳳張飛所說的話"殺人就殺人,哪來那麼多理由?"

  不是說不能夠沒有理由,但因為遊戲中總是以主角為觀點,如果其他人的觀點不容易詳述,那請刪掉好咩?不要一直用對話呀,那樣說教是會讓人覺得無趣的……因為太過於老掉牙了……而且兩人的爭執往往是沒有誰對誰錯的,用這種方式來呈現某一種大義的矛盾感也很糟糕……其實這種像是讀完悲狀史詩的讀後感大義,可以用別種方式呈現……像火鳳臥龍睡了那段,就是以孔明看到戰爭的無奈,簡短了自言自語說了些話,然後就又沉睡了……這種表達方式我覺得淡而有力呀……

  不過老實說,一般那種愛看戰爭大義的讀者,是不會在意那麼多的……而且可能還會因為那些話語而情緒激動(畢竟古時候也很常用這種話來激勵士兵送死的)……但問題是那是電影短片,比較適合這種單純地催眠手法,而且電影會用鏡頭取勝,不會只是兩個人對話那樣的枯燥乏味。而遊戲算是長期抗戰,那種不斷地說教是讓人覺得想睡覺的,雖然我承認我自己寫的小說也有犯過一樣的錯(茶)但我是覺得小說是因為都是文字沒辦法,但一到了遊戲,畫面和文字是要搭配的……

  老實說以上說得很模糊,要懂真的很難,只能意會。因為看來看去有些地方是有矛盾點的,但我想要表達的是一種不要讓故事趨於老掉牙的大義思想,但也可以從各種彈性的選擇看出你的堅持……動不動就用殺死對方才能解決事件真的是覺得太蠢了……

  不過說實在話的,今天軒轅劍要是不是寫關於歷史的故事,而是像是勇者鬥惡龍或著伊蘇那樣有著奇幻的世界觀的話,那以那些理由去殺怪物和魔王就會非常合理,因為魔物的目的就是破壞,因此可以用很慷慨激昂的理由去殺了他們。尤其是當魔物大軍來襲,一個人誓死保衛家園,那種感覺會比敵軍也是人會來得更有感覺……雖然本人不是很喜歡完全把怪物當成不是人啦……但至少這樣的設定是較讓人接受的……

  其實軒轅劍要是能夠回到以前二代的感覺會比較好發揮……只是伍代我是覺得被玩壞掉了= =",因為還是刻意把他弄得很沉重……其實說教不是不可以,但說教最好不要一直說……而如果你硬要扯進有戰爭的歷史,建議是把焦點放在打戰鬥智會比較精彩……雖然這應該就不會是軒轅劍了……所以我才會希望軒轅劍脫離這種沉重手法……因此我個人認為軒參還算挺成功的,因為他主要是一個人的遊記……這種故事其實會比較容易把奇幻寫進去……軒貳其實也是如此,但軒參贏是贏在主角群特質描寫比較多……賽特和妮可刻劃得都不錯。

橫艾還挺可愛的,他應該會是我軒轅劍心目中排第二名的女主角。(第一名是妮可XD)

  因此我是覺得,要寫實,請寫實到底,將焦點放在鬥智或現實描寫。要奇幻,請奇幻到底,將焦點轉到遊記或廣大的世界觀……

  所以希望下次軒轅劍請以山海界的故事寫下去吧……那樣比較有發揮的空間。因為加入歷史往往會過於沉重……我怕再這樣下去軒轅劍會越來越半調子呀……冏rz……

  還有,那個要選大義還是蒼生的問題,真要說的話,我是覺得沒什麼比選擇當下來得重要……如果要看長遠的未來,必須要讓當下富足,然後才能走得更遠。不過也有另外一種價值觀就是了,就像是火鳳裡八奇中分的兩派,一派是要先亂後治(賈詡、郭嘉、荀彧),另一派則是要穩定劉家,要給世人一個典範,不要讓人有想篡位的想法(孔明、龐統)。不過不拿火鳳當比喻,以歷史來借鏡,就是英國的民主革命和法國的民主革命。前者是緩慢但穩定漸進的,後者是激烈且經過無數次犧牲的……(前者可參考光榮革命,後者可參考法國大革命七月革命二月革命……etc)

編劇者可能的構思

  雖然說了那麼多的抱怨,主要是因為個人認為對於老玩家來說,主劇情想要表達的東西是讓人覺得還不夠的。只是站在一般觀眾的想法,其實那樣是OK的,畢竟一般的玩家不會想太多,遊戲要能做到讓玩家的好奇心旺盛起來其實就夠了,也因此這也是我認為漢之雲值得推薦的原因。

  簡單來說,因為劇情安排成功,就算本身劇本沒有太大魅力,但他一步一步埋伏筆,會有讓玩家有一直想知道接下來是什麼的欲望,這也是之前所提到的"有秘密的女人最美麗"這點成功之處。

  其實我玩到後面,看到最後是因為愛情而導致漢之雲的故事,我是覺得還挺不錯的。雖然軒轅劍還是和以往一樣,都沒在感情上做較為細膩的敘述。可是有這種出發點算是不錯的,我個人認為他可能是先以"雲雨巫山"這個典故慢慢去發揮的。

  雖然雲雨巫山常被認為是男女之間的性愛,可是換個角度想不也是愛情嗎?因此才會是巫山四仙子為了愛情的故事呀……其實有一點浪漫,但我是覺得漢之雲的主軸讓這樣的初發點不浪漫了XD~

  而美女常常會被一些歷史故事視為妖怪猛獸,總是說美女會誤國。因此也有了只愛美人不愛江山的名詞出現,導致江山與美人常常被認為是相對的。看得出大毛獸應該認為為何談愛情還要被冠上誤國的稱頭,真的是很莫名其妙。所以他在編劇的時候可能是有這樣想過,才刻意以愛情為目的,但卻是大義蒼生為主軸……突顯那些只愛江山的人的矛盾。

  而為了進一步了解可能的構思,這裡整理一下巫山四仙子,而四仙子是昔日天女青兒所帶來的四的樂器:

  大姊琴兒:結局後面女主角橫艾稱他為琴兒,所以她代表的是琴這個樂器。愛上的是周瑜,也是最成功的一個,其他都以悲劇收場。

大姊琴兒

周瑜

  二姊?兒:這個在故事中沒有提到太多她的相關資料,頂多知道她有可能是參考洛神。不過編劇是不是要把她視為洛神我就不清楚了。主要是因為她愛上的是曹植,所以才有這可能的相關。但根據我在知識+找到的資料,洛神跟琴會比較有關係,但琴已經被大姊用去了,不知道是大毛獸沒考慮到還是他有參考別的文獻……

裝扮成二姊的笙兒

曹植

  三姊笙兒:也就是女主角橫艾,愛上的是孔明。雖然故事是後來愛上主角焉逢啦,但老實說我從他們身上看不到愛情,雖然故事中有敘述他們有他們的默契,但老實說我也看不太出來……畢竟這段過程其實應該要用事件來表示,而不是對話來帶過會比較好。她代表的是笙這個樂器。順帶一提,橫艾常掛在嘴邊的"有秘密的女人最美麗"很有可能是參考那時流行的話"不能說的秘密"這部電影的名稱。

笙兒和孔明

  四妹?兒:故事中只知道她是赤衣尊者,但好像沒看到她的名字,不過可以知道的是她都抱著琵琶,因此她很有可能是代表琵琶。她愛上的是曹叡。依照前面幾張圖片,大概只有她是比較特別的……比較沒有仙子的感覺……另外,他會召喚很多幻獸,只是在最後魔化時沒有召喚一堆幻獸的鏡頭畫面,真的很可惜。
  赤衣尊者

曹叡

魔化的赤衣尊者


  而在人物設計方面,我一直記得很清楚,負責這方面的趙誠瑞在研發日記有提到他想搞一個戰隊在裡面,雖然他是說失敗了,但我看得出來他還是放了進去。是的,就是銅雀六尊者……我想他最大的遺憾可能是他沒有把曹叡變成一向被視為隊長的紅色……還有女性隊員是粉紅色的設定吧(淚)。老實說,要是最後大魔王是他們幾個呼喚出來的銅雀木甲怪物……那一定很棒……所以在我眼中,不是銅雀六尊者,根本就是銅雀戰隊!

除去已經離開的白衣,有紫衣、赤衣、黃衣、烏衣、綠衣,以及沒有露過面的金衣和銀衣……看來不只六人……但我還是想要看他們的合照呀!!不知道DOMO小組有沒有打算出個惡搞版的銅雀戰隊……


神秘部隊不夠神秘

飛羽部隊

  在上市前的宣傳中可以知道這次的故事是圍繞在一個蜀國的神秘部隊,老實說,這個神秘部隊設計得很失敗,因為不夠神秘……就連到了吳國也很明目張膽地被人招待……

  其實我是覺得應該要把他設計地像火鳳的殘兵的……就算不要像他們是以暗殺為主的好了,至少也要低調一點呀……

  而且變成神秘部隊的話,其實到了劇情中期還可以變成接任務,那些任務是由上級列表,然後由玩家選擇,因為我想,既然是趙雲自己成立的部隊,總不能讓軍餉全都向蜀漢拿吧?畢竟報帳也得實報的……所以他們算是自立更生,因此去取得資源是很重要的……所以個人認為劇情中間用拿三武器當做休息的橋段,不如變成這樣……(雖然這樣一來遊戲成本又得提高了@@")

人物刻劃不夠細膩

  簡單來講,這一代的人物刻劃是比伍代進步了,可是卻還不夠。

  例如:

  1.尚章和耶亞希的情感完全無法從故事劇情中獲得,只是橫艾一個人把話帶過,就說尚章其實是喜歡耶亞希的,但在說這話之前,完全沒有任何讓讀者有聯想的蛛絲馬跡。

尚章

  2.前期的游兆感覺是加假的,其實他很有讓某些讀者喜歡的特質,但卻因為一次離開後就沒有太多下文了……後來他也死得也莫名其妙,莫名其妙的是主角竟然抱著他的屍體想著和彊梧的過去……


主角抱著游兆的屍體回想和彊梧的過去,冏rz

  3.飛之部在中後期的敘述也是草草了事,感覺這些隊伍好像不存在一般,至少要讓他們出現在帳營呀,在主線討論戰略時也得要他們出現呀……如果因為成本關係,那建議前面一開始介紹飛之部時,不要放在同一帳營介紹,可以日後遊戲後遇到……而且儘量給那些角色讓玩家有路人的感覺(其實是知道他的存在,但對他沒興趣的那一種感覺)……像商橫就很成功,但祝犁和昭陽從頭到尾都不夠路人……游兆就不用講了……本來一開始以為是主角群,哪知道後來變得跟路人一樣……

  簡單來說,就像聖魔大戰裡也有分好幾個部隊,但也不是每個部隊都會提到。意思就是,那些不關己的人物就不要描寫太多啦……如果要描寫,請給他們一個讓人印象深刻且完整的戲份……不要只是那種,我知道祝犁擅長搞木牛流馬,但他的劇情是什麼?不知道。我知道昭陽很喜歡端蒙,但為何喜歡?沒講;加上得知端蒙死了的情感也沒透露……這種角色不如變成路人算了……雖然之後有做一點彌補,但我覺得太遲啦……中間一大段完全沒有他的存在感,要在後面讓玩家突然對他有印象,太難啦!雖然這樣做會違反天干十傑這樣的一個頭銜,但建議如果沒能力搞那麼大,還是別太勉強一次下太多的人物設定……(如果要省略一些人的存在感,還有一種辦法,就是多種路線,像是伊蘇:始源的故事可以玩三個路線,也能彌補一些不足。雖然這個成本應該也會挺大的,但我覺得至少這企劃會比玩一個人但每個角色都要認識好寫。)

祝犁(上圖)和昭陽的著墨讓人覺得有一點雞肋

  4.彊梧對孔明的忠心不要只是單純地讓玩家有"你要殺孔明?我就跟你反目!"這樣感覺,必須要多方讓玩家了解彊梧對孔明的忠誠。雖然之後有提到彊梧的父親就是孔明救的,但他對孔明的這份情感,卻完全感受不到……只是感到單純地跟愚民一樣,死撐著支持某個候選人一樣……那一段可以在回憶之殿多敘述呀……喔,敘述不是只是用文字帶過,要圖要動畫……只有文字是不夠力的……就是因為這段只有一小句話帶過,所以我才認為不夠力……

彊梧V.S.焉逢

  5.隱藏角色完全和主線角色搭不上邊,這種設計老實說不好,要嘛就不要加入,要嘛就讓他們在主線參一腳……不然很難有共鳴感的……

司徒薔(上)、青冥(中)、馬棄(下)這三個隱藏角色比伍代一堆角色好的地方就在於著墨比較多

  6.徒維也是蠻可惜的一個角色,畢竟被操縱的人物其實都是有機會被玩家所喜歡的,結果製作者竟然以"隊伍需要補血的角色"而如此設計徒維(詳見畫冊),最後讓徒維只是草人的故事安排是會使對他有興趣的玩家失望的……雖然勉強算是一個危急中的好設計……但站在玩家的角度,這樣的設計不免讓人覺得相當可惜……

我還挺喜歡徒維的,之前孔明說天干十傑有他的內線,我想說是他會比較好玩……

  7.第二女主角耶亞希其實是失敗的設計,不只人物的3D建模很明顯地是出了問題(在畫冊中有提到被修改很多次,都沒達到趙誠瑞的要求),且個性設計上是不太成功的……個人認為是給的故事不夠多,所以才會這樣。其實老實說我個人認為他要天真可愛都沒有軒參女主角妮可來得成功……當然,我個人是認為,3D模型失敗也是可能的原因,我是覺得她有一點大隻(可能是臉太大),所以無法讓人有疼愛的感覺……還有不管是2D還是3D,他的繪圖風格明顯就和其他角色差很多……這樣也是不行的,老實說我覺得把馬棄加個長髮或許還比較吸引人……

身為第二女主角,外觀不討喜是不行的呀~~趙先生應該堅持到底的……

身為第二女主角,我還是覺得耶亞希很沒有份量Orz……難道是因為我單純地對她不來電的緣故!?

  8.端蒙這個角色刻劃地其實不太算差。但我就是覺得好像少了些什麼,大概是她和馬稷的相關回憶畫面吧……而且整個劇情中讓我覺得她很像那種只會一直叫要殺了孔明的潑婦……大概是我個人覺得恨意還是火影的佐助比較有感覺。要那種仇人是抱著很機掰的理由而殺了你相關的親人或至愛才會引起我覺得他會想殺人是很合理的感覺……簡單來講就是站在讀者和復仇者都覺得殺了仇人是理所當然的感覺……

最後她脫得讓我很莫名其妙呀~呀~

  而所有角色中,只有橫艾這個角色的刻劃是最成功的,以一句"有秘密的女人最美麗"貫徹到底,讓人覺得她很神秘地很有趣。

  其實會說角色刻劃不夠的原因在於漢之雲野心太大,但很明顯應該是成本不足以這樣搞大,所以才會變成這樣。這款遊戲的企劃應該是要是交給史克威爾艾尼克斯那種大公司的……因為人物實在是太多了,這樣下去雪球是會越滾越大的……如果你要這作品好,不被雪球搞砸,那就必須花下足夠的成本……

青冥是我很感興趣的一名角色,所以就算我覺得他不好用我還是偶而會把他放在前線的

  不過也不是說他的主故事太複雜,只是覺得他人物可以多牽扯,若是小成本製作,就專心於幾個角色的刻劃就夠了……畢竟那些角色都是我們操縱的,不刻劃也太奇怪了……

最後主角白頭髮配紅衣其實還蠻有感覺的……

企劃剖析

  這個部分是在剖析一個企劃他要實作這遊戲時,他"有可能"所考量的限制與思考。所以有資料統計、成本剖析、支線剖析、怪物分配量剖析。

資料統計

  以下統計只是記錄,老實說要依據這些資料來分析什麼我沒太大把握……所以就暫時只是存放資料。(P.S以下有些統計資料是根據攻略本去計算的)

  角色數量(單位—個):
  天干十傑(10)、第二女主角耶亞希(1)、隱藏人物(3)、諸葛亮(1)、司馬懿(1)、持國使(1)(由於是要考量美術圖設計數量,故和本尊獨立開來)、增長使(1)、多聞使(1)、廣目使(1)、張郃(1)、鄧芝(1)、姜維(1)、廖化(1)、李嚴(1)、費禕(1)、楊儀(1)、趙雲(1)、曹璿(1)、曹叡(1)、赤衣尊者(1)、白衣尊者(1)、黃衣尊者(1)、青衣尊者(1)、烏衣尊者(1)、金衣尊者(1)(由於劇情有提到,所以猜測有可能有在企劃時考量過)、銀衣尊者(1)(同上)、張皓(1)、曹植(1)、孫權(1)、孫尚香(1)、孫峻(1)、巫山女神(3)(除去橫艾)、周瑜(1)、怪物(206)共256個3D物一般物件,加上我憑印象的省略計算,小城平均8個人,大城平均15人,小城有5個,大城有3個所以再加上85個一共341個人物物件。

  主要角色還要2D圖畫,除去概念圖與被丟棄的圖稿,所以一共要11張2D圖。加上宣傳照與封面共3張。

  還有法術數量、物品個數。

  除去一堆重複的帳營,大地圖有2個、迷宮有57個。

  支線有53個。(老實說最好還是分類一下比較好,但目前懶得分析,就算了)

  工作人員名單(右邊的編號是方便統計人數用):

  監製:蔡明宏(1)、饒瑞鈞(2)

  製作人:呂志凱(3)

  編劇:吳欣叡(4)

  程式監督:吳東興(5)

  主程式:呂志凱

  介面程式:徐育良(6)

  戰鬥程式:林家弘(7)

  壺中世界程式:徐育良

  安裝前導程式:呂志凱

  領航員程式:蔡佳翰(8)、林坤蒼(9)

  企劃統籌:廖國秀(10)

  文編:黃秀娟(11)、邱思齊(12)、吳欣叡、蔡明宏

  戰鬥數值企劃:王昱人(13)

  美術統籌:羅國成(14)

  角色設定:趙誠瑞(15)、李長憲(16)、蔡于旋(17)

  角色貼圖:李長憲、關志英(18)、謝濘光(19)、楊志豪(20)、楊景棠(21)

  模型製作:林耀元(22)、張家銘(23)、張家瑋(24)、陳偉程(25)

  動態製作:林耀元、張家銘、張家瑋、許銘峰(26)、劉芳麗(27)、黃偉權(28)、何軍(29)

  場景規劃:羅國成、王昱人

  場景設定:楊志豪

  場景製作:王星文(30)、林宏儒(31)、鄭立暘(32)、謝濘光、邱妮君(33)、劉樹興(34)、奇原多媒體有限公司

  介面設計:關志英

  物品繪製:陳鵬文(35)、關志英

  單張圖繪製:楊志豪、李長憲、關志英、羅國成

  特效製作:許文泉(36)、王光昇(37)

  美術支援:王福生(38)、郭幸豔(39)、陳建民(40)、林俊傑(41)、周佳珊(42)、周宜汶(43)

  宣傳人物繪製:趙誠瑞、王福生

  動畫總監:胡富欽(44)

  動畫監製:陳正宇(45)

  動畫統籌:李偉程(46)

  動畫腳本:吳欣叡

  動畫分鏡:陳正宇、李偉程

  動畫導演:陳正宇、李偉程

  動畫剪接:陳正宇、李偉程

  動畫語音統籌:陳正宇

  動畫語音規劃執行:李偉程

  動畫語音導演:呂志凱、吳欣叡、陳正宇、李偉程

  配樂製作:吳欣叡、曾志豪(47)

  音效製作:楊文祥(48)

  說明書編寫:呂志凱

  說明書美編:游雅玲(49)

  動畫製作單位:亞瑪影像科技(這個我就不清楚是哪部分有委託這家公司,目前可以確定的是配音員應該是這家公司幫忙找來的……配音員有六個……其他還有一些雜七雜八的有10個人,不確定是不是這家公司裡的人還是DOMO小組,我是覺得應該是這家公司裡的人)

這就是DOMO小組工作室呀

成本計算

  既然前面一直提到成本,那現在就來說說漢之雲可能的成本吧……

  根據大毛獸的研發日記,漢之雲是從2006年11月提案的,而它是在2007年12月發行,所以製作時間差不多是一年。

  最 基本的人事費用:小組成員數x月薪x開發時間,根據電腦玩家191期的專欄的算法,剛剛那樣的公式還要X3,因為要加 上宣傳、硬體維修、包裝……的雜七雜八費用,但我看了一下成員名單,感覺好像有些有算進去,加上那個乘3其實是算線上遊戲的,算單機應該不太準,所以不打算乘了。所以以一個人大約一個月三萬、這次製作小組大約50個人來算的話,就是 50x12X30000=18,000,000也就是一千八百萬。

  不過還有聲優費……那些費用完全無法得知,只從這裡知道日本聲優演一個半小時一集的費用是18,000日幣演出費,換算台幣大約除以5(其實應該是3.5-4左右)是3600台幣。

  雖然台灣配音員環境比較差,感覺拿的錢應該要比日本低,但這3600感覺好像挺低的,而我換算時也沒算得很精準,因此一個人就算3600好了。

  而有六名配音員,所以多花3600*6=21,600,不過還要加上外包的錢說……不知道要多少,這些加下去感覺應該不會到百萬,所以我還是算成本大概是一千八百萬好了……(這一段有截取並修改我在巴哈的一篇文章)

支線是有情感的,但獎勵實在是很差

  其實個人認為漢之雲的支線是歷代以來最成功的。為什麼成功呢?我還記得以前在玩軒參的時候,總是會回去某些城鎮,希望有不一樣的支線出現,只是都不太可能會有……在軒伍以前,支線都是一直線的,一個城鎮一個,頂多就是這個城鎮需要另一個城鎮的某個npc。

  軒伍算是幫漢之雲鋪路吧,因為軒伍的支線設計並不是之前所講的那種,他是會依據遊戲劇情,而有所變化的,因為一個城鎮不會只到一次,而每一次會因為主劇情的不同而讓對話也不太一樣。在漢之雲中就是如此,其中處理最好的就是漢中驛站的年輕人與歌妓,從遊戲剛開始的任務知道年輕人對那位歌妓的愛慕,但因為膽小而不敢說出口,到後來對話也慢慢得不同,後來也開始變成了支線故事,雖然沒有真的在一起,但也成了好朋友……這種感覺就像看到一個人的成長,是很棒的……

就是這個年輕人讓我覺得他成長了!雖然他只是個不起眼的NPC!

  也因為地方會一直來來往往,所以會對當地的某個npc產生了情感,而不再像以前rpg直線型的遊戲方式,東西一用過就把它捨棄的感覺。只是可惜的地方在於獎勵似乎都不太吸引人……像是有一個要跑很遠的路的支線,給的東西也不怎麼樣,真的是不符合經濟效益……

  像是交換物品的支線任務,都是換一些補品,老實說換補品這樣的設計要看玩家的需求量大不大。需求量大的代表很難得,或著戰鬥中真的很需要……可是給的那些東西都很好取得,且戰鬥中很少用到……因此有些要以物易物或多重任務的要給的物品最好是有讓玩家嘗到甜頭,不然我拿我辛辛苦苦抓到的怪物跟你換又或著是我千辛萬苦跑很遠來解這趟任務,結果竟然都是一些不值得的東西真的是很幹。就目前漢之雲來說,我是覺得那些任務要給的物品應該是要法寶或強的護駕會比較好……

這個小香菇之後靠著我們一直給木頭,變成了怪物還想把我們吃掉……老實說我一開始是覺得這個很有可能成為像徵性的任務(因為切換鏡頭時都會有那個小香菇在跳來跳去,那時候我連想到的是FF的陸行鳥……加上那隻小香菇每次都在打大魔王前出現……),但給的東西實在不怎麼樣,後來竟然也沒後續。

怪物分配量明顯不足、最後迷宮竟然要跑三次
  
  不知道是不是因為這次企劃沒有鮑宏修,取而代之的是廖國秀,而這傢伙感覺蠻生面孔的,從歷屆軒轅劍工作人員上看來可能是第一次擔任這種大任。不知道他有沒有在其他小組擔任過。而王昱人應該是軒伍新進的新手(他的研發日誌,不過這工作感覺不太像他規劃的)。不曉得是不是換人的關係,所以怪物的分配量沒辦法掌握好……

  因為在以往軒轅劍或其他遊戲當中,很強的小怪物都是在最後的迷宮出現的。但漢之雲最強的幾個小怪物不是在最後的迷宮,而是在一個很難被發現,且跟主線無關,也不會因為什麼劇情而引進的迷宮……

  從這個結果推斷,可能是怪物分配不當,等級差距過大,導致後來只好將那些怪物放在別處。

  當然,也有可能是劇情太短,只好這樣做。不過,就算是劇情太短,這種情形還真的是不常見。可能是考慮難易度的問題,但我還是覺得有可能是怪物分配量不當所造成的……

  而為何說劇情太短?因為最後的地圖跑了三次呀……在後面對決最後魔王時也沒預兆,在打大魔王前都不給人準備去解決其他事件或去練點功的= ="

這個地圖在後面竟然要跑三次,我只能三次看著明月無言了Orz……

系統剖析

  這代有煉妖壺系統、緞冶系統,所以可以好好的談一談,另外也會提到戰鬥系統和一些小遊戲。


回來的煉妖壺系統和鍛冶系統

  基本上煉妖系統沒啥變化,我是覺得還可以加入新要素進入合成……雖然目前想不到。

  還有這次收來的妖怪都會出現在壺中世界跑來跑去,這點還挺不錯的,有以前我想和收進來的怪物說話的一種感覺(雖然還是差恨多,但我說的是把一種感覺)。


  而鍛冶系統是讓我用最多的系統吧,這讓我體會到什麼是玩線上遊戲衝武器的感覺……總之就像是抽卡包一樣……個人是認為這個系統加得不錯……


枯燥乏味的戰鬥系統

  雖然上一代稱戰鬥系統是特色,加了情緒和氣勢系統進去。但問題玩起來還是沒啥太大的感覺……應該說那些東西好像不會成為關鍵性的一擊,當然,還有就是讓玩家覺得沒有氣勢系統和情緒好像也沒關係。加上老舊式的RPG玩法本就很無趣。基本上那些遊戲之所以會吸引人,好玩的地方在於特效,但軒伍的特效和漢之雲一樣,都只是像灑灰塵看小動畫而已,沒有什麼太吸引人的鏡頭。好比蒼之濤的木甲獸動畫,還有軒參火靈降臨的法術,簡單來說,就是缺少了一些能夠振憾無趣遊戲玩法的法術或召喚獸之類的東西……

  但我是覺得用這種手法玩家到最後還是會膩,建議還是改改戰鬥型態會更好,但改不了的話就是要加強那種手法了……

  不然,戰鬥只是為了難,有一點無趣,也會讓玩家根本不想重玩……(嗯,這代很少有一次把對方小兵都幹掉的感覺,實在是讓我不太想重玩……)

  但這代的戰鬥中還是有好玩的事發生,只要隊伍中有特別人物就會發動特別的對話。而和怪物對讓我想起當初玩楓之舞的時候……

戰鬥時要某的特定人物在前排才會引起對話

馬棄真的很好用

希望未來小遊戲能更多
  
  因為傳統RPG的戰鬥方式真的是很難改得有趣,所以要是能的話有時候不一定要打戰,可以加入別的要素提高遊戲的耐玩度。

  像這代就有引誘敵人和不讓敵人發現的小遊戲,我是覺得這兩個構思還挺不錯的。下次來個賽車吧!?

哈哈哈!來追我呀!

外觀剖析


  這裡指的就是美工的剖析、配音建議。簡單來講就是一個遊戲的外包裝。

美工明顯進步,但還有進步的空間

  和伍代相比,在對話過程中臉部動畫明顯自然很多,服裝設計也很華麗,這次有請到趙誠瑞來擔任角色設計算是挺成功的。而且,這代還加入了3D水墨化,也代表著美工人員的技術也提升了……雖然做這個是不是很難我不清楚,但至少和以往只會在背景上貼2D材質的水墨畫來說是進步很多……只可惜美中不足的是3D水墨化只出現在片頭動畫、戰鬥場景與壺中世界。我是覺得他還有發揮的空間……比如放在大地圖。或著乾脆從頭到尾都是3D水墨畫……

雖然有些人物的表情有一點死,但已經算是水準之上的好動畫了……
  
  但是呢,其他動畫還是頗為粗糙的,我是覺得四周圍的士兵怪怪的……這個怪我說不出口,就是覺得這樣有一點不自然……大概軒伍的動畫還是沒有改進……希望將來自己多觀察一點人物動畫,或許就能看出到底哪邊出問題了……

除了片頭外,動畫還是頗為粗糙的……

  不過還是有一些明顯的問題,像是主角拿長戟竟然拿那麼低的位置……

喂~朝雲,你拿那麼低的位置不會不好拿嗎Orz

  白衣尊者的劍光是很帥……但你看到他的形成過程就很冏……雖然是用捲起來的紙還是衣服就可以傷人感覺是很特別……但視覺上真的很怪……看過場動畫更明顯,有一點像拿棒棒腿……


配音沒有成功詮釋各個角色

  這標題不代表說是台灣配音不好,而是他配音的規劃位置太過於集中後段,導致後來聽到,沒有那種這個角色就是這個聲音的熟悉感。配音的規劃應該要平均分配,要是能的話在遊戲中動畫時出現(就是還是遊戲畫面看一堆對話框的時候),這樣一來會對於該角色原來就是這個聲音會慢慢地習慣,也讓那個角色活了起來。我想這才是配音最大的目的呀……讓角色活起來……

更新檔

  結果後來竟然還有更新檔,而且要重玩才能玩到新的支線……雖然和軒伍相比是比較不排斥重玩啦,但戰鬥過程和跑迷宮這種較為無趣的地方太多真的是有點讓人提不起勁就是了……

  真糟糕,以上好像太多抱怨了,儘管是有說優點,但我想大概都被口水掩概了。其實應該算是我愛之深責之切的心態吧……希望軒轅劍有朝一日成達到FF那樣的境界……

唯美的女主角拿著狼牙棒的感覺很微妙呀……

其它筆記

  這裡是放了當時記錄下來,但沒在上面被我提到的一些想法。這些都是當時在玩遊戲時想的。

伙伴的加入不該那麼勉強(採取比武招親還比較合理)
如果途中真的因為該人物個性活潑但在其間無劇情
後面突然講了會很突杌...看夷娃後面截圖,主角說夷娃活潑,讓過程中有歡樂,但玩家無法感受得出來....這不如不要說,或不必加入該角色..
找寶物是一個不錯的休息
但是……如果不要像主線那樣一個一個走
有種接公會任務會比較好
這樣也比較像秘密部隊(p.s飛羽一點都不像秘密部隊Orz……)
橫艾可能成為繼妮可之後我喜歡的女主角!?
逃脫找物品一定會有大魔王的迷思
找東西可以像某些遊戲的任務公會!?任務制……這樣才像秘密部隊呀……
有一些情感沒有徵兆...如同前面講的夷娃很活潑
不要把一些人完全當路人呀Orz……
如果是龐大秘密部隊
他的地下室要大到像一個世界……
內容如果要闡述大義,不要只是兩個人的爭執,因為沒有誰對誰錯,建議可以學火鳳燎原有一話(孔明睡了)的表現方式,淡而有力。
漢之雲的優點是每個小地方的npc都會重複遇到,每個階段有不同的煩惱,讓人覺得特別留下印象,有一點像軒參煉妖壺一樣,不過這很有可能只能針對rpg老手,因為有些玩家可能會懶得看那些小地方……
戰鬥完後主角朝的方向不能改變……
迷宮一定要有怪物的迷思
其實敵人在講解時不一定要說太白,可以騙人(指的就是黃衣尊者在回憶之殿那裡)
戰鬥太老調,但不是沒有辦法補強,如果是一般的老調rpg戰鬥,是少了些讓人記住的招式的,像我一直記得FF8的召喚獸還有軒參賽特的火神降臨……
3D走路不正常
昭陽看到端蒙的時候要以為自己死了才對……因為他可能不知道端蒙沒死……
朋友離開前要記得還裝備呀!!
沒有乘龍念法
配音要配到好的地方……(不是說聲優不好)
記得把漢之雲可能得成本算一下
照圖可否用小一點,還有可以照動畫的圖...
我照了七百張圖就用了1.6G了……

贈詩一首

  由於當初玩完後有一種莫名的感動,所以就想把這首詩的最後一句補完奉上來,算是感謝漢之雲的製作……雖然內心還是有點覺得美中不足的地方……但還是請繼續努力。

楓天蒼漢
落紛紛干戈,
地悠悠斷殘
海茫茫湧起,
魂裊裊現朝