LPC基础教程.docx

上传人:b****6 文档编号:5733714 上传时间:2022-12-31 格式:DOCX 页数:24 大小:45.85KB
下载 相关 举报
LPC基础教程.docx_第1页
第1页 / 共24页
LPC基础教程.docx_第2页
第2页 / 共24页
LPC基础教程.docx_第3页
第3页 / 共24页
LPC基础教程.docx_第4页
第4页 / 共24页
LPC基础教程.docx_第5页
第5页 / 共24页
点击查看更多>>
下载资源
资源描述

LPC基础教程.docx

《LPC基础教程.docx》由会员分享,可在线阅读,更多相关《LPC基础教程.docx(24页珍藏版)》请在冰豆网上搜索。

LPC基础教程.docx

LPC基础教程

 

LPC基础教程

 

目录

第一章:

编程环境基本介绍

1.1UNIX基本结构1

1.2UNIX基本命令1

第二章:

LPC程序及其资料形态2

2.1程序特点2

2.2程序的即时性2

2.3电脑是怎样认识程序的3

2.4LPC的资料型态3

第三章:

函数(functions)3

3.1什麽是函数?

3

3.2外部函数(efuns)4

3.3如何定义你自己的函数4

第四章:

基础的继承4

4.1从一个小程序开始4

4.2物件导向程式设计(objectorientedprogramming)5

4.3继承的作用5

第五章:

变数(variable)处理5

5.1数值与物件5

5.2区域(local)和全域(global)变数6

5.3处理变数的值6

5.4复杂的运算式6

5.5LPC运算子7

第六章:

流程控制(flowcontrol)9

6.1LPC流程控制叙述9

6.2if()10

6.3while()和do{}while()12

6.4for()回圈12

6.5叙述:

switch()13

6.6改变函式的流程和流程控制叙述14

第七章:

网络编程16

7.1Socket 模式-----------16

7.2创建 Socket-----------18

7.3客户端/服务器模型-----------------19

7.4绑定到一个端口--------------20

7.5安全----21

7.6监听连接--------22

编后语23

MUD是一种网络游戏,是英文MultipleUserDimension、MultipleUserDungeon或MultipleUserDialoguede缩写,可以翻译为多人世界,多人地下城或多人对话,我们俗称为“泥巴”。

MUD的基本部分是运行于UNIX系统上,其实现编译语言就是将要介绍给您的LPC语言。

其实,如果您已经对UNIX的一些基本指令有所了解的话,exp:

ls,mkdir,rm,mv,cp等等,那么您应该知道如何进入一个mud中的文字编译环境,编一个小程序并存储它了。

这里还需要说明一下,那就是lpc编译出的语言在结构上非常类似于我们所学的C语言编译程序,但是lpc与C语言还是有相当的差距的。

总之,我想说明的意思就是关键是要掌握编程的核心,即编译原理,知道了原理和方法,程序指令是死的,只要多下工夫,是能够弄好弄精的。

这里,我想通过初级篇和进阶篇的一些内容来向您说明LPC以及怎样运用这门语言,不过程序是要多实践的,光通过材料来学习还是不行的,多看看代码,多编些东西,多动手实践一下就会越来越熟悉它了。

本教程选取的是DescartesofBorg于1993年编写的基础lpc和中级lpc教程的内容.在这些教材的基础上我做了一些改动,以供您更方便容易的学习LPC这门语言.

第一章:

编程环境基本介绍

1.1UNIX基本结构

Mudlib编程语言lpc使用的是基本的UNIX命令及档案结构,因此我们有必要想了解一下UNIX方面的知识和相关内容.与我们常用的DOS系统一样,UNIX也使用阶层式的目录结构.所有的次目录都附属于根目录之下.而每个次目录之下同样可以有更多的次目录.一个目录可以有两种表示方法:

1)用目录的全名(fullname),或称作绝对名称(absolutename).

2)使用相对名称(relativename).

绝对名称就是从根目录一路写下来,直到该目录的名字为止.exp:

