精华内容
下载资源
问答
  • 数据库管理 D.BASIC和FORTRAN 一个完整的计算机系统通常应包括C 系统软件和应用软件 B.计算机及其外部设部C.硬件系统和软件系统D.系统硬件和系统软件 计算机辅助教学英文缩写是B CAD B.CAI C.CAM D.CAT 计算机的...
  • 一个程序应包括以下两个方面的内容: 对数据的描述 a.编写的程序中指定【数据的类型】和数据的组织形式,即数据结构 对操作的描述(算法) a.数据是操作的对象,操作的目的是对数据进行加工处理,以得到期望的...

    一个程序应包括以下两个方面的内容:

    • 对数据的描述

      a.编写的程序中指定【数据的类型】和数据的组织形式,即数据结构

    • 对操作的描述(算法)
      a.数据是操作的对象,操作的目的是对数据进行加工处理,以得到期望的结果。

    著名计算机科学家沃思提出了一个公式:

    数据结构 + 算法 = 程序

    故一名程序设计人员应具备:

    • 算法(解决“做什么”和“怎么做”的问题)
    • 数据结构
    • 程序设计方法(结构化程序设计)
    • 语言工具

    算法:做任何事情都要有的一定步骤

    分类:数值运算算法 / 非数值运算算法

    数值运算算法:求数值解 例如:求方程的根

    非数值运算算法:事务管理领域,图书检索

    简单算法举例

    • 求1×2×3×4×5
      步骤1:1×2,得到结果2
      步骤2:将步骤1得到的乘积结果在×3,得到结果
      步骤3,依次类推…
      虽然可以得出结果,但是如果有一万个数,就得相同的方式×以一万遍。

    可以设两个变量:

    • 一个变量代表乘数
    • 一个变量代表乘数
      不另设变量存放乘积结果,而直接将每一步的乘积放在被乘数变量中。
      设p为被乘数,i为乘数
      S1:使p=1
      S2:使i=2
      S3:使pi,乘积仍放在变量p中,可表示为:pi=p
      S4:使i的数值加1,即i+1=i
      S5:如果i不大于5,返回重新执行步骤S3,以及S4,S5;否则算法结束。
      最后得到p的数值就是5!的值。

    算法的特性

    • 有穷性(合理的范围内)
    • 确定性(算法的每一个步骤都应该是清晰确定的,新手很容易犯这个错误)
    • 有零个或者多个输入(外界获取的输入信息 / 内部设定的常量)
    • 有一个或者多个输出
    • 有效性(算法的每一个步骤都应当能有效的执行)

    表示算法

    • 自然语言表达
    • 流程图表示
      *目的是提高算法的质量,限制箭头的随意使用
      -
      -N-S流程图表示算法

    伪代码

    原因:算法比较复杂,需要反复修改时

    • 例如:打印x的绝对值
      if x is positive then
      print x
      else
      print -x
      也可以用汉字描述
      若x为正
      输出x
      否则
      输出-x
      也可以中英文混用
      if x 为正
      print x
      else
      print -x
      (关键字用英语表示,其他可用汉字)
      (原则便于书写和阅读即可)
      例如前面的例子,求1×2×3×4×5
      伪代码:
    1. 开始
    2. 置t的初始值为1
    3. 置i的初始值为2
    4. 当i<=5,执行下面操作
    5. 使t=t*i
    6. 使i=i+1
    7. {循环体到此结束}
    8. 输出t的值
    9. 结束

    也可以写成以下的形式
    begin // 算法开始
    1=t
    2=i
    while i 《 5
    {
    t*i=t
    i+1=i
    }
    print t
    end //算法结束

    本次算法采用 当型循环(第3行到第5行是一个当型循环)
    while意思为“当”
    实现代码

    #include<stdio.h>
    void main()
    {
    	int i,t;	//先定义数据类型
    	t=1;		//赋值
    	i=2;
    	while(i<5)
    	{
    		t=t*i;
    		i=i+1;
    	}
    	printf("%d\n",t);
    	scanf("%d",&t);
    }
    
    展开全文
  • 问题由文本组成,其中包括多行文件以及一系列可能的答案,这两个结构都可由数组表示,问题的文本是字符串的数组,每一个字符串包含了一行的内容。而答案存储在一个结构较为复杂的数组中 通常情况下,需要提供一个...
  • 完整的计算机应包括()。 A. 运算器、存储器、控制器 B. 外部设备和主机 C. 主机和实用程序 D. 配套硬件设备和软件系统 (答案) 答案:D 得分:2.0/2.0 第3题 若某段程序共花费了60时钟周期,该段程序共有50条...

    单项选择题
    第1题
    冯•诺伊曼机工作方式的基本特点是()。
    A. 多指令流单数据流
    B. 按地址访问并顺序执行指令 (答案)
    C. 堆栈操作
    D. 存储器按内容选择地址
    答案:B 得分:2.0/2.0

    第2题
    完整的计算机应包括()。
    A. 运算器、存储器、控制器
    B. 外部设备和主机
    C. 主机和实用程序
    D. 配套的硬件设备和软件系统 (答案)
    答案:D 得分:2.0/2.0

    第3题
    若某段程序共花费了60个时钟周期,该段程序共有50条指令,则CPI=?
    0.83
    3000
    1.2 (答案)
    得分:2.0/2.0

    第4题
    计算机系统中广泛采用总线将五大部件联系起来,使用总线结构可以()。
    A. 减少信息传输量
    B. 减少信息传输线的条数
    C. 提高信息传输的速度 (答案)
    D. 增加CPU的工作量
    答案:C 得分:2.0/2.0

    第5题
    运算器中临时存放数据的部件是()。
    A. ALU
    B. 寄存器 (答案)
    C. 存储器
    D. 指令寄存器
    答案:B 得分:2.0/2.0

    第6题
    软件系统包括哪些软件?
    windows、office
    系统软件、应用软件 (答案)
    windows 、高级语言
    得分:2.0/2.0
    第7题
    从器件角度看,计算机经历了四代变化。但从系统结构看,至今绝大多数计算机仍属于()型计算机。
    A. 并行
    B. 智能
    C. 实时处理
    D. 冯•诺伊曼 (答案)
    答案:D 得分:2.0/2.0

    第8题
    对计算机软硬件资源管理,是()的功能。
    A. 操作系统 (答案)
    B. 应用程序
    C. 语言处理程序
    D. 用户程序
    答案:A 得分:2.0/2.0

    第9题
    主频为10MHZ,则时钟周期为_______。 。
    1000ns
    10ns
    100ns (答案)
    得分:2.0/2.0

    第10题
    运算器虽有许多部件组成,但核心部件是()。
    A. 数据总线
    B. 算术逻辑运算单元 (答案)
    C. 多路开关
    D. 累加寄存器
    答案:B 得分:2.0/2.0

    填空题
    第1题
    计算机存储器的最小单位是()。
    学生答案:比特
    标准答案:比特
    得分:2.0 /2.0

    第2题
    在计算机系统中,在总线上传送的信息包括()、地址和控制信息
    学生答案:数据
    标准答案:数据
    得分:2.0 /2.0

    第3题
    计算机的软件通常分为()和应用软件两大类。
    学生答案:系统软件
    标准答案:系统软件
    得分:2.0/2.0

    第4题
    在计算机系统中,多个部件之间信息传送的公共通路称为()。
    学生答案:总线
    标准答案:总线
    得分:2.0/2.0

    第5题
    计算机硬件由控制器、()、存储器、输入设备和输出设备五个部分构成。
    学生答案:运算器
    标准答案:运算器
    得分:2.0/2.0

    第6题
    输入输出设备以及磁盘存储器统称为()。
    学生答案:外部设备
    标准答案:外围设备
    得分:0.0/2.0

    第7题
    计算机硬件由控制器、运算器、存储器、()和输出设备五个部分构成。
    学生答案:输入设备
    标准答案:输入设备
    得分:2.0/2.0

    第8题
    指令周期由取指周期和()周期组成。
    学生答案:执行
    标准答案:执行
    得分:2.0 /2.0

    第9题
    指令周期由()周期和执行周期组成。
    学生答案:取指
    标准答案:取指
    得分:2.0 /2.0

    第10题
    计算机硬件由控制器、运算器、存储器、输入设备和()五个部分构成。
    学生答案:输出设备
    标准答案:输出设备
    得分:2.0 /2.0

    展开全文
  • 美籍匈牙利数学家冯•诺依曼提出了一个通用的计算机设计方案三个重要思想: (1)计算机至少由运算器、控制器、存储器、输入设备、输出设备五个基本功能部分组成。 (2)采用二进制数形式表示计算机的指令和...
  • 问题4-17:一个大学能否就使用一个很大局域网而不使用许多相互连接较小局域网? 问题4-18:一个10 Mb/s以太网若工作在全双工状态,那么其数据率是发送和接收各为5 Mb/s还是发送和接收各为10 Mb/s? 问题4-19:...
  • 一个程序应包括以下两方面内容: (1) 对数据描述在程序中要指定数据类型和数据组织形式即数据结构(Data structure) (2) 对操作描述即操作步骤 也就是算法(Algorithm)数据是操作对象操作目的是对数据进行...
  • IP应用程序-源码

    2021-02-21 08:38:42
    IP应用程序(图像处理应用程序)是一个仓库,其中包括用于获取以下内容的所有python和Shell代码: 所有边缘检测水平 影像还原 压缩 & 其他 罗伯茨交叉算子 Roberts交叉算子用于图像处理和计算机视觉中边缘检测。...
  • windows 程序设计

    2011-07-24 21:16:30
    因为这些窗口看起来有些像桌面上纸(当然,这是计算机还未占据办公桌之前年代),Windows有时被称作:一个显示多个程序的「具象化桌面」。 Windows早期版本使用一种「非优先权式(non-preemptive)」多任务...
  • 一个简单节点应用程序,可让您与随机人(例如聊天轮盘或omegle)进行视频聊天 科技类 WebRTC 节点 套接字 jQuery查询 错误/已知问题 目前,此应用尚未经过任何大规模测试。 在我本地计算机上,最多经过测试...
  • 刘师少 Tel 86613747h E-maillss@ 授课: 51学时 学分: 3 教学目标: 知识能力素质;...一个程序应包括以下两方面内容: (1) 对数据描述在程序中要指定数据类型 和数据组织形式即 数据结构 (data structure) (2)
  • 它主要应包括什么内容?简述其作用。 答:记录设备硬件特性、连接和使用情况等信息数据结构称为设备控制块dcb。系统为每一个设备构造一个设备控制块。 它主要包括以下内容: 1、 设备名。设备名是设备系统名,...

    计算机操作系统第八章课后作业

    8-1:什么是设备独立性?引入这一概念有什么好处?
    答:所谓的设备独立性是指用户在编制程序时所使用的设备与实际使用的设备无关。
    好处:
    1:方便用户
    2:提高设备的利用率
    3:提高系统的可适应性和可扩展性。

    8-3:什么是设备控制块?它主要应包括什么内容?简述其作用。
    答:记录设备的硬件特性、连接和使用情况等信息的数据结构称为设备控制块dcb。系统为每一个设备构造一个设备控制块。
    它主要包括以下内容:
    1、 设备名。设备名是设备的系统名,即设备的物理名。
    2、 设备属性。设备属性是描述设备现行状态的一组属性。
    3、 指向命令转换表的指针。命令转换表记录了一台设备能实施记录了一台设备能实施的I/O操作表,表中包含设备特性的I/O例程地址,不具备某一功能时,在其例程地址上填-1;
    4、 在I/O总线上的设备地址
    5、 设备状态
    6、 当前用户指针
    7、 I/O请求队列指针

    8-4:什么是缓冲?引入缓冲的原因是什么?
    答:缓冲是两种不同速度设备之间的传输信息时平滑传输过程的常用手段。
    引入缓冲技术的原因:
    1、 为了进一步缓和CPU和I/O设备之间速度不匹配的矛盾。
    2、 提高CPU与I/O设备之间的并行性。
    3、 为了减少中断次数和CPU的中断处理时间。
    4、 为了解决DMA或通道方式下数据传输的瓶颈问题。

    8-8:什么是独占设备?对独占设备如何分配?
    答:独占设备是让一个应用程序在整个运行期间独占使用的设备。
    独占设备采用独享分配方式或称为静态分配方式,即在一个应用程序执行前,分配它所要使用的这类设备;当应用程序处理完毕撤离时,收回分配给它的这类设备。静态分配方式实现简单,且不会发生死锁,但采用这种分配方式时外部设备利用率不高。

    8-9:什么是共享设备?对共享设备应如何分配?
    答:由多个作业、进程共同使用的设备称为共享设备。
    对共享设备采用共享分配方式,即进行动态分配,当进程提出资源申请,由设备管理模块进行分配,进程使用完毕后,立即归还。

    8-10:什么是虚拟设备技术?什么是虚拟设备?如何进行虚拟分配?
    答:所谓虚拟设备技术,是在一类物理设备上模拟另一个物理设备技术,是将独占设备转换为共享设备的技术。
    用来代替独占型设备的那部分外存空间称为虚拟设备。
    对虚拟设备采用虚拟分配。当某进程需要与独占设备交换信息时,系统就将与该独占设备所对应的那部分磁盘的一部分存储空间分配给它。

    8-11:什么是spool系统?什么是预输入?什么是缓输出?
    答:操作系统提供外部设备联机同时操作的功能设备spool系统,又称为假脱机系统。
    spool系统在应用程序执行前将应用程序的信息通过独占设备预先输入到辅存上的一个特定的存储区域存放好。称为预输入。
    在应用程序执行中,也不必直接启动独占设备输出数据,而只要将其输出数据写入磁盘中存取,在应用程序执行完毕后,由操作系统来组织信息输出,称为缓输出。

    8-19:在UNIX系统中,缓冲区首部的结构如何?它的作用是什么?

    答:缓冲区首部结构有:
    1:设备号dev
    2:块号blkno
    3:状态flag
    4:指向数据区域的指针
    5:传送字节数
    6:返回的I/O出错信息
    7:b_forw 设备缓冲区队列前向指针
    8:b_back 设备缓冲区队列后向指针
    9:av_forw 空闲缓冲区队列前向指针
    10:av_back 空缓冲区队列后向指针

    展开全文
  • 所谓指令系统指一个计算机系统能执行所有指令集合。 (2)数据结构研究3个方面 ① 数据集合中各数据元素之间所固有逻辑关系,即数据逻辑结构; ② 在对数据进行处理时,各数据元素在计算机中存储...
  • 计算机操作 课程设计

    2012-02-20 18:34:50
    学生按上述内容要求,用自己熟悉高级语言编写程序(语言自选,种类不限), 并在计算机上通过程序,完成课程设计。 时间安排在18周 五、提交方式 电子部分以电子邮件方式或者U盘拷贝方式提交给班长。把设计...
  • [y]正确猜测后,播放将继续进行下一轮操作(用户进入模式一个步骤)。 [y]用户猜完一个完整模式后就赢得了游戏 [y]用户在错误猜测后输了游戏(警报在我屏幕录像之外弹出。) 实现了以下可选功能: 任何...
  • 问题由文本组成,其中包括多行文件以及一系列可能的答案,这两个结构都可由数组表示,问题的文本是字符串的数组,每一个字符串包含了一行的内容。而答案存储在一个结构较为复杂的数组中 通常情况下,需要提供一个...
  • 计算机图形学期末作业

    万次阅读 多人点赞 2018-09-11 15:34:22
    学生可以通过层级建模( 实验补充1和2)方式建立多个虚拟物体,由多个虚拟物体组成一个虚拟场景,要求在程序中显示该虚拟场景,场景可以是室内或者室外场景;场景包含地面。 添加纹理 参考实验4.1,为场景中...

    作业要求:

    期末大作业 虚拟场景建模

    一、作业内容

    在屏幕上显示一个包含多个虚拟物体的虚拟场景,并且响应一定的用户交互操作。

     

    具体内容包括:

    1. 场景设计和显示

    学生可以通过层级建模( 实验补充1和2)的方式建立多个虚拟物体,由多个虚拟物体组成一个虚拟场景,要求在程序中显示该虚拟场景,场景可以是室内或者室外场景;场景应包含地面。

    1. 添加纹理

    参考实验4.1,为场景中至少两个主要物体添加纹理贴图 。

    1. 添加光照,材质,阴影效果

    参考实验3.3和实验3.4,实现光照效果,阴影等。

    1. 用户交互实现视角切换完成对场景的任意角度浏览

    参考实验3.1,完成相机变换。

    1. 通过交互控制物体

    参考实验2.3,实现物体的变换,允许用户通过键盘或者鼠标实现场景中至少两个物体的控制(移动,旋转,缩放等等)。

     

    二、作业说明与要求

     

    1. 程序代码:本次作业不提供参考代码,具体可参考实验补充2的代码框架,程序运行窗口标题设为“学号_姓名_期末大作业 。最终提交的代码中与作业内容相关部分必须写上注释。 
    2. 过程说明报告:使用附件提供的以论文、报告等形式考核专用答题纸.doc”撰写,题目可以是虚拟场景建模或者场景模型的名称,内容需对整个工程代码实现的过程文字进行详细地描述配有一定的截图说明,即类似于实验报告中实验步骤部分的撰写方式。排版要整齐,字体要规范。宋体五号,至少八页。
    3. 使用说明书:自行撰写一个word文档,命名为“学号_姓名_使用说明书。内容必须包含(a)一张有代表性的模型绘制截图,(b)模型的层次结构框图,(c)鼠标和键盘的具体交互用法, 即对如何使用鼠标和键盘与虚拟场景模型进行交互描述清晰并配有一定的截图说明。
    4. 上传格式:按上述要求完成实验,一并提交电子版过程说明报告、使用说明书和源代码压缩包。文档程序压缩包名称为“学号_姓名_期末大作业”。
    5. 截止时间
    6. 答辩说明:第18周理论课和实验课将安排课程大作业答辩,按照学号顺序,每人上台展示自己的期末大作业。具体答辩安排等候后期通知。

     

     

    学生作业:

    一、整体游戏设计

    游戏描述:

    “操纵角色”站在某个“方块”上,然后在该“方块”的 前后左右 的某个方向,在一定距离生成一个 新的“方块”。点击鼠标使“操纵角色”跳跃至新的方块上,跳到则加分,跳不到则游戏结束。其中,按住鼠标左键能调节跳跃力度,放开鼠标左键则开始跳跃。

    注:本实验“跳一跳”游戏 参考自 微信“跳一跳”小程序游戏。

     

    设计图解:

    图 1 :“跳一跳”设计图解

     

    说明:

    ① 新生成方块的前后左右 生成方向是随机的,但是不会在上一个方块的位置方向上生成。

    ② 方块间的距离在一定范围内也是随机的,确保“操纵角色”的最大跳跃距离大于它。

    ③ 生成的方块为立方体,尺寸相等。

     

    二、图形的基本绘制及相关说明

    1、obj模型的绘制

    1)获取obj文件的UV坐标数据,顶点坐标数据,顶点法线数据,存储三角面片的顶点索引数据(包括顶点坐标、UV坐标、顶点法线索引)。

    读取obj文件注意一下几点即可:

    ① 把顶点数据存储到m_vertices_(按每个顶点的x、y、z坐标依次存储);

         把法线数据存储到m_normals_(按每条法线的x、y、z坐标依次存储);

         把顶点颜色数据存储到m_color_list_(由顶点法线决定。按每个顶点颜色的r、g、b坐标依次存储);

         把纹理坐标数据存储到m_vt_list_(按每个纹理坐标的x、y坐标依次存储);

         把索引信息存储到m_faces_(以每个面的三个顶点为一组数据,可知一组数据有9个值,这9个数据值依次按:3个顶点坐标点索引、3个uv坐标点索引、3个法线坐标索引 顺序存储)。

     

    因为obj文件索引是从1开始的,为方便找顶点相关数据,先给相关容器加一个0。

     

    ③ 用getline(fin, str)函数逐行检测(fin为obj文件的ifstream流,str为读取的当行文本字符串)。每读一行检测第一个空格前的字符串是否为“v”“vt”“vn”或“f”。

         是,则要把相关数据用>>按空格分开读取后压入到相关容器中。读取索引数据时,每读一个顶点的三个索引数据(即:顶点索引/uv点索引/     法线索引),要用getline函数按'/'作为分隔符分割;

     

    2)由索引确定顶点相关信息并传给shader

    在update_vertex_buffer函数申请顶点数组对象和顶点缓存对象,获得足够的空间存储坐标,颜色,法线以及纹理坐标。

    已知绘制各个面所需的数据索引,因此只要根据索引值到数据容器中寻找相应的值即可。

    以顶点坐标数据为例:

    Mesh_Painter.cpp文件中获取到我们刚刚获得的无序顶点坐标数据容器,赋给新容器vertex_list;同理获得存储索引数据的新容器face_list;num_face为面的个数,易知值为face_list.size() / 9 。

    现在,我们想通过face_list中的顶点坐标索引值获取有序的顶点坐标、并存储在容器points中。 已知face_list每9个数据为1组,且顶点坐标索引在前3个数据;而vertex_list则是以每3个数据为1组。

    易知其获取方法,以下为核心代码:

    //

    for (int i = 0; i < num_face; i++)

    {

    int index = face_list[9 * i];

    points[3 * i] = vec3(

    (vertex_list[index * 3 + 0] - p_center_.x) / (1.5 * d),

    (vertex_list[index * 3 + 1] - p_center_.y) / (1.5 * d),

    (vertex_list[index * 3 + 2] - p_center_.z) / (1.5 * d)

    );

    index = face_list[9 * i + 1];

    points[3 * i + 1] = vec3(

    (vertex_list[index * 3 + 0] - p_center_.x) / (1.5 * d),

    (vertex_list[index * 3 + 1] - p_center_.y) / (1.5 * d),

    (vertex_list[index * 3 + 2] - p_center_.z) / (1.5 * d)

    );

    index = face_list[9 * i + 2];

    points[3 * i + 2] = vec3(

    (vertex_list[index * 3 + 0] - p_center_.x) / (1.5 * d),

    (vertex_list[index * 3 + 1] - p_center_.y) / (1.5 * d),

    (vertex_list[index * 3 + 2] - p_center_.z) / (1.5 * d)

    );

    }

    GLintptr offset = 0;

    glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(vec3)*num_face * 3, points);

    //顶点坐标传给shader

    offset += sizeof(vec3)*num_face * 3;

    delete[] points;

    //

    其余顶点相关信息获取方法类似,不细说明。

    3)根据模型的各个信息进行图形绘制,同时要对纹理贴图进行创建和赋值,这里调用外部类FreeImage来实现。

     

    2、矩形图形的绘制

       绘制流程与上述obj图形的绘制流程比较相像,唯一不同的是obj文件的所有信息是通过读取文件得到的,而矩形图形的所有信息都是自己写的,参考以下图形坐标点及绘制顺序,和纹理坐标点来进行点信息的写入:

    图 2:矩形图形顶点坐标点及顶点的建立顺序图

     

    图 3:矩形图形纹理坐标图

     

     

    3、模视变换和透视投影

     1)模型变换矩阵为单位矩阵

     2)相机观察矩阵根据eye(视点)、at(参考点)、up(向上变量)三参数确定。

    核心代码:

    mat4 lookAt(const vec4& eye, const vec4& at, const vec4& up)

    {

    //归一化:normalize

    //向量积:cross

    vec4 n = normalize(at - eye);

    vec4 u = normalize(vec4(cross(n, up), 0.0));

    vec4 v = normalize(vec4(cross(u, n), 0.0));

    vec4 t = vec4(0.0, 0.0, 0.0, 1.0);

    mat4 c = mat4(u, v, -n, t);

    return c * Translate(-eye);

    }

    3)本实验采用透视投影,透视投影变换矩阵由fov(视角)、aspect(投影平面长宽比)、zN(近裁剪平面)、zF(远裁剪平面) 四个参数决定的。

    核心代码:

    mat4 perspective(const GLfloat fovy, const GLfloat aspect,

    const GLfloat zNear, const GLfloat zFar)

    {

    GLfloat top = tan(fovy*DegreesToRadians / 2) * zNear;

    GLfloat right = top * aspect;

     

    mat4 c;

    c[0][0] = zNear / right;

    c[1][1] = zNear / top;

    c[2][2] = -(zFar + zNear) / (zFar - zNear);

    c[2][3] = (-2.0*zFar*zNear) / (zFar - zNear);

    c[3][2] = -1.0;

    c[3][3] = 0.0;

    return c;

    }

     

    4)本实验是在上述相机坐标系下进行的,而且所有模型都乘上了该透视投影矩阵。

     

    4、阴影的绘制及光照模型

    1)阴影变换矩阵为:

    根据光源坐标lx,ly,lz值,可求得投影在y=0平面的阴影变换矩阵为:

    mat4 shadowProjMatrix = mat4(-ly, 0.0, 0.0, 0.0,

    lx, 0.0, lz, 1.0,

    0.0, 0.0, -ly, 0.0,

    0.0, 0.0, 0.0, -ly);

     

    由于在本实验中,并不是所有物体都需要进行阴影绘制,所以要用一个变量shadowflag去判断某个模型是否需要进行阴影绘制。

    而绘制阴影需要用到黑色,所以绘制阴影时给片元着色器传入一个flag来判断要绘制的是带纹理的模型还是阴影,确定绘制颜色fcolor。

     

    2)本实验依旧采用phong光照反射模型,根据模型的顶点坐标及法向量,和光源坐标,设定好环境光反射、变量漫反射和镜面反射变量,即可确定反射光照。

    相关核心系数及计算见片元着色器文件代码:

    void main()

    {

    vec3 ambiColor = vec3(0.3, 0.3, 0.3);

    vec3 diffColor = vec3(0.7, 0.7, 0.7);

    vec3 specColor = vec3(0.4, 0.4, 0.4);

     

    // TODO 计算N,L,V,R四个向量并归一化

    vec3 N_norm = normalize(N);

    vec3 L_norm = normalize(lightPosition - V);

    vec3 V_norm = normalize(-V);

    vec3 R_norm = reflect(-L_norm, N_norm);

     

    // TODO 计算漫反射系数和镜面反射系数

    float lambertian = clamp(dot(L_norm, N_norm), 0.0, 1.0);

    float specular = clamp(dot(R_norm, V_norm), 0.0, 1.0);

    if(flagcolor==0)

    fColor = vec4(0.0, 0.0, 0.0, 1.0);

    else

    {

    float shininess = 10;

    fColor = vec4(ambiColor +

    diffColor * lambertian +

    specColor * pow(specular, shininess), 1.0) * texture2D( texture, texCoord );

    }

        fNormal = normal;

    }

     

    5、平移、缩放、旋转变换

    平移、缩放和旋转功能就是把它们对应的变换矩阵乘上当前作用点来实现。

    其中,平移、缩放、绕xyz轴旋转的变换矩阵可以直接调用函数Translate()、Scale()、RotateX()、RotateY()、RotateZ() 生成返回值。

    ①平移:

      函数:Translate(vec3(tx,ty,tz))

    ②缩放:

      函数:Scale(vec3(Sx,Sy,Sz))

    绕x轴旋转:

      函数:RotateX(theta)

    ④绕y轴旋转:

      函数:RotateY(theta)

    ⑤绕z轴旋转:

      函数:RotateZ(theta)

     

     

    三、初始场景的搭建

    1、背景颜色

    背景颜色绘制为天蓝色,代码为:glClearColor( 0.5, 0.6, 1.0, 1.0 );

     

    2、场景层次结构设计

    图 4:场景层次结构设计图

     

    由上图可见场景图层设置大概有五层,分别为:

    ①  第一层(y=-0.2):地面层

                该层地面主要由上文提到的矩形模型实现。绘制矩形图形后并进行缩放平移旋转等调整,给其赋上纹理贴图即可。

                而该层纹理贴图有四种,可根据随机函数随机选择一种贴图进行加载。

                该图层不需要绘制阴影,shadowflag判断变量要置为0 。

                部分代码如下:

            //选择贴图

            int floorimg = rand() % 4;

            if (floorimg == 0)

           str = "texture/floor.jpg";

            else if(floorimg == 1)

           str = "texture/tudi.jpg";

            else if (floorimg == 2)

           str = "texture/caodi.jpg";

            else

           str = "texture/shamo.jpg";

     

            My_Mesh* my_mesh9 = new My_Mesh;

            my_mesh9->generate_square();

            my_mesh9->set_texture_file(str);

            my_mesh9->set_translate(-1.0, -0.2, -1.5);

            my_mesh9->set_scale(2.5, 2.5, 2.5);

            my_mesh9->set_theta(180, 0, 0.);

            my_mesh9->set_theta_step(0, 0, 0);

            my_mesh9->set_shadowflag(0);

            my_meshs.push_back(my_mesh9);

        mp_->add_mesh(my_mesh9);

     

    ②  第二层(y=-0.1):游戏分数展示层

                该层地面主要由上文提到的矩形模型实现。绘制矩形图形后并进行缩放平移旋转等调整,给其赋上带有具体数字的纹理贴图即可通过贴图的方式展示分数。

    ③  第三层(y=0):阴影层

                展示模型阴影。

     

    ④  第四层(y>0):方块层

                在y=0平面上绘制方块,初始时加载obj模型绘制三个方块。其中,方块的纹理贴图有26种选择,贴图的选择同样为用随机函数随机选择。

                其中,方块具有比较重要的属性有renewflag,该变量表示该方块的编号。编号不同表示的意义为:

                renewflag=1:表示当前角色所在的方块。

                renewflag=0:角色上一个所在的方块。

                renewflag=2:角色即将要跳至的下一个方块。

                为突出跳跃目标,给renewflag=1的方块设置一个旋转变量的增量,使其每次绘制时旋转角度都加上这一增量,从而模拟出方块在自动旋转的效果。

     

                方块比较重要的属性还有direction,该变量能表示下一个方块出现的方向。如下图方块,编号表示的下一个方块出现的方向:

                

    图 5:下一个方块出现的方向及对应编号

     

    ⑤  第五层(y>0.5):角色层

                由于方块缩放后的边长为0.5,因为角色要站在方块上,所以角色层在y=0.5的平面上方。本次实验使用之前实验提供的wawa.obj来模型作为“操纵角色”。

                角色比较重要的属性有renewflag,其含义与上述方块的renewflag属性含义相同,该属性在角色中可以描述为“角色即将跳跃的方向”。

                同时,角色还有一个face属性,表示当前角色面的朝向,具体方向编号与renewflag相同。

     

    由于本项目为一个小游戏,并且许多过程都需要重载读取模型或截图信息,所以不适宜加入太多其余与游戏无关的模型,所以场景比较单调,但是这是为游戏流畅性所必需的。

     

    运行程序,初始化为(由于贴图选择具有随机性,下列展示其中三种初始化情况):

        

    图 6:初始图1

     

       

    图 7:初始图2

     

       

    图 8:初始图3

     

     

    四、键盘控制视角切换

    本实验主要是通过键盘按键调用函数改变eye的相关参数来实现视角切换的,而这种改变eye值的视角切换会使镜头围绕at参考点进行变化。

    核心代码:

    void Mesh_Painter::update_eye()

    {

    float xx = rad * cos(tAngle * DegreesToRadians) * sin(pAngle * DegreesToRadians);

    float yy = rad * sin(tAngle * DegreesToRadians);

    float zz = rad * cos(tAngle * DegreesToRadians) * cos(pAngle * DegreesToRadians);

    eye = vec4(xx, yy, zz, 1.0);

    }

    由上代码可见决定eye值参数有rad、tAngle、pAngle,键盘按键调用函数改变这三个变量值即可。

    以下相机镜头的变换都是围绕参考点进行的:

    键盘控制表如下:

    W/w:相机绕着参考点往上移(增加tAngle)

    S/s:相机绕着参考点往下移(减小tAngle)

    A/a:相机绕着参考点往左移(减小tAngle)

    D/d:相机绕着参考点往右移(增加pAngle)

    Q/q:拉远相机(增加rad)

    E/e:拉近相机(减小rad)

    Space:重开游戏

    Esc:退出程序

     

    如调整镜头后:

    图 9:调整镜头1

     

    图 10:调整镜头2

     

    五、鼠标左键按下后控制角色弹跳力度

    由代码if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) 可令其在按下鼠标左键时,触发后面的事件,这里触发的事件是使程序绑定一个空闲回调函数的对象idle2。

    该函数能不断调用当前角色所在方块的函数add_scale_step(),该函数能减小Scale缩放函数的y参数,使方块在y轴方向发生缩小变化,同时角色也会跟随着每次变化,也变化相应的位移。从而模拟角色正在像弹簧般压缩方块的动作。

    注意当压到一定的限度时则不能再往下压了。

    核心代码为:

    void

    idle2(void)

    {

    bool flag;

    /*要先判断三个方块哪个方块是当前角色所在方块,

    该方块需要y轴上的缩小,模拟类似弹簧被压缩的过程*/

    if (my_meshs[1]->get_renewflag() == 1)

    flag = my_meshs[1]->add_scale_step(-0.0004);

    else if (my_meshs[2]->get_renewflag() == 1)

    flag = my_meshs[2]->add_scale_step(-0.0004);

    else if (my_meshs[3]->get_renewflag() == 1)

    flag = my_meshs[3]->add_scale_step(-0.0004);

     

    //每次方块成功压缩一点时,角色也往下位移同等距离

    if(flag)

    my_meshs[0]->add_trans_step(0, -0.0004, 0);

     

    glutPostRedisplay();

    }

     

    //mesh.cpp

    //改变y轴方向的缩放

    bool My_Mesh::add_scale_step(float step)

    {

    if (Scale[1] > 0.2)

    {

    Scale[1] += step;

    return true;

    }

    return false;

    }

    //改变平移

    void My_Mesh::add_trans_step(float x, float y, float z)

    {

    vTranslation[0] += x;

    vTranslation[1] += y;

    vTranslation[2] += z;

    }

     

    如下图所示压缩到最大后的情景:

    图 11:方块压缩图

     

    六、鼠标左键放开,角色和方块快速复原到压缩前情景

    上述如果一直按住鼠标没放开,程序就会一直空闲调用idle2函数,模拟压缩过程,并且最后压缩到一定地步时不会再变化。

    而此时如果松开鼠标左键则会因为代码else if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)判断鼠标松开,从而执行别的事件,这里会把空闲回调函数对象切换至idle3,这样方块压缩过程就结束了。但在这之前,还要先获取方块y轴上的缩小参数,以确定压缩率,才能得知待会角色要跳多远。

    调用idle3函数后能让压缩方块和角色很快的恢复压缩前状态(该恢复过程也是动态的)后,立即切换绑定空闲回调函数对象到idle4,基本无缝接入待会角色的弹跳过程。

     

    该代码比较简单,原理与上述第五部分大致相同,因此不一一描述。

     

    七、压缩方块回弹 及 角色弹跳

    该过程比较复杂,主要内容包括:

    • 根据上一部分得到的压缩过程中得到的压缩方块的y轴上的缩小参数(范围为0.2 ~ 0.5),可确定压缩率为:

           float multiply = (0.5 - yy) / (0.5 - 0.199);   //压缩率: 0 < multiply < 1

     

    • 根据压缩率,设计算法控制跳跃时长(或者说控制跳跃帧),跳得越远,时间应该越长。

     

    • 根据跳跃方向选择相对应的位移变化,调用改变位移参数的函数即可,位移高度与长度都与压缩率成正比关系。

     

    • 如果压缩率达到了0.7,角色要有一个翻滚动作。翻滚动作实则为改变旋转矩阵参数即可改变,而角色翻滚动作的参考轴 共同取决于 角色的面朝向(face)和要跳的方向(direction)。

     

    • 模拟角色刚弹出时,原压缩方块要有一定程度的回弹,实则为y轴上小幅程度的缩放变化。该回弹缩放变化量也要与压缩率成正比关系。

     

    • 角色跳跃完成后,要进行检测,判断角色是否成功落到目标方块上(后文会详解该部分)。

     

    根据以上内容设计代码如下:

    //角色弹出 及 压缩方块回弹

    void

    idle4(void)

    {

    int direction = my_meshs[0]->get_direction();

    float d = 2.0;  //

    float multiply = (0.5 - yy) / (0.5 - 0.199);   //压缩率: 0 < multiply < 1

     

    //获取当前方块

    int i;

    if (my_meshs[1]->get_renewflag() == 1)

    i = 1;

    else if (my_meshs[2]->get_renewflag() == 1)

    i = 2;

    else if (my_meshs[3]->get_renewflag() == 1)

    i = 3;

     

    //控制跳跃时长(控制跳跃帧)。跳得越远,时间应该越长

    int multime = 500;

    float time_temp = 48.0 * multiply * multiply;

    multime = time_temp + 50;

    int face = my_meshs[0]->get_facedirect();

    int direct = my_meshs[0]->get_direction();

     

    int tt;

    float dd = 1.2;

    //初始位置到最高点过程

    if (t >= 1 && t <= multime)

    {

    //拖慢程序让弹跳时,最高点的滞空时间长一点

    tt = t*t*3;

    while (tt--)

    std::cout << "";

     

    //根据跳跃方向选择相对应的位移变化,长度和高度位移都与压缩率成正比关系

    if (direction == 0)

    my_meshs[0]->add_trans_step(0.0, dd * multiply / multime, multiply * d / (2 * multime));

    else if (direction == 1)

    my_meshs[0]->add_trans_step(multiply * d / (2 * multime), dd * multiply / multime, 0);

    else if (direction == 2)

    my_meshs[0]->add_trans_step(multiply * d / (-2 * multime), dd *  multiply / multime, 0);

    else if (direction == 3)

    my_meshs[0]->add_trans_step(0, dd * multiply / multime, multiply * d / (-2 * multime));

     

    my_meshs[i]->add_scale_step(-0.0007); //模拟角色刚弹出时,方块有一定程度的回弹

     

    //如果压缩率达到了0.7,角色要有一个翻滚动作

    if (multiply > 0.7)

    {

    //角色翻滚动作的参考轴 取决于 角色的面朝向和要跳的方向

    if (face == 3 && direct == 3)

    my_meshs[0]->add_theta(360.0 / (-2 * multime), 0.0, 0.0);

    else if (face == 2 && direct == 2)

    my_meshs[0]->add_theta(0.0, 360.0 / (-2 * multime), 0.0);

    else if (face == 1 && direct == 1)

    my_meshs[0]->add_theta(0.0, 360.0 / (2 * multime), 0.0);

    else if (face == 0 && direct == 0)

    my_meshs[0]->add_theta(360.0 / (2 * multime), 0.0, 0.0);

    else if (face == 3 && direct == 1)

    my_meshs[0]->add_theta(0.0, 360.0 / (2 * multime), 0.0);

    else if (face == 3 && direct == 2)

    my_meshs[0]->add_theta(0.0, 360.0 / (-2 * multime), 0.0);

    else if (face == 2 && direct == 3)

    my_meshs[0]->add_theta(360.0 / (-2 * multime), 0.0, 0.0);

    else if (face == 1 && direct == 3)

    my_meshs[0]->add_theta(360.0 / (-2 * multime), 0.0, 0.0);

    else if (face == 2 && direct == 0)

    my_meshs[0]->add_theta(360.0 / (2 * multime), 0.0, 0.0);

    else if (face == 0 && direct == 2)

    my_meshs[0]->add_theta(0.0, 360.0 / (-2 * multime), 0.0);

    else if (face == 0 && direct == 1)

    my_meshs[0]->add_theta(0.0, 360.0 / (2 * multime), 0.0);

    else if (face == 1 && direct == 0)

    my_meshs[0]->add_theta(360.0 / (2 * multime), 0.0, 0.0);

    }

    }

    //最高点到跳跃终点的过程

    else if (t >= (multime + 1) && t <= (2 * multime))

    {

    //拖慢程序让弹跳时最高点的滞空时间久一点

    tt = (t - (multime + 1))*(t - (multime + 1))*3;

    while (tt--)

    std::cout << "";

     

    //根据跳跃方向选择相对应的位移变化,长度和高度位移都与压缩率成正比关系

    if (direction == 0)

    my_meshs[0]->add_trans_step(0.0, dd * multiply / (-1 * multime), multiply * d / (2 * multime));

    else if (direction == 1)

    my_meshs[0]->add_trans_step(multiply * d / (2 * multime), dd * multiply / (-1 * multime), 0);

    else if (direction == 2)

    my_meshs[0]->add_trans_step(multiply * d / (-2 * multime), dd * multiply / (-1 * multime), 0);

    else if (direction == 3)

    my_meshs[0]->add_trans_step(0, dd * multiply / (-1 * multime), multiply * d / (-2 * multime));

     

    my_meshs[i]->add_scale_step(0.0007); //模拟角色刚弹出时,方块有一定程度的回弹

     

    //如果压缩率达到了0.7,角色要有一个翻滚动作

    if (multiply > 0.7)

    {

    //角色翻滚动作的参考轴 取决于 角色的面朝向和要跳的方向

    if (face == 3 && direct == 3)

    my_meshs[0]->add_theta(360.0 / (-2 * multime), 0.0, 0.0);

    else if (face == 2 && direct == 2)

    my_meshs[0]->add_theta(0.0, 360.0 / (-2 * multime), 0.0);

    else if (face == 1 && direct == 1)

    my_meshs[0]->add_theta(0.0, 360.0 / (2 * multime), 0.0);

    else if (face == 0 && direct == 0)

    my_meshs[0]->add_theta(360.0 / (2 * multime), 0.0, 0.0);

    else if (face == 3 && direct == 1)

    my_meshs[0]->add_theta(0.0, 360.0 / (2 * multime), 0.0);

    else if (face == 3 && direct == 2)

    my_meshs[0]->add_theta(0.0, 360.0 / (-2 * multime), 0.0);

    else if (face == 2 && direct == 3)

    my_meshs[0]->add_theta(360.0 / (-2 * multime), 0.0, 0.0);

    else if (face == 1 && direct == 3)

    my_meshs[0]->add_theta(360.0 / (-2 * multime), 0.0, 0.0);

    else if (face == 2 && direct == 0)

    my_meshs[0]->add_theta(360.0 / (2 * multime), 0.0, 0.0);

    else if (face == 0 && direct == 2)

    my_meshs[0]->add_theta(0.0, 360.0 / (-2 * multime), 0.0);

    else if (face == 0 && direct == 1)

    my_meshs[0]->add_theta(0.0, 360.0 / (2 * multime), 0.0);

    else if (face == 1 && direct == 0)

    my_meshs[0]->add_theta(360.0 / (2 * multime), 0.0, 0.0);

    }

    }

    //跳完

    else

    {

    my_meshs[0]->retransY(); //细微调整角色到最准确的y方向位置

    my_meshs[i]->rescale();  //细微调整压缩方块到最准确原大小

    t = 1;

    check_flag = mp_->check();  //跳跃完成后检测其是否正确跳到目标方块上

    glutIdleFunc(idle5);   //切换空闲回调函数对象

    }

    t++;

    glutPostRedisplay();

    }

     

    八、落点检测

    这一部分主要是通过获取角色和目标方块(或者原角色所在方块)的平移位移量xz来进行比较,保证角色的x和z坐标要在目标方块的一定范围内。比如,假设x、z为角色xz坐标,xx、zz为 原角色所在方块 或者 目标方块 的xz坐标,这里可以令:

    if (x <= (xx + 0.31) && x >= (xx - 0.31) && z <= (zz + 0.31) && z >= (zz - 0.31))

    判断角色是否在方块的一定范围内,根据结果返回值并把结果值赋给check_flag即可。

    结果为0表示角色没跳在任何方块上;结果为1表示角色落在原方块上;结果为2表示角色落在新方块上。

     

    原理简单,不展示代码。

     

     

    九、角色和目标方块的回弹,以及角色转向

    这一部分内容为:

    • 根据上一部分得到的检测结果,如果check_flag为1,则表示此时角色还是落在原来的方块上,则此时角色小幅度弹跳(平移。根据方块压缩率动态变化)。重新绑定回仅有重绘功能的空闲函数回调对象idle,等待下一次跳跃。
    • 如果check_flag为0,则表示角色没跳到任何方块上。此时平移掉落地上,并把gameflag设为0,表示game over,空闲回调函数的对象绑定到idle7,等待发落。
    • 如果check_flag为2,则表示角色成功跳到新方块上。此时要根据角色的face和direction属性确定要转向的角度(角色转向是为了 让角色面对的方向 能根据新方块出现的位置 而作出调整)。在角色跳落至新方块的一瞬间,模拟回弹过程,角色微微弹起(平移。平移量由压缩率决定),弹起上升过程中角色同时实行转向(旋转)。而角色回弹过程中,新方块也有回弹(y方向缩放)。完成该过程则把空闲回调函数的对象绑定到idle6。

     

    部分代码:

    //回弹和转向

    if (t >= 1 && t <= 80 && check_flag != 0)

    {

    my_meshs[0]->add_trans_step(0, 0.005 * multiply, 0); //角色落在方块上,弹跳

    if (check_flag != 1) //角色落在了新的方块上

    {

    my_meshs[0]->add_theta(0.0, 0.0, theta / 80); //弹跳上升过程中角色转向

    my_meshs[i]->add_scale_step(0.0008); //新方块回弹

    }

    }

    else if (t >= 81 && t <= 160 && check_flag != 0)

    {

    my_meshs[0]->add_trans_step(0, -0.005 * multiply, 0); //角色落在方块上,弹跳

    if (check_flag != 1) //角色落在了新的方块上

    my_meshs[i]->add_scale_step(-0.0008); //新方块回弹

    }

     

    else if (t >= 1 && t <= 50 && check_flag == 0)  //掉落地面

    {

    my_meshs[0]->add_trans_step(0, -0.5/50, 0);

    }

     

    十、旧方块下陷

    当角色成功跳到目标方块后,回调函数会变为idle6,这一部分会使旧的方块往地下陷落。旧的方块就是指renewflag为0的方块(前问提过,当前方块renewflag为1;下一个跳跃目标方块为2,上一个旧方块则为0)。

    这一部分就是普通的y轴向下逐步平移即可,无需细述。

    值得注意的是,为了不把地下方块的阴影投到y=0平面上,要把shadowflag设为0,不绘制其阴影。

    完成后空闲回调函数绑定为idle7。

     

    十一、视点跟踪

    第十部分以及第九部分的game over状态后,都会绑定idle7为空闲回调函数对象。这一部分会让相机动态平移,保持参考点仍为操纵角色,相机视角仍以角色为中心。

    这一部分原理也比较简单,根据角色的平移方向和平移量即可让相机的eye值和at值做一样的变化了。

    需要注意的是,由于“分数展示界面”要一直保持在相机镜头的固定位置,所以“分数展示界面”(实质为矩形模型)也要做同样的平移变化。

     

    完成以上操作后,这一部分还要通过gameflag来判断是否已经game over了,如果game over了则给操纵角色设置一个旋转增量,让其旋转起来,为后面的游戏结束场景做准备。空闲回调函数绑定至idle9。

    如果没有game over,则通过函数newblock()来创建一个新的方块(其实只是改变了旧方块的位置和贴图),创建成功后空闲回调函数对象绑定为idle8。

     

    十二、“创建”新方块

    该部分包括以下内容:

    • 给所有(三个)方块的renewflag编号减1,减至-1时则变为2,因为该编号的值只能为0,1,2 。
    • 编号减1后,给当前编号为1的方块停止自转,给当前编号为2的方块设置旋转增量。
    • 随机生成一个新方向,并保证不会在前一个方块的方向生成(即如果在前一个方块方向生成了则重新随机取数)。
    • 随机生成一个以当前所在方块为中点的距离。 因为游戏限定在一定区域内,如果生成方块位置超过了该区域,则要重新生成方向和距离。
    • 成功随机生成上述方向和距离数据后,把它作为平移参数赋给renewflag=2的方块(这里y坐标值要调整,要保证新方块暂时在地底下),此时便确定了新方块的位置。
    • 更新当前所在方块和角色的方向,这一方向即为即将新生成方块的方向。
    • 由于之前方块潜入地底不绘制阴影,此时要把shadowflag打开。
    • 由于是“新方块”,那么贴图就不能是之前旧的。所以此时要重新随机选取方块贴图(26种),选好后新的纹理贴图,并更新绘制。

     

        由上一部分可知,“创建”新方块这一部分函数完成后,空闲回调函数对象变为了idle8。

     

    十三、新方块由地底升起 及 回弹

    该idle8回调函数对象 对renewflag=2的方块执行y轴向上的平移操作,模拟新方块从地底冒出的动态过程。

    新方块冒出来后,立马切换空闲回调函数为idle10,对其进行回弹操作(即y轴缩放,上文多次提到“回弹”,不再细述),这样可以增加新方块“冒土”后的动感。

    操作完成后则重新把空闲回调函数的对象切换至idle,等待下轮操作。

     

    十四、游戏结束阶段

    在第十一部分“视点跟踪”部分判断gameflag是否为0,是0则表示game over,除了对角色模型设置旋转增量使其自转外,还立马把空闲回调函数对象切换至idle9函数。

    这一部分的内容有:

    • 对角色模型进行向上的动态平移(保证会移出默认的相机视野外),此时场景就会变为:角色模型落在地上后,螺旋上升直到移出相机视野。
    • 三个方块都动态往地底下陷落(平移)。
    • 地面上会新浮现出两个矩形图形,分别是——贴图写着“Game Over”的矩形 以及 “press“space”restart”的矩形。    而这两个矩形是初始化过程中就已经创建好了的,只不过正常游戏时,它们都在地面下方,被地面掩盖住了看不到,而在游戏结束阶段则会平移上来。(相机视野变换过程中这两个矩形图形也会做一样的平移)
    • 以上角色模型和方块模型的shadowflag都设为0,不绘制阴影。

     

    游戏结束例图如下:

       

    图 12:game over图

     

    十五、其他注意事项及说明

    1、空格键重新开始游戏

            重新开启游戏其实就是把存储绘制图形的数组的信息都给清除,如my_meshs.clear(),把空闲回调函数对象设为初始的idle,同时把eye和at等相关数据值都设为初始值,再对模型进行初始读取载入绘制即可。

    2、设置按下鼠标后的标志mouseflag和模型运动的标志moveflag。

            设置这些标志能有效保证程序游戏能够正常的运行,而不会出现一些奇怪的bug。比如,物体运行过程中,moveflag为1,此时按下鼠标左键,程序会判断moveflag,为1则表示在运动,无法执行按下鼠标后的操作,这样就保证程序能正常执行逻辑。  当模型运动完后moveflag就会设为0 。

            同理,为尽量避免bug也要设置mouseflag,比如我们已经知道当物体运动时按下鼠标左键是没有后续事件响应的,而此时如果物体运动完了松开鼠标左键,就会因为没进行“方块压缩”过程而发生后续操作,产生逻辑错误。   当按下鼠标左键mouseflag赋值为1,松开鼠标左键后要判断mouseflag是否为1才能执行后续操作,如果为1则执行后续操作并把mouseflag再设回为0 。

            空格重启游戏时也要对这些标志变量进行初始化。

    3、得分设计。

    得分score从0开始,每次成功跳到目标方块后,则增加scoremul。

    而scoremul初始为1,每当角色模型落在离目标方块很近的地方时(距离差小于成功落点的距离差),则+1 。

    比如说,该实验中,个人设定落点成功的判定范围见该语句:

    if (x <= (xx + 0.31) && x >= (xx - 0.31) && z <= (zz + 0.31) && z >= (zz - 0.31)

    而scoremul+1的距离判定范围见该语句:

    if (x <= (xx + 0.05) && x >= (xx - 0.05) && z <= (zz + 0.05) && z >= (zz - 0.05))

     

    而当落点成功却没落在该scoremul+1的指定范围内时,scoremul重置为1 。

     

    程序每次算完得分后,就会在当前该函数内根据得分去重新选择读取载入相对应的数字纹理贴图以更新 分数展示界面。

     

     

    展开全文
  • 第三章 需求分析 一 . 填空题 1. 需求分析步骤 , , , 2. 需求分析阶段需编写文档有 3.... 对于计算机程序处理数据其数据域应包括 , , 和数据结构 6. 数据内容即是 7. 把一个功能分解成几个子功能并确定 ,
  • 试问这时由哪一个计算机使用ARP响应分组将计算机B硬件地址告诉计算机A? 问题4-25:有人将ARP列入网络接口层,即认为ARP不在IP层,这样对吗? 问题4-26:一个主机要向另一个主机发送IP数据报。是否使用ARP就可以...
  • 程序应简单、清晰、可读性好 B. 符号名命名要符合语法 C. 充分考虑程序执行效率 D. 程序注释可有可无 (25) 下面对对象概念描述错误是(A) 注:P55 A. 任何对象都必须有继承性 B. 对象是属性和方法封装体 C...

空空如也

空空如也

1 2 3 4 5 ... 18
收藏数 342
精华内容 136
关键字:

一个计算机程序应包括的内容