链表应用

#include "stdio.h"  
#include "stdlib.h"
#include "string.h"
#include "ctype.h"
#define M 50 
typedef struct
{
   char name[20];
   char
units[30]; 
   char
tele[10]; 
}ADDRESS;

int enter(ADDRESS t[]);
void list(ADDRESS t[],int n);
void search(ADDRESS t[],int n);
int delete(ADDRESS t[],int n);
int  add(ADDRESS t[],int n);
void save(ADDRESS t[],int n);
int load(ADDRESS t[]); 
void display(ADDRESS t[]);
void sort(ADDRESS t[],int n);
void qseek(ADDRESS t[],int n);
void copy(); 
void print(ADDRESS temp);
int find(ADDRESS t[],int n,char *s) ;
int menu_select(); 

main()
{
   int i;
   ADDRESS
adr[M]; 
   int
length; 
  
clrscr(); 
   for(;;)
   {
     
switch(menu_select())  
     
{
    
case 0:length=enter(adr);break;
    
case 1:list(adr,length);break;
    
case 2:search(adr,length);break;
    
case 3:length=delete(adr,length);break;
    
case 4:length=add(adr,length); 
break;  
    
case 5:save(adr,length);break;
    
case 6:length=load(adr); break;
    
case 7:display(adr);break; 
    
case 8:sort(adr,length);break;
    
case 9:qseek(adr,length);break;
    
case 10:copy();break;
    
case 11:exit(0);
     
}
   }
}