/daemon/skills/sword.c就是根目录下daemon目录下的skills目录下的sword.c程序.相对名称使用的是相对於其他目录的名字.以上面的例子来说,相对於/daemon,存在目录skills,不难得出,绝对目录是从根目录开始的,而相对目录则灵活的多,随便一个几极的子目录都可以成为确定另一个目录的相对根目录.这里还要确定一下,上述举例中的/daemon/skills/我们都称为路径,而sword.c就是我们所说的档案名。

怎么样,和DOS差不多吧,其实树形目录结构是很多系统共同的部分。

1.2UNIX基本命令

LPmud使用许多UNIX的指令,比较典型的指令有:

ls,cd,rm,mv,edit等等.这些指令对于我们维护和使用LPC的编程环境是非常有用的.这里先举一些常用的指令供您参考:

pwd显示你目前所在的工作目录.

cd改变你目前的工作目录.

ls列出一个目录里面所有的档案.(相当于DOS中的dir)

rm删除指定的档案.(相当于DOS中的del)

mv更改指定档案的档案名.(相当于DOS中的rename)

cp拷贝一个档案到指定目录的命令.(相当于DOS中的copy)

mkdir建立一个新的目录.(相当于DOS中的md)

rmdir删除一个目录,不过该目录必须是空目录.(相当于DOS中的rd)

more如果一个程序太长了,使用这个指令可以分页显示该档案代码.(相当于DOS中的type|more)

edit进入编程模式的指令.

从上面的初次接触中我们不难发现,无论是环境还是指令和我们常用的系统都是差不多的,原理是一样的。

第二章:

LPC程序及其资料形态

2.1程序特点

我们使用LPC编写程序的所写的内容可以统称为物件(objects).一般来说,我们运行一个程序的时候,是有开始和结束的.换句话说,就是所有的程序开始执行的时候,总有一个开头的地方和结束的地方,程序执行后就终止了.而LPC的程序不同,整个mudlib的driver系统运行的是我们用LPC编写出来的一个个程序,这些程序在不同的时间和情况下被不断的调用,虽然都是运行程序,但是LPC的程序在mudlib中是不存在绝对的触发点和结束点的。

这一点需要我们注意。

2.2程序的即时性

本来整个mud游戏可以全部用C语言来写.这样游戏的执行速度将会快上很多,然而这样却让mud缺乏可塑性,使巫师在游戏正在执行的时候无法即时加入新东西.DikuMUD就是全部用C语言写成的.而LPMUD的理论就是driver不该决定游戏内容,而游戏内容应该决定于游戏中的个别事物,并能够在游戏执行时加上东西.这就是为什麽LPMUD使用LPC程式语言.它能让你用LPC定义游戏内容,交给主运行系统根据需要读取并执行.当我们用LPC写了一个程序(假设是用正确的LPC),当你上传(send)成功后,一旦游戏中的东西参考它,他就会即时发生作用.这就是使用LPC语言做到的即时性编程效果.

2.3电脑是怎样认识程序的

我们使用的任何一种编程语言,电脑都不能直接接受它,必须通过转化才行.电脑语言是由0与1组成的一系列排列有序的代码组成的.而我们所用的BASIC、C、C++、Pascal等等,这些电脑语言全都是过渡语言.这些电脑语言让你能把想法组织起来,让思考更易转换成电脑的0与1语言.而转换是通过我们常挂在嘴边所说的编译来实现的.不过对于不同类型的数据,电脑把他转化过来存储起来的时候将不是直接的0和1的形式,就是说,每一个LPC变量都有变量型态指导如何转换资料.比方说我们事先说明intx,就是说明x是一个整形的量值,通过对资料形态的说明,可以让电脑明白每组0,1系列的数据的明确意思.

2.4LPC的资料型态

LPMuddriver具有以下的资料型态:

void,status,int,string,object,int*,string*,object*,mixed*有一些资料型态是我们经常使用的,具有非常重要的作用:

float,mappingfloat*,mapping*.现在我们所用的LPmud的driver一般都是MUDOS,其中的资料形态和上面所例举的差不多.

第三章:

函数(functions)

3.1什麽是函数?

同任何函数一样,LPC函数获得输入值,然后返回输出值.记得Pascal语言是把过程(procedure)和函数区分开来.LPC并不这样做,采用另外一种形式来区分.Pascal称为过程的东西,在LPC就是无返回值(void)型态的函数.也就是说,程序或无返回值函数不传回输出值.Pascal称为函数的东西,就是有传回输出值的.在LPC里,最短的正确函式是:

