欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > DOC文档下载  

    计算机应用技术毕业论文基于WinCE的小游戏设计.doc

    • 资源ID:2393033       资源大小:294.50KB        全文页数:33页
    • 资源格式: DOC        下载积分:8金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要8金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    计算机应用技术毕业论文基于WinCE的小游戏设计.doc

    毕 业 设 计题 目: 基于WinCE的小游戏设计 系 部: 信息工程系 专 业: 计算机应用技术 班 级: 12计算机应用技术(2)班 姓 名: 王 芳 指导教师: 李 婷 摘 要 从2001年开始,游戏作为一种产业已经渐渐地为中国大众接受,它所带来的经济效益和社会效益更是人们之前所没有估计到的,当游戏作为一种很重要的娱乐手段被大众接受时,游戏产业就已经注定会带来巨大的经济效益。连连看游戏是一款经典小游戏,操作简单,适合所有玩定。连连看游戏软件在Windows环境下,基于MFC框架设计开发,可以实现初始化界面,用户使用鼠标点击两张相同图案的小方块进行消除,并有多种图案样式的功能选择,丰富了游戏的娱乐性。此连连看游戏程序界面美观,操作简单,具有一定的趣味性,是一款老少皆宜的休闲佳品。本文通过需求分析与方案论证,首先对开发连连看游戏程序进行初步的分析,然后通过总体设计的详细设计论述了系统的开发和实现过程。关键词 连连看 单机游戏;游戏开发 目 录第1章 绪论 .1 1.1课题背景.1 1.2课题意义.1 1.3课题内容及目标.1 第2章 总体设计.2 2.1开发工具和运行环境.22.1.1开发工具.2 2.2连连看游戏的设计步骤.22.2.1程序画面的实现.2 2.2.2程序代码的添加.2 2.3基类源代码详解.3 2.3.1基类的构造函数介绍.3 2.3.2基类中其余函数代码的解释.4 2.4卡片类源代码详解.5 2.4.1 Object类.52.4.2 卡片类的构造函数.52.4.3 卡片类中其余函数代码的解释.5 2.5卡片集合类源代码详解.52.5.1卡片集合类的构造函数.52.5.2与卡片处理、绘制、重置相关的函数.62.5.3游戏程序中对屏幕单击的处理.82.5.4判断两张卡片之间是否可以连通.8 2.6游戏类源代码详解.9 2.6.1“离屏技术”的画面绘制方法.9 2.6.2游戏程序的初始化.92.6.3游戏对象的处理.102.6.4绘制卡片之间的连接线DrawLine函数.10 第3章 游戏状态.12 3.1游戏状态概述.12 3.2“连连看"游戏程序状态的介绍.12 3.3程序状态的添加所引起的代码变化.123.3.1卡片集合类.123.3.2游戏类.123.4变化部分代码详解.123.4.1卡片集合类.123.4.2游戏类.13第4章 计时器.16 4.1程计时器功能简介.16 4.2计时器类的添加.16 4.3代码变化的类及新添加的模块代码详解.17 4.3.1计时器类.17 4.3.2游戏类.20 4.4计时功能中时间显示方式的改变.204.4.1变化后的时间显示方式.204.4.2时间显示方式的代码变化.214.4.3代码变化后的计时器类代码详解.224.4.4 代码变化后的游戏类代码详解.24第5章 系统测试.25 结束语.26 致谢.27 参考文献.28第1章绪论1.1 课题背景“连连看”是目前非常流行的一款休闲类游戏。由于它的游戏规则简单、画面精美、操作简便,而赢得了很多玩家的喜欢。在游戏开始运行以后,只需要在多种图形当中,按照游戏的规则(两个图形的连线当中不能有别的图形遮挡,并且两个图形之间最多只允许有两个拐点)找出两个图案相同的图形,然后用鼠标把两者连接在一起,就可以消去彼此相连的两个图菜。在规定的时间内,玩家消掉的图案越多,其得分也越高。1.2 课题意义开发连连看游戏程序的目的是为了人们休闲的需要,在紧张的工作之余休闲类的小游戏能够给人们带来最大程度的放松,也可以增加人们之间的交流、沟通,通过游戏还可以认识更多的朋友,达到人们之间相互娱乐的目的,而且小游戏还不会浪费资源,不像大型游戏占据资源和牵扯精力,可谓工作娱乐两不误。通过此次课题的设计,掌握如何制作一个游戏软件,以及制作游戏软件的整个流程,制作游戏软件的步骤,为以后的就业工作打下基础。1.3 课题内容及目标连连看游戏主要是鼠标两次点击的图片是否能消去的问题。前提是点击两张相同的图片,若点击的是同一张图片或者是两张不同的图片,则不处理。在两张相同图片所能连通的所有路径中,如果存在一条转弯点不多于两个的路径,就可以消去;如果没有,则不可以。此程序的课题内容及目标如下。1. 随机生成游戏界面2. 选择两个图案相同的方块,并且不超过两个转弯的连线将它们连接起来,便可以消除这对方块,每一局玩家需要在规定的时间内消除所有的方块,当完成任务,系统会提示,然后重新开始游戏。3. 当玩家有事,也可以选择暂停。通过对以上功能的实现,达到界面美观,操作简单,增加游戏的娱乐性、趣味性,使玩家对此游戏产生兴趣。第2章 总体设计2.1开发工具和运行环境2.1.1开发工具本程序采用Microsoft Visual Studio 2008作为开发工具。Windows CE 的设计目标是:模块化及可伸缩性、实时性能好、通信能力强大、支持多种 CPU。从操作系统内核的角度看,Windows CE 具有灵活的电源管理功能,包括睡眠/唤醒模式。在 Windows CE 中,还使用了对象存储(Object Store)技术,包括文件系统、注册表 及数据库。它还具有很多高性能、高效率的操作系统特性,包括按需换页、共享存储、交叉 处理同步、支持大容量堆(Heap)等。 Windows CE 拥有良好的通信能力。它广泛支持各种通信硬件,亦支持直接的局域网连 接以及拨号连接,并提供与 PC、内部网以及 Internet 的连接,包括用于应用级数据传输的 设备至设备间的连接。在提供各种基本的通信基础结构的同时,Windows CE还提供与 Windows 9x/NT 的集成和通信。 Windows CE的图形用户界面相当出色。它拥有基于Microsoft Internet Explorer的Internet 浏览器,此外,还支持 TrueType 字体。开发人员可以利用丰富灵活的控件库在 Windows CE 环境下为嵌入式应用建立各种专门的图形用户界面。Windows CE 甚至还能支持诸如手写体 和声音识别、动态影像、3D 图形等特殊应用。 Windows CE 是一个多任务的操作系统,可以同时执行多个任务,并在他们之间来回切换,这其实是Windows的简化版本,可以通过我们熟悉的Windows的操作方式来控制Windows CE,它也带有“我的文档”,也有很多软件如 Pocket Word、Pocket Excel 等。 Windows CE 同时内置了多媒体功能,通过 Windows Media Player 可以播放 MP3,甚至是视频。Windows CE 具有可扩充的 Compact Flash/MMC/SD 插槽,通过扩充卡可以实现多 种功能,例如网页浏览、无线接入或者增加更大的存储空间。2.2、“连连看”游戏的设计步骤 2.2.1程序画面的实现1.运行Visual C#,新建一个Pocket PC 2003的应用程序。把工程的名字命名为“LinkGame”。2.添加游戏程序相关的资源图片。 2.2.2程序代码的添加1.展示游戏中所有对象的基类Object。把诸如图形绘制相关的位置坐标、选择图形区域等操作都放在了这个类中。这种代码组织结构不但使整个程序看上去结构非常清晰,也很好地体现了面向对象概念的精髓所在。即把共性的东西抽象出来,放在一起,方便后面具体对象的实现。 2.卡片类Card。Card类继承自基类Object,因为卡片类中包含了卡片绘制等一些基本的功能,因此从这个意义上讲,继承自Object是最合适的。以后只需要修改基类Object的相关代码,就可以实现用不同图形的卡片绘制(比如,选择不同的卡片作为背景进行绘制等) 卡片集合类主要负责卡片集合相关的事项。比如,绘制整个卡片数组、实现背景卡片的随机排序、处理鼠标在卡片集合上的单击等。可以说,游戏中关键的功能,如处理鼠标单击,判断两张卡片是否可以可见、连通等功能都是在这里实现的。 3.游戏程序的主类frmMaim.cs。frmMain.cs中主要包含了游戏的主循环、应用程序的初始化、对象的处理、对象的绘制等游戏程序的主要功能。概括地讲,该游戏程序都是依靠这个类“串”起来的。因此,建议读者首先要了解该类中如何把游戏程序的各个功能组合在一起,在此基础上再来仔细研究其余类中代码的具体实现。2.3、基类源代码详解在程序代码中提到的Object类是所有对象的基类。在这个游戏中,图形的绘制、选中标示的绘制等都需要计算目的位置的坐标、源图像的坐标等。因此,根据面向对象的思想,把所有这些经常用到的属性都抽象成了一个基类。在这个基类当中包含了一些基本的操作,这样当再派生出具体类(比如,背景卡片)的时候,只需要继承自这个基类就可以了,这就是Object类的作用。2.3.1基类的构造函数介绍在一个类中,首先需要实现的就是该类的构造函数。例如:pubuc Object(Game gRifle) this.game=game;public Object(Game game,Image image,ImageAttributes imageAttr :this(game) this.image=image; this.imageAttr=imageAttr; 上面这两个构造函数的函数名称是完全一样的,都是Object,只有里面的参数不相同。我们把这种在同一个类中函数名称相同,而参数类型不同的现象叫做函数的重载。使用重载函数可以使程序代码在编译的时候,根据函数参数的不同自动地选择相应的函数进行编译。这样可以大大降低程序的复杂程度。 在“this.game=game”、“this.image=image”和“this.imageAttr=imageAttr”中,this后面的game、image和imageAttr为Object类中的变量,在它们的前面加上this就表示是Object类中的变量;等号后面的那些值则为参数列表中传递过来的参数。 在第2个构造函数的参数列表后面“:this(game)”的作用是调用Object(Game game)。用户可以把this看作是Object,这样this(game)自然就可以被看成是Object(game),也就是调用第1个构造函数了。这样做的好处在于,当对Object(Game game)进行修改以后,第2个构造函数是不需要修改的。当然,也可以在第2个构造函数中添加以下语句: this.game=game虽然这样也可以实现原来函数的功能,但是如果第1个构造函数发生了变化,第2个构造函数也需要进行相应的修改。2.3.2基类中其余函数代码的解释public bool Visible get return this.visible; /返回对象是否可见 当卡片被消去以后,就处于不可见的状态,反之,则处于可见状态。这就是Visible函数的作用。 public virtuat Void Process() /对对象进行相应的处理和操作。默认值为空,需要的时候可以在子类重写该函数2.4、卡片类源代码详解2.4.1 Object类“:Object”表示卡片(Card)类是Object类的子类,它继承了父类的所有功能,同时又具备自己的一些特性。2.4.2 卡片类的构造函数pubIlc Card (Game game,Image image,ImageAttributes imageAttr,int left,int top) :base(game,lmage,imageAttr)这个构造函数参数列表后面的“:base(game,image,imageAttr)”表示构造函数在初始化的时候,会将Card参数列表里面的game、image和imageAttr传递给基类构造函数Obiect(Game game,Image image,ImageAttributes imageAttr),这样就实现了初始化所属游戏game、源图像image和颜色属性imageAttr的功能。2.4.3 卡片类中其余函数代码的解释public override void Reset()/重置对象 Show();/重置对象为可见2.5卡片集合类源代码详解 2.5.1卡片集合类的构造函数public Cards(Game game,Image imageCard,ImageAttributes imageAttrCard) this.game=game; /设置游戏对象 this.rows=HEIGHT/Card.HEIGHT; /计算卡片集合的行数 this.cols=WIDTH/Card.WIDTH; /计算卡片集合的列数this.count=this.cols *this.rows; /计算卡片数 this.cards=new Cardthis.count; /生成卡片对象数组for(int row=0;row<this.rows;row+)/遍历卡片集合的每一行 for(int col=0;col<this.cols;col+)/遍历卡片集合的每一列 int index=this.cols *row+col;/计算卡片索引,其取值范围为071。 int left=Card.WIDTH *col+LEFT;/计算卡片左上角X坐标 int top=Card.HEIGHT+row+TOP;/计算卡片左上角Y坐标上面这段代码中的Card.WIDTH*col得出的是当前卡片的左上角距离第一张卡片左上角的距离,再加上后面的LEFT,就得到了当前卡片左上角的X坐标。同理,我们也可以得到当前卡片左上角的Y坐标。 int type=(index/2)Card.TYPE_MAX; /设置卡片类型为两两相同 index/2实现了卡片类型两两相同,再进行“Card.TYPE_MAX”的计算则实现了对20种卡片类型的选择。在该函数执行完以后,数组集合Cards中每相邻的2个卡片的图形是一样的。2.5.2与卡片处理、绘制、重置相关的函数public void Process() /处理卡片对象数组 for(int i=0;i<this.count;i+)if(this.cardsi.Visible)this.cardsi.Process();上面的这段代码中,调用的cardsi.Process()实际上没有实现任何的功能。那么为什么还要添加这段代码呢?这是因为在面向对象的程序设计当中,Cards类既然作为一个集合类,就需要处理每一个元素,这是作为集合类的一个要求。因此,在这里添加这段代码,以保证Cards类的完整性。public void Draw(Graphics gx)/绘制卡片集合 for(int i=0:i<this。count;i+) if(this.cardsi.Visible) this.cardsi.Draw(gx);/调用Card类中的Dmw()函数进行绘制 下面这段代码实现了对卡片集合的重新设置。public void Reset()/重置集合 for(int i=0; i<this.count;i+)/重置卡片对象数组 this.cardsi.Reset();  for (int i=1;i<this.count;i+) /实现对卡片对象数组的随机排序int j=this.game.Random.Next(i,this.count);int type=this.cardsi-1.Type;this.cardsi-1.Type=this.cardsj.Type;this.cardsj.Type=type;下面来看看如何通过for循环语句实现卡片数组的随机排序。上面循环语句里面的Random.Next是返回大于等于i,且小于this.count的整数。从前面的介绍当中已经知道,当初始化卡片数组的时候,每相邻两个卡片的种类是一样的。在这里只需要打乱它们的排列顺序就可以了。其随机排序的过程为:首先通过上面提到的随机函数来得到一个大于等于i,且小于等于this.count的随机数j。把i-1中的卡片类型和j中的卡片类型进行交换,这样就实现了卡片的随机交换功能。第1步通过前面卡片数组的初始化实现了卡片类型的配对,而第2步在配对的基础上实现了卡片类型的随机交换。实际上,在程序设计的过程中,尤其是在游戏程序的设计过程中,随机数的应用是非常广泛的。比如,程序背景画面的随机更新、背景音乐的随机播放、背景图案的随机抖动等都需要借助随机函数的帮助。 this.selected=-1;/重置选中卡片编号在上面的一行代码中,因为所有的卡片被重置以后,没有卡片被选中,因此,selected被设置成-1。2.5.3游戏程序中对屏幕单击的处理public Void Hit(int x,int y) /处理智能设备屏幕的单击 /当单击屏幕的位置处于卡片显示区域外的时候 if(y<TOP)|(y>=ToP+HEIGHT)|(x<LEFT)|(x>=LEFT+WIDTH) return;/不作任何处理 /当单击屏幕的位置处于卡片显示范围内的时候,计算鼠标单击处的行和列int row=(yTOP)/Card.HEIGHT;int coI=(xLEFT)/Card.WIDTH;/被选中卡片的索引编号int selected=this.cols* row+col; if(this.cardsselected.Visible) 当选中的卡片是可见的时候 if(this.Selected=-1) /当单击位置上的卡片还没有被选中的时候 this.selected=selected; /选中该卡片 this.selected=selected语句中,this修饰的是Cards类中的成员变量selected;等号后面出现的是Hit函数中的局部变量selected。2.5.4判断两张卡片之间是否可以连通根据游戏的规则,每两张相同卡片之间的拐点不能超过2个,并且拐点之间不能有别的方块进行阻挡。因此,要判断两张卡片是否可以连通,还需要判断中间的两个拐点和其余部分是否可以连通。而要想判断这4个点是否连通,则需要判断每2个点之间是否可以连通。基于这样的一种判断思路,我们分别设计了3个函数。Lfinked(int src,int dest)。 Connected(int rowl,int coll,int row2,int col2,int row3,int col3,int row4,int col4)。 Through(int srcRow,int srcCol,int destRow,int deskCol,bool skipSrc)。用(rowl,coll)代表起始点所处的行列;(row4,col4)代表目标点所处的行列;(row2,col2)和(row3,col3)代表两个拐点所处的行和列。2.6、游戏类源代码详解2.6.1“离屏技术”的画面绘制方法要采取一种被称之为“离屏技术”的画面绘制方法。具体的设计思路是:首先创建一个虚拟的屏幕,然后把将要绘制的图形画面绘制到这个虚拟屏幕上,最后把虚拟上的所有内容复制到可以显示的真正的物理屏幕上。使用这种技术可以很好地避免屏幕的闪烁现象。这是因为在绘制到虚拟屏幕的时候,所花费的时间很短。在内容变化不大的时候,几乎看不到任何的闪烁。离屏技术主要有以下3个步骤:创建用于离民屏显示的虚拟屏幕。在创建的虚拟屏幕上绘制画面。将虚拟屏幕上的整个画面复制到真正的物理屏幕上。在这个游戏当中,gxPhy对应的是物理屏幕;gxOff对应的是后台的虚拟屏幕,这样就从编码上实现了离屏显示技术。2.6.2游戏程序的初始化public Game() Init();/初始化游戏 MainLoop();/进入到游戏的主循环当中 为了使得在每一次游戏开始的时候,卡片的排列顺序都不相同,在程序代码中就需要用随机函数生成不同的随机数。prot4ected void Init()/初始化应用程序 this.gxPhys=this.CreateGraphicsO;/在前台物理屏上绘制图像/在后台需要绘制的图像,就是前面提到的图片资源中的Background.bmp文件this.imageOff=Resources.Background;/后台绘图面this.gxOff=Graphics.Fromlmage(this.imageOff);上面代码中FromImage的作用为用ImageeOff创建新的gxOff对象。2.6.3游戏对象的处理1.处理所有游戏对象的ProcessAll函数。 public void ProcessAll() this.cards.Process(); /处理卡片集合 2.所有游戏对象的绘制DrawAll函数。public void DrawAll() /绘制所有游戏对象 /绘制背景,以覆盖并准备重绘前景 this.gxOff.Drawlmage(this.imageBack,0,0);/绘制卡片集合,调用了Card类中的Draw函数this.cards.Draw(this.gxOff);/刷新前台显示屏幕,此时将后台画面一次性绘制到前台,离屏技术的体现 this.gxPhys.Drawlmage(this.imageOff,0,0); 3.所有游戏对象的重置ResetAll函数。 public void ResetAll() /重置所有游戏对象 this.cards.Reset(); /重置卡片集合 2.6.4绘制卡片之间的连接线DrawLine函数。 public void DrawLines(int xl,int yl,int x2,int y2,int x3,hat y3,int x4,int y4) Pen pen=new Pen(Color.Red); /设置画笔的颜色为红色下面的3行代码实现了在起始点、目标点和两个拐点之间绘制连接线。 this.gxPhys.DrawLine(pen,xl,yl,x2,y2); this.gxPhys.DrawLine(pen,x2,y2,x3,y3); this.gxPhys.DrawLine(pen,x3,y3,x4,y4);本章小结本章主要介绍了游戏程序“连连看”的整体结构及各函数实现的功能,其中包括游戏对象中所有对象的基类Object,它定义了图形绘制相关的位置坐标、选择图形区域等操作,又介绍了卡处类Card,它包含了卡片绘制等一些基本的功能,如绘制卡片数组、实现背景卡片的随机排序、处理鼠标在卡片集合上的单击等,还介绍了游戏程序的主类fraMain,它包含了游戏的主循环、应用程序的初始化、对象的绘制等游戏的主要功能,它将整个程序串在了一起。第3章 游戏状态的添加3.1、游戏状态概述在游戏程序设计中,游戏状态的添加可以大大增加游戏产品的完整性、可玩性以及游戏界面的友好性。有的游戏在进入到暂停状态的时候会停止当前画面,然后在画面显示暂停信息;有的游戏则会直接进入到游戏设置画面等。3.2、“连连看"游戏程序状态的介绍1. 游戏启动时的状态;2. 游戏运行中的状态;3. 游戏暂停状态下的状态; 4. 游戏重新运行的状态;5. 游戏胜利时的状态;6. 重新开始游戏的状态3.3、程序状态的添加所引起的代码变化“连连看”游戏一共包含4个类,分别为对象的基类、卡片类、卡片集合类和游戏类。其中,对象的基类和卡片类在这个版本的程序中没有发生变化,卡片集合类也只作了很少的修改,惟一变化较大的就是游戏类。3.3.1卡片集合类卡片集合(Cards)类和上一章的版本相比,Draw()函数发生了比较大的变化。3.3.2 游戏类 在这个版本的“连连看”游戏程序中,发生代码变化较大的是游戏类frmMain.cs。3.4、变化部分代码详解3.4.1卡片集合类卡片集合(Cards)类,主要实现了卡片的屏幕绘制、判断两张卡片之问是否连通等功能。在这个版本的“连连看”中,Cards类的变化为体现在Draw()函数的变化上。在第2章中,游戏程序在取得胜利以后,画面上是没有任何提示信息。在本章的程序当中,增加了胜利状态的显示画面,使游戏的功能更趋于完整。在程序中定义的bool类型变量won的作用就是表示游戏玩家是否处于胜利通关的状态。循环语句中代码的作用是在屏幕上绘制出所有的背景图案,一般只有在游戏开始的时候,或者重新开始的时候才需要进行游戏画面的绘制。当然,此时玩家不可能处在通关胜利的状态下,因此,在循环语句当中需要添加“won=false”语句。3.4.2游戏类游戏类中包含了整个游戏程序的主函数、初始化函数等信息,和第三章的Cards类相比,变化较大。在本程序中是在构造函数的前面增加一个枚举类型,具体的代码如下: public enum Status MainMenu, Won, Paused, Playing, Exiting ; 从名称中可以很清楚地看出其代表的含义,分别为:MainMenu:主菜单,也就是游戏启动时的状态。Won:胜利状态。Pause:游戏暂停状态。Playing:游戏正在进行当中。Exiting:游戏退出。构造函数和前一个版本的程序相比,构造函数也发生了一定的变化。通过函数的对比,可以发现,在新版本中去掉了MainLoop()这一行代码。这样做是因为当前版本的游戏程序在初始化的时候,首先展现给玩家的是游戏的启动界面,只有当用户单击屏幕以后才会进入到游戏的循环当中。而前一个版本的游戏直接展现的就是游戏界面,可以直接进入到游戏的循环当中。因为添加了不同的游戏状态,同时需要在进入到游戏主循环函数的时候,进行游戏初始化状态的判断,因此,需要在MainLoop()函数的最前面添加InitGame()函数。I

    注意事项

    本文(计算机应用技术毕业论文基于WinCE的小游戏设计.doc)为本站会员(文库蛋蛋多)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开