第四章 系統實作
4.2 功能建置
在 3D Game Studio 的功能中把人物移動的動作用框架播放方式連續呈現。
也就是,我們先利用 3D 軟體編輯製造出多種動感的 3D 模型人物,利用連續播 放框架技術做出人物移動的感覺。下面我們展示幾種人物的姿勢動作,從圖 4.12 來看,一個完整的行走過程是從 a->b->c->d。為了更深一層去了解,最後我們 放上與這些功能有關的相關演算法。
a b
c d 圖 4.12 人物行走 3D 姿態
如圖 4.13 來看,一個完整的行走過程是從 a->b->c->d。
a b
c d 圖 4.13 人物跳躍 3D 姿態
圖 4.14 人物站立 3D 姿態 圖 4.15 人物跑步 3D 姿態
function actor_anim_transition(str_anim_target) //狀態轉換
anim_trans_cycle = MY._MOVEMODE; //狀態變數指到動作轉換循環變數 MY._MOVEMODE = _MODE_TRANSITION; //轉換變數指到狀態變數
while(MY._ANIMDIST < 4)
{ //這部分說明連續動作的變換
MY.frame = int(MY.frame) + (MY._ANIMDIST / 4.0);
MY._ANIMDIST += TIME;
wait(1);
2.環境建設
虛擬校園環境的安排是參照逢甲大學的實際環境去做規劃。以圖 4.16 逢 甲大學校園分佈圖為準,針對每一棟大樓和校園內部環境做路徑規劃的設計。
圖 4.17 和圖 4.18 是本專題中用來設計校園路徑的設計圖。
圖 4.16 逢甲大學 校園分佈圖
圖 4.17 校園路徑設計圖 側面
圖 4.18 校園路徑設計圖 俯視
3.路徑控制
﹝1﹞自由模式和自動導覽
在我們的系統之中,一開始可選擇自由移動或是自動導覽, 當主角在自由 模式下行動時,使用者可以用鍵盤或是滑鼠來操控在 3D 校園裡任意走動。如果 選擇自動導覽模式,則選好目的地後,系統將會自動帶到目的地,並且人物可以 在任意時間內,轉換兩種模式(按畫面上的紅色大圓球),如圖 4.19 右下方的大 圓球。
圖 4.19 校園導覽系統 執行畫面
function free_to_auto() //自由轉自動模式 { update_v=0;
fcu_auto_time=1;
choose_place(); //按下控制鍵後跳離到目的地選擇函式 } 演算法 4.2 路徑處理 導覽模式切換
﹝2﹞路徑偵測和規劃
穿透式物件,更貼切的說法是此元件像是一個路由站---紀錄著通往各地的路 徑。當主角走到此時,此元件便會通知主角下一個路徑的位置,這樣提升了很多 規劃路徑的彈性。
第三次改良---在本專題中,逢甲校園內共設定有 20 個資訊站,作為判斷路 徑用,若每個資訊站若按照原來的方法設計,則必須紀錄非常大量的資訊,耗時 浩工不符合效益,且在以後的程式碼維護上變成是一種大問題。這些問題來自 於,如果要在增加一個資訊站,我們則必須去針對每個資訊站做大幅度的修改。
於是我們最後在資訊站的實作上改良成,資訊站只紀錄到某站的路徑一直走到最 接近目的地的資訊站時才告知直接通往某大樓的路徑,這樣一來在規劃路徑上就 會方便許多並且在選擇目的地時,只要讓系統知道最接近的目的站和大樓名稱兩 個條件就能無誤行走到目的地。
另外之後在程式碼的維護上也很快速,因為整個路經偵測系統與目的地大樓 是分開的,要新增一條新路徑和目的地都變的很容易。
最後我們放上與這些功能有關的相關演算法。
路徑設定 圖 4.21 資訊站 資訊站
function scan_event //路徑資訊區域通知 {
str_for_entname(info_station_name,me);
me=player;
if (EVENT_TYPE == event_scan) {
if (str_cmpi(info_station_name,"F")==1) // F 站 {
F_station_main(); // F 站主程式 }
function F_station_main() {
find_next_at_F_station(); // F 站次程式 }
演算法 4.3 路徑處理 資訊站處理
function find_next_at_F_station() {
me=player;
if (str_cmpi(player_info_place_building,"iecs")==1) //若這是最進站 則通知直達路徑
{
ent_path("to_iecs");
ent_waypoint(my._TARGET_X,1);
return;
ent_waypoint(my._TARGET_X,1);
ent_waypoint(my._TARGET_X,1);
}
// 自動導覽主程式
// 說明:角色隨一路徑行走 並且能偵測資訊站 action patrol_path
{
actor_init();
my._FORCE=5;
if (result == 0) { my._MOVEMODE = 0; } // 找不到路徑 則停止 while (my._MOVEMODE > 0)
演算法 4.3 路徑處理 資訊站處理(續)
{
temp.x = MY._TARGET_X - MY.X;
temp.y = MY._TARGET_Y - MY.Y;
temp.z = 0;
result = vec_to_angle(my_angle,temp);
force = MY._FORCE; //速度
result=scan_entity (player.x, temp); } //掃描所在區域,掃到的話會自動通知新路徑
// 已經到達目的地
if (result==0) {break;}
演算法 4.3 路徑處理 資訊站處理(續)
} } }
if (fcu_move_mode==1) //切換成自由模式~
{ break;}
圖 4.22 第一人稱視角圖
圖 4.23 第三人稱視角圖
圖 4.24 固定視角圖
圖 4.25 側面視角圖
function cycle_person_view() //循環切換視角
CAMERA.DIAMETER = 0;
CAMERA.GENIUS = player;
CAMERA.X = player.X; //像機位置處理 CAMERA.Y = player.Y;
CAMERA.Z = player.Z + player.MIN_Z;
CAMERA.PAN = player.PAN;
CAMERA.TILT = player.TILT + head_angle.TILT;
CAMERA.ROLL = player.ROLL;
if(my_height < 5) //人物水平高度在 5 以下 {
headwave = sin(player_dist*walk_rate); //擺頭動作
if((player._MOVEMODE == 0)|| (player._MOVEMODE == _MODE_WALKING)) { //狀態數值為 0 的行走
if(((headwave > 0) && (walkwave <= 0))|| ((headwave <= 0) && (walkwave
> 0)))
{
play_sound(thud,30); //走路聲音 } 演算法 4.5 視角切換 第一人稱視角處理
walkwave = headwave;
headwave = walk_ampl*(abs(headwave)-0.5); //擺頭動作 } if(player.__BOB == ON) { CAMERA.Z += headwave; }
person_3rd = 0; }} CAMERA.genius = player;
CAMERA.pan += 0.2 * ang(player.pan-CAMERA.pan);
if ( (player._MOVEMODE == _MODE_PLANE) ||(player._MOVEMODE == _MODE_CHOPPER)) {
CAMERA.tilt += 0.2 * ang(player.tilt-CAMERA.tilt); } else
{
CAMERA.TILT = head_angle.TILT;
if((person_3rd < 1) && (camera_dist.Z == 0)) {
演算法 4.6 視角切換 第三人稱視角處理
camera_dist.Z = -(player.MAX_Z-player.MIN_Z)*eye_height_up;} } vec_set(temp,temp_cdist);
CAMERA.X += 0.3*(player.X - temp.X - CAMERA.X); //像機處理 CAMERA.Y += 0.3*(player.Y - temp.Y - CAMERA.Y);
CAMERA.Z += 0.3*(player.Z - temp.Z - CAMERA.Z);
temp = ent_content(NULL,CAMERA.X);
if((temp == CONTENT_SOLID) && (camera_solidpass == 0)) { //畫面變換
temp_cdist.X *= 0.7;
temp_cdist.Y *= 0.7;
temp_cdist.Z *= 0.7; }
else
{ //畫面變換
temp_cdist.X += 0.2*(player.MAX_X + camera_dist.X - temp_cdist.X);
temp_cdist.Y += 0.2*(player.MAX_Y + camera_dist.Y - temp_cdist.Y);
temp_cdist.Z += 0.2*(player.MAX_Z + camera_dist.Z - temp_cdist.Z); } if (temp == CONTENT_PASSABLE)
{
if (FOG_COLOR != _FOG_UNDERWATER) //打霧功能 (未使用) {
current_fog_index = FOG_COLOR;
演算法 4.6 視角切換 第三人稱視角處理 (續) FOG_COLOR = _FOG_UNDERWATER; } } else
{
if (FOG_COLOR == _FOG_UNDERWATER) {
CAMERA.GENIUS = PLAYER;
CAMERA.X = PLAYER.X + (orbit_camera_dist * SIN(orbit_camera_pan));
CAMERA.Y = PLAYER.Y + (orbit_camera_dist * COS(orbit_camera_pan));
CAMERA.Z = PLAYER.Z + orbit_camera_zOff;
TOUCH NULL,CAMERA.POS;
IF (IN_PASSABLE)
camera.TILT = temp.TILT; }
演算法 4.7 視角切換 隨身視角處理 (續) function move_view_chase() //移動追逐視角
{ if ((_camera == 0) && (player != NULL)) { CAMERA.DIAMETER = 0;
CAMERA.genius = player;
vec_diff(temp,nullvector,chase_camera_dist);
vec_to_angle(chase_camera_ang,temp);
chase_camera_ang.roll = 0;
vec_set(camera.x,chase_camera_dist);
vec_rotate(camera.x,player.pan);
vec_add(camera.x,player.x);
vec_set(camera.pan,player.pan);
ang_rotate(camera.pan,chase_camera_ang); }}
演算法 4.8 視角切換 追逐視角處理
function fixed_views() //固定視角處理 {if (fixed_cam == null) { return; }
if (update_v==0) { return; } vec_set (camera.x, fixed_cam.x);
vec_set (temp, player.x);
vec_sub(temp, camera.x);
vec_to_angle(camera.pan, temp);}
演算法 4.9 視角切換 固定視角處理
5.其他功能
在本專題中還運用到了按鈕介面以及事件觸發元件,如圖 4.26 為事件觸發 元件。圖 4.29 是 GUI 按鈕介面,設計控制按鈕方便操控系統。事件觸發元件 (event_entity)提供固定式攝影機或是動態事件觸發,跟環境有關,如圖 4.27 和圖 4.28。事件觸發元件先設定好處發時要做的事情,然後在主角行進中觸發 時就一併啟動該元件的事件,譬如:如圖。最後我們放上與這些功能有關的相關 演算法。
圖 4.26 事件觸發元件
圖 4.27 固定式攝影機一
圖 4.28 固定式攝影機二
action touch_event_1 //event_entity 物件驅動設定 {
my.ENABLE_scan = ON;
my.EVENT = what_event_1;
}
function what_event_1() //執行的 EVENT {
update_v=1;
fixed_cam=ptr_for_name ("cam_1");
fixed_views();
}
action patrol_path {
result = content(my.x);
if (result == CONTENT_PASSABLE) //通過透明區塊 {
圖 4.29 GUI 按鈕介面 Panel test_panel
{
pos_X = 20; pos_y = 20; //面板位置設定 mouse_map = test_b;
bmap = main_intro; //面板圖示
flags = REFRESH,d3d,transparent; //決定是否一開始就出現 on_click = chengemap ; //擊發時的動作 }
function chengemap()
{ test_panel.bmap= test_b ; //圖示變換 }
演算法 4.11 其他功能 按鈕元件設計
function begin_title() //開始的畫面 {
set system_title_panel.visible,on; //面板設定 set begin_panel.visible,on;
set main_intro_panel.visible,on;
system_title_panel.alpha = 0;
begin_panel.alpha = 0;
main_intro_panel.alpha = 0;
while (main_intro_panel.alpha < 100) {
system_title_panel.alpha+= 2*time; //設定延遲時間 begin_panel.alpha+= 5*time;
main_intro_panel.alpha += 2*time;
wait(1);
} }
演算法 4.12 其他功能 畫面秀出延遲函式
function text() {
set test_panel.visible,on; //面板設定 set ask_auto_panel.visible,on;
test_panel.transparent = ON;
test_panel.alpha = 0;
while (test_panel.alpha < 100) {
test_panel.alpha += 2*time; //延遲時間 wait(1);
}
wait(1000);
test_panel.alpha = 0;
set test_panel.visible,off;
wait(1);
}
on_s begin_title; //點擊 S 控制鈕後的動作 on_f favor_choose; //點擊 F 控制鈕後的動作 ACTION wall_touch {
SET MY.ENABLE_IMPACT, ON;
SET MY.EVENT text; }
演算法 4.13 其他功能 按鈕觸發功能
4.3 流程設計