voiddo_nothing(){},这个函数不接受输入,没有任何指令,也不传回任何值.要写出正确的LPC函数有三个部分:

1)宣告(declaration)2)定义(definition)3)呼叫(call)就像变数一样,函数也要宣告.这样一来,就可以让我们的driver知道:

1)函数输出的资料是什麽型态

2)有多少个输入的资料以及它们的型态为何.

比较普通的讲法称这些输入值为参数.所以,宣告一个函数的格式如下:

返回值型态函数名称(参数1,参数2,...,参数N);这样是形式我们在很多编程语言中都遇见过,所以是不难理解和运用的.需要说明一点的是:

哪一个函数定义在前都没有关系.这是因为函数并不是由前往后连续执行的.函数只有被呼叫时才会执行.唯一的要求是,一个函数的宣告必须出现在函数的定义之前,而且也必须在任何函数定义呼叫它之前.我们不妨举出write_vals()和add()两个函数的例子,仅供参考:

/*首先,是函式宣告.它们通常出现在物件码的开头.*/

voidwrite_vals();

intadd(intx,inty);

/*接着是定义write_vals()函式.我们假设这函式将会在物件以外被呼叫.*/

voidwrite_vals()

{intx;

/*现在我们指定x为呼叫add()的输出值.*/

x=add(2,2);

write(x+"\n");}

/*最後,定义add()*/

intadd(intx,inty)

{return(x+y);}

3.2外部函数(efuns)

也许你已经听过有人提过外部函数.它们是外部定义的函数.外部函数是由muddriver所定义.如果您已经编写LPC程序代码很久,那么实际上您已经接触到了很多函数,exp:

this_player(),write(),say(),this_object()...等等,这些看起来很像函数的式子其实就是外部函数.外部函数的价值在于它们比LPC函数要快得多,因为它们是事先就以电脑可以直接读取和运行的二进制码的格式存在着.这些外部函数是早就被定义和宣告好的内容,需要时您只需要直接呼叫调用它们就可以了.

创造外部函数是为了处理普通的、每天都需要使用到的函数呼叫、处理internetsocket的输出与输入、其他用LPC难以处理的事情的完成和实现.它们是在driver内以C写成的,并与driver一起编译在mud开始之前,这样它们执行起来会快得多.但是对您来说,外部函数呼叫就像对您的函数呼叫一样,它们还是需要知道两件重要的事:

1)它的返回值是什么,2)它需要什么参数.

外部函数的详细资料及其形态,可以在你的mud中的/doc/efun目录找到.不过因为每种driver的外部函数都不相同,所以无法给出一个详细的类型表分类,不过,你可以通过「man」或「help」指令(视mudlib而定)找到详细的资料.例如指令「manwrite」会给你write外部函式的详细资料.当然,「more/doc/efun/write」也可以.

3.3如何定义你自己的函数

虽然在档案中,函数次序的先后是没有什么关系的,但是定义一个函数的程式代码的先后顺序却非常重要.当一个函数被呼叫时,函数定义中的程式代码按照出现的先后顺序执行.例如在4.1中的write_vals()中,这个指令:

x=add(2,2);

如果你想看到write()使用正确的x值,就必须把它放在write()呼叫之前.

函数要返回一个值时,由「return」指令之后跟着与函数相同资料型态的值来完成返回.在先前的add()之中,指令「return(x+y);」把(x+y)的值传回给write_vals()并指定给x.也就是说「return」停止执行函数,并返回程式代码执行的结果给呼叫此函数的另一个函数.另外,它将跟在它后面任何式子的值传回呼叫的函数.因此,要停止执行失去控制的无返回值函数,使用return就可以了;而后面不应加上任何东西.这里需要提醒您一点的是,使用「return」传回任何函数的资料型态必须与函数式本身的资料型态相符合,这是一一对应的关系.

第四章:

基础的继承

4.1从一个小程序开始

我们来看下面这个小程序,它实现的是一个房间:

inheritROOM;

voidcreate()

{set("short","日月园");

set("long","这是江南的工作室,其实就是一个盛开着各种花卉的小花园\n");

set("exits",(["down":

"/d/xyj/kezhan","north":

"/u/power/doorroom",]));

setup();

}