menu_select()
{
   char s[80];
   int c;
   gotoxy(1,25);
   printf("press any key enter
menu......\n");
   getch();
   clrscr();
   gotoxy(1,1);
  
printf("********************MENU*********************\n\n");
  
printf("    
0. Enter record\n");
  
printf("    
1. List the file\n");
  
printf("    
2. Search record on name\n");
  
printf("    
3. Delete a record\n");
  
printf("    
4. add record \n");
  
printf("    
5. Save the file\n");
  
printf("    
6. Load the file\n");
  
printf("    
7. display record on order\n");
  
printf("        
8. sort to make new file\n");
  
printf("        
9. Quick seek record\n");
  
printf("    
10. copy the file to new file\n");
  
printf("        
11. Quit\n");
  
printf("***********************************************\n");
   do{
     
printf("\n    
Enter you choice(0~11):");
     
scanf("%s",s);
     
c=atoi(s);
  
}while(c<0||c>11);
   return c;
}

int  enter(ADDRESS t[])
{
   int i,n;
   char *s;
   clrscr();
   printf("\nplease input num
\n");
  
scanf("%d",&n);
   printf("please input record
\n");
  
printf("name            
unit                    
telephone\n");
  
printf("------------------------------------------------\n");
  
for(i=0;i<n;i++)
   {
     
scanf("%s%s%s",t[i].name,t[i].units,t[i].tele); 

     
printf("----------------------------------------------\n");
   }
   return
n; 
}

void list(ADDRESS t[],int n)
{
   int i;
   clrscr();
  
printf("\n\n*******************ADDRESS******************\n");
  
printf("name              
unit                    
telephone\n");
  
printf("------------------------------------------------\n");
  
for(i=0;i<n;i++)
  
printf("%-20s%-30s%-10s\n",t[i].name,t[i].units,t[i].tele);
  
if((i+1)%10==0)  
   {
     
printf("Press any key continue...\n");
     
getch(); 
   }
  
printf("************************end*******************\n");
}

void search(ADDRESS t[],int n)
{
   char
s[20];  
   int
i;  
  
clrscr();  
   printf("please search
name\n");
   scanf("%s",s);
   i=find(t,n,s);
  
if(i>n-1) 
     
printf("not found\n");
   else
     
print(t[i]); 
}

void print(ADDRESS temp)
{
   clrscr();
  
printf("\n\n********************************************\n");
  
printf("name               
unit                     
telephone\n");
  
printf("------------------------------------------------\n");
  
printf("%-20s%-30s%-10s\n",temp.name,temp.units,temp.tele);
  
printf("**********************end***********************\n");
}

int find(ADDRESS t[],int n,char *s)
{
   int i;
  
for(i=0;i<n;i++)
   {
     
if(strcmp(s,t[i].name)==0) 
     
return i;  
   }
   return
i; 
}

int delete(ADDRESS t[],int n)
{
   char
s[20]; 
   int ch=0;
   int i,j;
   printf("please deleted
name\n");
   scanf("%s",s);
   i=find(t,n,s);
  
if(i>n-1) 
     
printf("no found not deleted\n");
   else
   {
     
print(t[i]);
     
printf("Are you sure delete it(1/0)\n"); 
     
scanf("%d",&ch); 
     
if(ch==1) 
     
{
    
for(j=i+1;j<n;j++) 
    
{
       
strcpy(t[j-1].name,t[j].name);
       
strcpy(t[j-1].units,t[j].units);
       
strcpy(t[j-1].tele,t[j].tele);
    
}
    
n--; 
     
}
   }
   return
n; 
}

int add(ADDRESS t[],int n)
{
   ADDRESS
temp; 
   int i,j;
   char s[20];
   printf("please input
record\n");
  
printf("************************************************\n");
  
printf("name               
unit                     
telephone\n");
  
printf("--------------------------------------------------\n");

  
scanf("%s%s%s",temp.name,temp.units,temp.tele);
  
printf("------------------------------------------------\n");
   printf("please input locate
name \n");
   scanf("%s",s);
  
i=find(t,n,s); 
  
for(j=n-1;j>=i;j--)  

   {
     
strcpy(t[j+1].name,t[j].name);
     
strcpy(t[j+1].units,t[j].units);
     
strcpy(t[j+1].tele,t[j].tele);
   }
  
strcpy(t[i].name,temp.name);
  
strcpy(t[i].units,temp.units);
  
strcpy(t[i].tele,temp.tele);
  
n++;  
   return n;
}

void save(ADDRESS t[],int n)
{
   int i;
   FILE
*fp; 
  
if((fp=fopen("record.txt","wb"))==NULL) 
   {
     
printf("can not open file\n");
     
exit(1); 
   }
   printf("\nSaving
file\n");
  
fprintf(fp,"%d",n); 
  
fprintf(fp,"\r\n"); 
  
for(i=0;i<n;i++)
   {
     
fprintf(fp,"%-20s%-30s%-10s",t[i].name,t[i].units,t[i].tele);
     
fprintf(fp,"\r\n");
   }
   fclose(fp);
   printf("****save
success***\n");
}

int load(ADDRESS t[])
{
   int i,n;
   FILE *fp;
  
if((fp=fopen("record.txt","rb"))==NULL)
   {
     
printf("can not open file\n"); 
     
exit(1); 
   }
  
fscanf(fp,"%d",&n);
  
for(i=0;i<n;i++)
     
fscanf(fp,"%20s%30s%10s",t[i].name,t[i].units,t[i].tele);
  
fclose(fp); 
   printf("You have success read
data from file!!!\n");
   return n;
}

void display(ADDRESS t[])
{
   int id,n;
   FILE *fp;
  
if((fp=fopen("record.txt","rb"))==NULL)
   {
     
printf("can not open file\n");
     
exit(1); 
   }
   printf("Enter order
number...\n");
  
scanf("%d",&id); 
  
fscanf(fp,"%d",&n);
  
if(id>=0&&id<n)

   {
     
fseek(fp,(id-1)*sizeof(ADDRESS),1);
     
print(t[id]);
     
printf("\r\n");
   }
   else
     
printf("no %d number record!!!\n ",id);
  
fclose(fp); 
}

void sort(ADDRESS t[],int n)
{
   int i,j,flag;
   ADDRESS temp;
  
for(i=0;i<n;i++)
   {
     
flag=0; 
     
for(j=0;j<n-1;j++)
     
if((strcmp(t[j].name,t[j+1].name))>0)
     
{
    
flag=1;
    
strcpy(temp.name,t[j].name); 
    
strcpy(temp.units,t[j].units);
    
strcpy(temp.tele,t[j].tele);
    
strcpy(t[j].name,t[j+1].name);
    
strcpy(t[j].units,t[j+1].units);
    
strcpy(t[j].tele,t[j+1].tele);
    
strcpy(t[j+1].name,temp.name);
    
strcpy(t[j+1].units,temp.units);
    
strcpy(t[j+1].tele,temp.tele);
     
}
     
if(flag==0)break; 
   }
   printf("sort
sucess!!!\n");
}

void qseek(ADDRESS t[],int n)
{
   char s[20];
   int l,r,m;
  
printf("\nPlease  sort before qseek!\n");
   printf("please
enter  name for qseek\n");
   scanf("%s",s);
  
l=0;r=n-1; 
  
while(l<=r)
   {
     
m=(l+r)/2;
     
if(strcmp(t[m].name,s)==0)
     
{
    
print(t[m]);
    
return ;
     
}
     
if(strcmp(t[m].name,s)<0) 
    
l=m+1; 
     
else
    
r=m-1;
   }
  
if(l>r)  
     
printf("not found\n");
}

void copy()
{
   char outfile[20];
   int i,n;
   ADDRESS
temp[M]; 
   FILE *sfp,*tfp;
   clrscr();
  
if((sfp=fopen("record.txt","rb"))==NULL)
   {
     
printf("can not open file\n");
     
exit(1);
   }
   printf("Enter outfile name,for
example c:\\f1\\te.txt:\n");
   scanf("%s",outfile);
  
if((tfp=fopen(outfile,"wb"))==NULL)
   {
     
printf("can not open file\n");
     
exit(1);
   }
  
fscanf(sfp,"%d",&n);
   fprintf(tfp,"%d",n);
   fprintf(tfp,"\r\n");
  
for(i=0;i<n;i++)
   {
     
fscanf(sfp,"%20s%30s%10s\n",temp[i].name,temp[i].units,
   
temp[i].tele);
     
fprintf(tfp,"%-20s%-30s%-10s\n",temp[i].name,
   
temp[i].units,temp[i].tele);
     
fprintf(tfp,"\r\n");
   }
   fclose(sfp);
   fclose(tfp);
   printf("you have success
copy  file!!!\n");
}

揭秘:《剑网3》开发全过程

转载自http://job.17173.com/content/2008-11-20/20081120172521681,1.shtml

作者:西山居工作室/剑网3/程序 Readme

  
编者按:西山居作为国内知名的游戏工作室,十余年来积累和沉淀了很多东西,无论是美术还是策划或程序或测试,无论是早期的《中关村启示录》、还是现在的《剑侠情缘》系列。金山官方博客将会邀请西山居美术、策划等同事为我们分享游戏制作过程中的点点滴滴。希望通过这些,能够让大家更多地了解到游戏是如何“炼”成的,也希望通过此,为有志于游戏行业的朋友们提供一些指导和建议。

  剑侠情缘叁为什么要自己开发引擎?

  剑侠情缘叁是西山居的第一款全3D网络游戏,使用的是我们自主开发的剑侠叁3D引擎。也许有人会好奇的问:市面上有这么多的游戏引擎,为什么不选择成熟的引擎而要选择自主研发呢?你们真的有信心能做的出来?这个问题就需要从金山的传统说起了。金山是一个以技术立业的公司,我们的核心竞争力在于自主研发能力。从WPS到毒霸再到剑侠情缘网络版,都是从无到有,自主研发出来的。全3D网络游戏代表着网络游戏的发展趋势,而其中的核心技术之一就是3D图像引擎。3D图像引擎技术的理论基础是计算机图形学,这是一门成熟的学科;而在开发剑叁3D引擎之前,我们使用过一款商业化的引擎,在技术上有了一定的积累。有了理论的指导和实际的经验,我们对自主开发并完成一款3D引擎有相当的信心。我们也希望通过引擎的开发建立一支稳定高效的团队。在剑叁引擎的开发过程中,我们的团队始终保持着对技术的不懈追求,不断的完善着3D引擎的功能和效果。同时通过和美术策划同事的合作,我们在引擎相关工具的制作上也积累了大量的经验。这些收获为我们今后追求更高的目标打下了坚实的基础。

  我们做了什么?

  从立项到现在,剑侠情缘叁经过了多年的开发。在这漫长的过程中,我们都做了些什么呢?我们主要的工作包括3D图像引擎和相关的工具的开发。

  图像引擎的作用,是把抽象的数据转换成图像显示到屏幕上。剑叁采用的是由多张地图组合成为整个游戏世界的方式。我们把每张地图都称为一个场景,玩家的人物就在各个场景中活动。场景由多个部分组成,比如说大地我们称为地表;地上的房子、树、城墙什么的,被称为物件;玩家的人物,NPC等活动的元素,被称为活动物件。3D引擎的作用,就是组织好地表和分布其上的物件和活动物件,把它们按照策划和美术同事的设计完美的显示出来。

  在剑侠情缘叁开始之前,我们做了一个小的演示程序。这个演示的主要目的是测试一些关键的技术是不是可行,效果如何,并且为美术同事制定美术元素制作规范提供参考。当时,剑侠情缘叁是一个采用传统2D游戏斜45度视角的游戏,
所以我们的演示程序也是按照这个要求来做的。通过这个Demo,我们主要测试了2D逻辑下的场景管理,3D模型和特效的显示,骨骼和顶点动画技术。

技术测试的3D引擎项目炸弹人

在这个Demo里玩家可以控制一个人物在场景里来回跑动,放置炸弹。玩法和以前FC上的炸弹人类似。当然这个Demo不是说剑侠情缘要做成这样的游戏,他的目的是帮助我们测试上面提到的关键技术,证实已知的方法是确实可行的。测试完成的相当不错,这些技术到现在的都还在使用中。

  有了良好的测试结果, 我们就准备开始大干一场了。在M1的期间(PS,
M是指里程碑,是我们对项目一个目标阶段的说法),我们制作了地图编辑器和特效编辑器。有了地图编辑器,美术同事可以给地表刷上不同的图,表现出草地、沙地之类的变化,然后在刷好的地表上,摆放上房子、路灯、树等等物件,再加上NPC,一个基本的场景就完成了。我们就可以进入到场景里,活动活动腿脚,欣赏下美丽的风景,和NPC做做友好的交流;有了特效编辑器,我们就可以制作火焰、雨雪、水花这些华丽的效果,把这些东西也放到场景里面,画面就显得更有生气了。

  随后我们的工作主要是一些修整和完善。等到WOW推出之后,我们发现2D方式的斜45度视角和WOW的全开放视角比起来,在表现力和游戏体验上都有相当的差距。所以整个项目组在讨论之后,在剑侠情缘叁M2.1的时候作出了一个重大的决定。我们放弃了斜45度锁定视角,转而采用全开放的视角。

  这个决定对3D引擎的影响是巨大的。本来我们采用斜45度视角只要把以前2D游戏的场景管理方式稍加修改就可以了,但改成开放视角之后,需要采用全新的场景管理方式。更要命的是,这个变化不只影响到我们3D引擎,
还影响到美术的的制作。

M1时的剑叁3D引擎截图

  对程序来说,3D场景的管理,是有着成熟的技术理论的支持的。经过一段时间的努力,我们完成了程序上的调整。但是这并不代表整个项目调整的完成。全开放视角对美术的场景制作的观念也带来了巨大的冲击:
以一个房子来说,
在开放视角下,玩家可以从各个角度各个距离观察这个房子,而以前45度锁定视角,玩家只能在一个固定的角度和有限的距离范围内来查看。这就对房子的制作精度有了更高的要求。很多美术之前出于效率考虑采用的优化方法,比如说只制作能被看见的部分,就不能再被使用了。

  开放视角带来的另外一个问题,是可视距离增大带来的场景复杂度的上升。以前斜45度视角只能看到有限的范围,而开放视角之后,如果在平视状态下,视野范围会比以前大很多倍。在程序上,我们采用了LOD技术来动态的调整场景的复杂度,以达到效率上的要求。而对美术来说,
场景的规划比以前有了更高的要求,把很多的东西集中的堆在地图某些区域之内是绝对不被允许的。
如何合理的规划一张地图上的物件,物件应该如何制作才能在画面效果和运行效率间找到平衡, 这些都是急需解决的问题。

  因为美术同事也是第一次制作全3D的地图,缺乏全3D场景的制作的经验。所以他们也做了一个Demo,一张模板地图。最终的选择是剑侠情缘叁的新手村地图。就好像玩家今后都诞生于新手村一样,我们其他所有的地图也都诞生自新手村地图。通过这张地图的制作,美术同事总结出了地图制作和物件制作的规范。那个过程是痛苦而快乐的。痛苦在于很多之前的美术工作被完全的推翻和制作上作出的许多调整;快乐在于开放视角带来的全新游戏体验:忽然可以看到一个广阔的空间的震撼,是每一个从锁定视角游戏过渡到开放视角游戏的玩家都难以忘却的。

 

2008年11月20日 17:25:21  
发表评论/查看评论

 

M2.1改版之后的剑叁3D引擎

  在程序的调整完成之后,我们的程序员爆发出了旺盛的创造欲望。那时显卡的可编程管线技术已经比较普及了,所以我们修改了3D引擎,正式加入了对可编程管线的支持。对于热爱画面表现胜过一切的3D图像程序员来说,
这就好像打开了通往新世界的大门。基于贴图模板的四层地表贴图、法向量贴图、水面反射、全屏幕特效、环境光阻挡图,
预渲染阴影图、柔体,剑侠情缘叁的画面就像从侏罗纪公园回到了现实中。

  在那之后一直到现在, 3D引擎组除了继续美术工具的制作之外,提高渲染效率和效果的变成了我们的主要工作。

  更高的渲染效率,意味着图像引擎可以承受更高的场景复杂度,也就是说可以在场景里面放置更多的东西,
让画面显得更丰富,从而提高整体画面感觉。在这方面我们通过优化场景管理和渲染流程,
并采用了一些DX9的新技术,效率得到了显著提升。然后我们充分使用了这部分优化带来的空闲性能,实现了大规模地形植被(地上长满了各种各样的植物),动态光影(从此不再只有刀光没有剑影了),
并整合了物理引擎(长袖飘飘的效果)。

  在美术的工具上,在完成基本功能之后,我们的工作重点放在了工具的易用性上,主要的方向是制作工具的自动化。举个例子来说,比如需要在地图上的两个地方之间勾出一条道路。以前的做法,是美术用类似画笔的工具在这个路线上画上道路的贴图。设想一下,如果两个点之间有一公里远,那么美术同事就需要用笔刷一点点的涂完这个一个公里的长度。如果有这样一个工具,只要在两个点之间连一条线,并在两点之间根据需要设定一系列的关键点,然后点“确定”,瞬间就可以自动生成一条连接两点,并且经过所有关键点的道路,世界会变得多么美好。

目前的3D引擎效果

  剑叁3D引擎的历史到这里基本上就介绍完了,更多的历史在等待着我们去书写。剑侠情缘叁背负着西山居的光荣与梦想,体现着金山对技术的执着追求,能够参与这样一个激动人心的项目,是我们每一个人的荣幸。

部分同事在去年愚人节剑叁发生大头事件的合照

 

“西山居出品,必属精品!”

  “剑网3真稳定!剑网3真好玩!”

  “不卡号、服务端程序连续运行144小时不崩溃!”

  上述是剑网3项目组全体成员要实现的伟大目标!

软件开发周期性测试

  也许你会问,为什么我们这么重视产品的“稳定”?因为这是结合了西山居人多年研发和运营网络游戏的丰富经验总结出来的,游戏功能可以逐个版本进行完善,游戏流畅度可以一步一步去改善,但是如果在游戏运营过程中,经常出现服务器宕机,客户端程序崩溃,这对于我们广大玩家来说,无疑是当头一棒!极大的影响游戏乐趣。

  我们是如何来实现“稳定”这个目标的?剑网3的测试人员平时都在做些什么呢?通过本文,你将对剑网3的质量团队有初步的了解。也希望大家以后能够给予剑网3这个产品更多的支持!

  剑网3是西山居目前研发时间最长的项目,差不多研发了5年了!“质量第一”是西山居工作室实现精品游戏的第一步,如果质量关没有通过的话,宁可将产品发布时间表推迟,也不能发布一个不稳定的产品出去。

  总体来讲,剑网3的质量人员主要分为“游戏测试工程师”和“测试开发工程师”。当然还有SQA(质量保证组),SCM(配置管理组),这两个组主要工作是项目管理方面。质量人员平时的主要工作是与策划或程序员讨论功能需求设计,进行测试设计(如编写测试方案和测试用例),编写测试报告。

日常代码测试

游戏测试工程师主要的任务目标是确保剑网3的各个游戏功能按照策划案被完整地、正确地实现,实际制作出来的游戏场景与任务要与策划设计的一致,发现的问题或BUG多数为策划设计类和功能类的BUG。例如,游戏场景的风格是否与策划内容一致(如策划设计的是雪地场景,实际实现的也应该是雪地场景,不能在这个场景中出现不协调的场景元素。),功能NPC的功能是否正确实现(如命名为“饰品店老板”的NPC不能同时卖武器),音效是否正确实现(如刀击与棍击的音效是不同的),等等。

  游戏测试工程师的基本要求是对我们的游戏功能和需求非常熟悉。如果你深入玩过多款不同类型的游戏并能够很好的理解游戏系统,并且有一定的编程基础(编译语言不限),就能够更好的帮助发现BUG和提升游戏的可玩性等游戏质量。

游戏测试工程师平时的主要工作有:按版本进行系统测试或功能测试,跑场景(检查障碍、物件、任务、怪物分布等等)、测试怪物AI、检查和测试物品掉落机率、检查NPC对话、测试武功技能等等。同时还会做兼容性测试(如:显卡、CPU、操作系统等等)、易用性测试(如界面操作顺畅度、界面友好度等)。


代码测试工作流程定义

  测试开发工程师主要的任务目标是保障程序代码的质量,同时开发和提供各种调试、测试需要用到的辅助工具,测试开发工程师还需要通过“代码走查”和“单元测试”来发现程序代码规范性问题和潜在的BUG。“让计算机做善长做的事情”----
是测试开发工程师做事的一个重要理念,所以我们开发出了一些自动化的测试工具,如可以自动检查配置表错误的检查工具,可以帮助测试工程师自动跑任务的游戏机器人等。因为我们在每天的凌晨会自动构建版本(通常叫做Nightly
Build),然后会进行自动化测试,所以测试开发工程师每天早上上班第一件事就是看自动化测试报告,这样可以及时地发现每个版本的问题,及时修复。

  测试开发工程师的基本要求掌握较好的编程能力和程序调试能力,有一定的软件系统设计能力,同时对所开发的产品的相关领域知识有一定的了解和掌握,如我们开发的是网络游戏,那么就要会Socket编程,图形编程(如2D或3D),数据库设计与操作等。

  为了更好的说明剑网3质量人员主要的工作任务,给出以下示意图:

  如上图所示,测试开发工程师主要是确保“系统设计—详细设计与编码”这个阶段的相关质量,如系统设计是否合理,算法是否是最优的,代码可读性如何、有没有BUG等等。要特别提出的是,测试开发工程师的工作可以在版本还没有完整编译出来之前就可以开展,也就是说,只要程序员把设计文档写好,或者代码提交到代码库,测试开发工程师就可以开始进行测试了。在游戏测试工程师的工作之前就可以发现一部分BUG。避免这些BUG遗留到系统测试阶段。而游戏测试工程师侧重于发现集成环境下出现的BUG和产品化方面的BUG。

  当然,除了上述说到的要有“专业”的能力外,还需要其它方面的能力,简单地说就是“工作能力”了。网络上有一篇文章,大意是“测试人员必备的十大素质”,有耐心,细心,良好的沟通能力,很好的抗打击能力,较好的总结能力,洞察力,对问题的敏感能力等等。说实话,如果你真的可以同时做到了这些,我可以称你为“神”了!不过作为一名优秀的软件测试工程师(不管是游戏测试或是测试开发),会编程、有耐心、对问题有较好的敏感性、良好的沟通能力确实是做好软件测试工程师的比较重要的前提条件。

就拿耐心来说吧,大家都知道,在游戏研发过程中,会经历无数次的版本集成,也就是说会出无数个版本,对于游戏测试工程师来说,基本上每个版本提交测试后,都需要去将各个场景的任务跑一遍(任务个数成百上千噢。。。),同时还要检查每个NPC和怪物的位置和功能等等,这样做久了肯定会累的。自己想不清楚的话,可能会放弃,如果想清楚了,工作中也经常有一些比较有趣的事情发生。比如为了测试方便,我们的测试工程师们在游戏里一般都是“上帝”。呵呵,其实就是在游戏里可以使用各种各样的“GM指令”啦~~~有了GM指令,你可以随意设置你的角色的等级,获得所有高级装备,学会各种门派的顶级武功,去任何你想要去的地方,这样,各大怪物BOSS当然不在话下,你想怎样孽待这些怪物都可以。哇哈哈~~~不过,有时为了尽量模拟游戏发布后,玩家可能碰到的问题,还是会限制使用“GM指令”的。记得曾经发生过一件很有趣的事:某日测试工程师A创建了一个角色,要测试NPC的一些动作,把村子里面的一个教武功的NPC和周围几个其它NPC杀了,连地上走动的小鸡都不放过,这时在旁边做其它测试的同事发现不能从这个NPC接任务了,然后就开始把追杀他!

工具开发流程

  至此,各位应该对剑网3的测试有了初步的了解了吧?

  总之,我们的目标是做一款精品游戏,做一款好游戏!剑网3的质量保障人员是我经历过的项目中人数最多的,也是最有实力的一支队伍,有了这样一支队伍,再加上一批有做精品游戏理念的项目其它成员,我相信我们能够把剑网3的质量做得足够好,让大家顺畅地、开心地游戏。

游戏开发工具浅谈

转载自http://job.17173.com/content/2008-10-30/20081030174833105.shtml

 作为目前国内游戏业的从业人员,我就我的工作经历把我知道的游戏开发知识分享给大家。所知有限,大家不要见笑哈~今天先说一下一个游戏制作团队需要使用的开发工具。毕竟“工欲善其事,必先利其器”,没有顺手的开发工具,表达和实现难免总是受限。

   
业界标准的游戏制作团队包括设计师(策划)、艺术家(美术)、架构师(程序)三部分,同时也要加上QC(测试)小组以保证迭代开发中的快速验证、除bug与模块稳健度。那么这次就主要介绍各个工作岗位的开发人员需要使用和建议使用的各种开发工具。

   
先从程序说起。程序员需要使用的工具,依据游戏平台的不同、开发端的不同有着不同的区分。但是一般都离不开C++,因此必备的开发工具就是Visual
Studio。以前PC平台上多用C开发,现在基本已经全部采用C++,但考虑到运行效率,有些网络游戏的服务器端开发仍然使用C。但是完全依靠人工写代码不但低效、劳累而且容易出错。因此出现了许多中间件(MiddleWare)开发套件,这些是封装好的图形、物理、粒子、AI、网络、声音、UI模块,内部嵌入了各种游戏中使用的函数。程序员只需要写好接口、加入针对性的运算函数便可以把这些部分的工作量减少很多了。而比较大型的中间件可能包含了这其中的许多模块,这便是游戏引擎(Game
Engine)。游戏引擎有很多种,有综合性的,比如unreal tournament、quake
3D、LithTech、jupiter等等。也有专注性的,最主要专注于两个方面——图形和物理。比如专注图形的ogre和专注物理的havok、ode,现在由于网络游戏开发比较热,引擎的网络部分也得到重视,一般采用C/S方式,也有P2P的方式,有些引擎会提供强大的分布式运算和ado技术。但也有一些引擎没有网络部分,一是由于调用数据的不确定,二是网络端会有专门的优化,许多程序员会写专门的算法处理这一部分。图形用户界面(GUI)有的为团队自己写,因为各种游戏界面需求不太一样。有的用引擎或第三方提供的GUI包写的。有很多……比较著名的是GTK+、wxWidgets、Qt

   
美术方面,二维的标准开发工具是painter和photoshop,三维的标准开发工具是3D
max和maya。二维不用多说,基本多少年都没什么变化。输出的标准格式早期是pcx、bmp,现在最常用的是tga、dds,tga是标准工业格式,已被业内大多数企业所接受很久。dds是为对应directX节省缓存的一种压缩格式,本身也有很多种格式,效果没有无损压缩图像那么好,但对于提高显示效率和节省游戏容量效果很好(图形是游戏中最占容量的部分)。png也是很好用的一种格式,正被逐渐接受。jpeg很少被使用,一是因为图像有损压缩,二是不支持alpha通道,无法实现一些特定效果。三维最早是max和lightwave,但maya的崛起使得其也逐渐成为游戏开发的标准工具。现在不少制作团队都开始转向maya,lightwave在欧美开发团队使用的比较少,日本的开发团队则非常喜欢lightwave。除此之外,由于CG产业的迅猛发展以及开发要求的提高,许多新型的优秀三维工具也进入游戏开发领域。比如softimage、motion
builder等,它们在动画制作方面有着强大的功能。三维输出的主要格式是max(流行)和obj。游戏中各种绚丽的效果是用粒子实现的,这也是美术工作的一部分。一般没有什么标准的工具,只要美术制作出粒子最基础的纹理材质图片(很小的二维图形,常用png格式),再导入到程序中计算路径、发射角、密度、生命周期、着色、受力等。也出现了一些独立的专门制作粒子特效的工具,二维游戏里面最常用的是particle
illusion(它本来是用于影视粒子特效制作的)。三维的有很多,比如particle accelerator、particle
editor等等。

   
策划方面的标准和使用的工具都很杂。由于策划是内容的开发者,所以首先要解决文字和数据的问题。MS 
word和excel是不可少的工具。虽然策划不是美术和程序,但是图像表达和逻辑表达也是策划应该尽量作到的。二维图像表达你至少要会使用word自带的绘图功能,但仍然建议掌握一些基础的平面绘图工具,比如photoshop、fireworks等等,如果你能用动画表示更好,比如flash、gif等;三维建议了解max、maya,我推荐使用轻型快速的三维工具进行表达,比如silo、sketchup等。它们都可以输出为obj格式,方便导入到max中(多用于查看,因为模型会有一定程度的破损,部分需要重新制作),也可以使用截图软件截屏然后制作二维示意图。策划的工作还涉及脚本(script)创作,比如游戏的部分AI、任务逻辑、物品(诞生、消失)控制、运算(hp减血、攻击数值)数据、物理碰撞锁死编辑、触发器等。这些方面的主要文件格式为ini、xml,还有直接封包为bin、pak以及程序自己开发的各种存储格式。不少游戏使用python、lua等通用的脚本语言进行解释,它们可以很方便的嵌入到宿主程序中,加快了调试效率。多数游戏引擎也会提供强大的脚本编译器。

   
其实策划拥有强大的编辑器就可以把上面这些全省了……不过需要程序先把框架搭好,美术先把资源做好,策划才可以拼接设计,这已经耗费了很多时间了。所以能保证制作之前完成规划性的设计是很重要的。策划还需要要考虑可用性、复用性、逻辑锁死以及提出的资源需求(包括质量、数量)对效率的影响。比如哪些美术资源是可以重复使用的,图像质量要求要达到什么程度(过高的要求会大大降低程序渲染效率,也会增加整个团队的工作量),数值变化的临界点以及控制机制。当然这些就是具体的工作内容了,这里不再详述。

   
音乐音效部分有专门的创作团队制作,多数游戏制作商为外包。但也有许多不太注重品质的制作商直接就让策划做了(无敌的音效库……)。标准的创作方法是,首先需要在录音室创作音源,用音频采集卡录制cd品质,在专业工具中进行编辑,包括采样、滤波、除噪、编辑通道、混音、剪辑和合成,最后输出为wav或ogg格式。ogg格式压缩率更高,品质也很好(强于mp3),比起wav格式更省体积;也可以直接创作数字音源,制作midi格式的音乐音效,这就要有更多的专业知识了。这方面的工具有很多,Cubase是标准的开发工具,也可以使用sound
forge、sound editor编辑。