从这个简单的程序中,我们不难得出以下几点也存在几个问题:

1)create()是函数的定义.

2)它呼叫set()、set_exits(),而这两个函数在这段程序代码中并没有宣告或定义.

3)最上面有一行,不是宣告变数或函式,也不是函式定义!

问题:

1)为什麽没有宣告create()?

2)为什麽set()、set_exits()已经宣告并定义过可以直接使用了?

3)程序最上面一句话究竟是什么意思,产生什么作用呢?

这就是本章将要介绍的基础的继承,下面我们开始.

4.2物件导向程式设计(objectorientedprogramming)

继承(inheritance)是定义真正物件导向程式设计的特性之一.它让你创造通用的程式码,能以多种用途用於许多不同的程式中.一个mudlib所作的,就是创造这些通用的档案(物件),然后我们通过调用这些档案来帮助我们制造特定物件.如果你必须把定义前面工作室全部所需要的程式码写出来,大概必须要写1000行程式码才能得到一个房间所有的功能.显然那是不切实际的.再者,这种程式码与玩家和其他房间的互动性很差,因为每一个创造者都写出自己的函式以作出一个房间的功能.所以,你可能使用query_long()写出房间的长叙述,其他的巫师可能使用long().这就是mudlib彼此不相容最主要的原因,因为它们使用不同的物件互动协定.

因此OOP的出现克服了这些问题.前面的工作室中,inheritROOM表示你已经继承了ROOM的函数ROOM拥有普通房间所需要的全部函式定义其中.当你要制造一个特定的房间,你拿这个房间档案中定义好的通用函式功能,并加上你自己的函式create()就可以很轻松地制造一个独特的房间.

4.3继承的作用

例举上面这个房间的例子,inheritROOM使你调用出了ROOM这个已经宣告好的函数,该函数包含了许多房间函数,如set()和set_exit()等等,正是基于这些函数都是实现宣告并定义好的,所以我们可以直接利用它们来进行我们的代码编辑工作.在你的creat()函式里,你呼叫那些函式来设定你房间一开始的值.这些值让你的房间不同於别的房间,却保留与记忆体中其他房间互动的能力.

由于mudlib之间还存在差异性,所以不同的mudlib就各有一套不同的标准函数供我们使用,例如F_SSERVE和SSERVE其实是同一个标准函数.因此在coding之前我们需要弄清楚我们所处的mudlib的环境以及提供的标准函数的一些具体情况再开始编程.

第五章:

变数(variable)处理

5.1数值与物件

基本上,mud里头的物件都不一样的原因有两个:

1)有的物件拥有不同的函式

2)所有的物件都有不同的数值

现在,所有的玩家物件都有同样的函式.它们不一样的地方在於它们自己所拥有的数值不同(例如id),举例来说,名字叫做mzjl的玩家跟fyfbi,他们各自的name变数值不同,一个是"mzjl",另一个是"fyfbi".

所以,游戏中量值地改变伴随着游戏中物件值的改变.函式名称就是用来处理变数的过程名称.例如说,create()函式就是特别用来初始化一个物件的过程.函式之中,有些特别的事称为指令.指令就是负责处理变数的.

5.2区域(local)和全域(global)变数

跟大多数程式设计语言的变数一样,LPC变数可以宣告为一个特定函式的「区域」变数,或是所有函式可以使用的「全域」变数.区域变数宣告在使用它们的函式之内.其他函式并不知道它们存在,因为这些值只有在那个函式执行时才储存在记忆体中.物件码宣告全域变数之後,则让後面所有的函式都能使用它.因为只要物件存在,全域变数就会占据记忆体.你只有在整个物件中都需要某个值的时候,才要用全域变数.看看下面两段程式码:

intx;intquery_x(){returnx;}voidset_x(inty){x=y;}

voidset_x(inty){intx;x=y;write("x设定为"+x+"并且会消失无踪.\n");

第一个例子里,x宣告在所有的函式之外,所以在x宣告之後的所有函式都能使用它.x在此是全域变数.

第二个例子中,x宣告在set_x()函式里.它只有在set_x()执行的时候存在.之後,它会消失.在此,x是区域变数.

5.3处理变数的值

给driver的指令(instruction)用来处理变数值.一个指令的范例是:

x=5;

上面的指令很清楚.它把5这个数值指定给x变数.不过,这个指令牵涉到一些对普通指令来说很重要的观念.第一个观念是运算式,一个运算式就是有值的一系列符号.在上面的指令中,运算式5的值指定给变数x.常数是最简单的运算式.一个常数就是不变的值,像是整数5或是字串"hello".最後一个观念就是运算子.在上面的例子中,使用了=这个指定运算.

在LPC有更多其他的运算子,还有更复杂的运算式.如果我们进入一个更复杂的层次,例如:

y=5;x=y+2;

第一个指令使用指定运算子以指定常数运算式5的值给变数y.第二个指令把(y+2)的值以加法运算子把y和常数运算式2加起来,再用指定运算子指定给x.

换另一种方法来讲,使用多个运算子可以组成复杂的运算式.在前面的范例中,一个指令x=y+2;里面含有两个运算式:

1)运算式y+22)运算式x=y+2

5.4复杂的运算式

前面你大概已经注意到,运算式x=5「本身」也有个值是5.实际上,因为LPC运算子如同运算式一样也有自己的值,它们能让你写出一些非常难解、看起来毫无意义的东西,像是:

i=((x=sizeof(tmp=users()))?

--x:

sizeof(tmp=children("/std/monster"))-1)

基本上只是说:

把外部函式users()传回的阵列指定给tmp,然後把此阵列元素的数目指定给x.如果指定给x的运算式值为真(不是0),就指定x为1并指定i的值为x-1的值.如果x为伪,则设定tmp为外部函式children()传回的阵列,并指定i为阵列tmp的元素数目再减1.你曾经用过以上的叙述吗?

我很怀疑.不过你可能看过或使用与它相似的运算式,因为一次合并这麽多的东西在一行里面,能提升你程式码的执行速度.比较常使用LPC运算子这种特性的写法大概像这样:

x=sizeof(tmp=users());

while(i--)write((string)tmp[i]->query_name()+"\n");

取代这样子的写法:

tmp=users();

x=sizeof(tmp);

for(i=0;iquery_name()+"\n");

像是for()、while()、阵列......等等东西稍後会解释.

不过第一段程式码比较简洁,执行起来也比较快.

下面提供一些LPC运算子的说明.

5.5LPC运算子

=指定运算子(assignmentoperator):

范例x=5

说明:

把「右边」任何运算式的值指定给它「左边」的变数.

注意,你只能於左边使用一个变数,也不能指定给常数或复杂的运算式.

+加法运算子(additionoperator):

范例x+7

左边值加上右边值的总和

说明:

把右边运算式的值加上左边运算式的值.

对整数(int)型态值来说,就表示数值总和.对字串(string)来说,表示右边的值接在左边的值後面("a"+"b"的值是"ab").这个运算子不改变任何原始值(即变数x维持原来的值).

-减法运算子(subtractionoperator):

范例x-7

左边运算式的值减去右边的

说明:

虽然它是减法,但实际上与加法的特性是相同的.字串"ab"-"b"的值是"a".

*乘法运算子(multiplicationoperator):

范例x*7

说明:

除了这个作数学乘法之外,特性与加法、减法相同.

/除法运算子(divisionoperator):

范例x/7

值与说明同上

+=加法指定运算子(additiveassignmentoperator):

范例x+=5

值与x+5相同

说明:

它把左边的变数值和右边的运算式值加起来,把总和指定给左边的变数.例如如果x=2...x+=5指定7值给变数x.整个运算式的值是7.

-=减法指定运算子(subtractionassignmentoperator):

范例x-=7

值:

左边的值减去右边的值.

说明:

虽然执行的是减法运算,但特性与+=相同.

*=乘法指定运算子(multiplicativeassignmentoperator):

范例x*=7

值:

左边的值乘上右边的.

说明:

除了乘法以外,与-=和+=相似.

/=除法指定运算子(divisionassignmentoperator):

范例x/=7

值:

左边变数的值除以右边的值.

说明:

除了除法以外,同上.

++後/

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 高中教育 > 理化生

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1