分类
未分类

3ds Max 教程动画教程:使太空战斗机飞行

使太空战斗机飞行

在本教程中,将使用路径约束设置太空战斗机的动画,使其沿简单路径飞行。还将引导如何混合路径。

素材下载
 
 

>>添加和调整飞行路径

在第一个练习中,将为太空战斗机指定路径约束并使其沿路径飞行。还将设置一些路径参数,以改进太空战斗机的飞行动态。

设置课程: 

加载素材文件夹中的 flyingspacefighter.max 文件。

 该场景包括下列各项:

  • 一个名为 SpaceFighter 的太空船。
  • 一条路径 Path01
  • 一个名为 SpaceCam 的(隐藏)摄影机。

 

一、指定路径约束: 

  • 在“顶”视口中选择 SpaceFighter 对象。
  • 打开“动画”菜单,并选择“约束”>“路径约束”。 在太空战斗机和光标之间连接了一条虚线。
  • 单击绿线 Path01。一旦选择了该路径,太空战斗机将跳到该路径的起点。(任何样条线都可以成为动画路径。)同样,命令面板将自动切换到“运动”面板。
  • 如有必要,从“运动”面板中向上滑动卷展栏,直到可以看到所有的“路径参数”卷展栏。您将看到 Path01 已经添加到路径列表中。
  • 激活“SpaceCam”视口并播放动画。太空战斗机会沿路径飞行,但其朝向不正确。
  • 在“路径参数”卷展栏的“路径选项”组中,设置下列内容:(可以在播放动画时更改设置)·启用“跟随”:太空战斗机会沿着路径飞行,并且当路径弯曲时它也会转弯,但它垂直于运动路径。
    ·在“轴”组中,将轴更改为 Y 轴:太空战斗机将重新确定方向并朝向路径方向,但它是向后飞行的。
    ·启用“翻转”:太空战斗机此时的朝向是它沿路径飞行的方向。
  • 再次播放动画。现在太空战斗机将沿路径正确地飞行,但其飞行动态看起来不逼真。

 

二、改进飞行特性

 在本部分中,将改进太空战斗机的飞行特性。将使它在进入和退出转弯时移动得更逼真。

使飞行更逼真: 

  1. 启用“倾斜”,并再次播放动画(如果动画仍未播放)。现在当太空战斗机飞过转弯时它会倾斜。但是,运动难以察觉;它需要变得更明显。您将使用“倾斜量”和“平滑度”设置,以使太空战斗机看起来像是在路径转弯中倾斜一样。
  2. 将“倾斜量”设置为 7.0。“倾斜量”控制对象向其前进路径的任意一侧倾斜的程度。如果您是坐在驾驶员座舱中,则正值使太空战斗机向左倾斜,负值使其向右倾斜。请注意所设置的“倾斜量”的大小。如果值太高,太空战斗机会整个翻转过来。请试验不同的设置,并在继续操作之前将其恢复为 7.0。
  3. 将“平滑度”设置为 1.0。平滑度控制太空战斗机在经过路径中的转弯时发生倾斜的快慢程度。较小的值使对象对曲线的变化反应更灵敏,而较大的值则会消除突然的转折。太空战斗机的飞行更平滑,因为它完成转弯时会校正自身。尝试增加和降低“平滑度”的值来观察结果。
  4. 将场景另存为 MySpaceFighter01.max

 

三、设置太空战斗机路径的动画

 您可以模拟路径参数设置以获取更多动态的动画.。在本节中,您将通过模拟一些设置更改为操作添加一些戏剧效果。

  设置路径参数的动画: 

  1. 将时间滑块移至第 60 帧。
  2. 启用“自动关键点”,并将“倾斜量”设置为 6.0  您将看到在时间线的第 60 帧处添加了一个新关键点。
  3. 将时间滑块滑动到 75,并将“倾斜量”设置为 12.0
  4. 禁用“自动关键点”并播放动画。当太空战斗机进入第二个弯道时,它转弯时剧烈地摇摆,好像在躲避导弹或避开激光。
  5. 将场景另存为 MySpaceFighter02.max

 

四、混合路径

到目前为止,您使用的是单一路径。3ds Max 允许沿着多条路径集成运动,这会得到一些有趣的运动效果。

设置课程: 

打开文件 flyingspacefighter02.max

 

 该场景包括下列各项:

 

  • 一个名为 SpaceFighter 的太空船。 
  • 两条路径 Path01(绿色)和 Path02(红色)。 
  • 一个名为 SpaceCam 的摄影机(隐藏)。

 

使太空战斗机沿混合路径飞行: 

  1. 选择 SpaceFighter,并打开“运动”面板。太空战斗机已被约束到 Path01
  2. 在“路径参数”卷展栏中,单击“添加路径”按钮。
  3. 选择红色路径 Path02。太空战斗机在两条路径之间的中途是如何确定位置的。这是因为每条路径都同等程度地影响太空战斗机。
  4. 再次单击“添加路径”按钮以将其禁用。
  5. 激活 SpaceCam 视口(如果其尚未激活),并播放动画。“权重”设置控制太空战斗机受每条路径影响的程度。
  6. 在“路径参数”对话框的路径列表中,高亮显示 Path01 项并将其“权重”值(紧邻列表下方)设置为 25.0
  7. 再次播放动画。太空战斗机跟随 Path02 的程度更紧密一些,因为它的权重比 Path01 大。为每条路径试验不同的“权重”设置并观察结果。
  8. 将场景另存为 MySpaceFighter03.max

 

 

>>用约束和控制器设置太空战斗机的动画

在本课程中,将对执行任务的太空战斗机飞行编队使用多种约束和控制器。

设置课程: 

打开 flyingspacefighter03.max

场景已经包含下列内容:

 

  • 由三架太空战斗机 FlightLeader、Wingman01Wingman02 组成的飞行编队。 
  • 虚拟对象 SpaceshipControl。 
  • 两条运动路径:flightpath(可见)和 wingmanpath(隐藏)。 
  • 摄影机(隐藏)SpaceCam

 

一、使用虚拟对象控制飞行编队

虚拟对象是辅助对象。您可以在“创建”面板中的“辅助对象”按钮创建它们。当设置动画时,它们是很有用的。通过设置虚拟对象的动画,可以专注于用非常简单的对象设置运动,而不会降低系统的速度。一旦完成了虚拟对象的动画,就可以将对象链接到虚拟对象上。现在将虚拟对象移到哪,对象就移到哪。

将太空战斗机链接到虚拟对象: 

  1.  激活“顶”视口(如果其尚未激活),并从主工具栏中单击“选择并链接”按钮。
  2. 选择 FlightLeader,并将光标拖动到虚拟对象 SpaceshipControl 上。松开鼠标按钮。FlightLeader 现在已链接到 SpaceshipControl。无论您将 SpaceshipControl 移动到何处,FlightLeader 都会随之移动。
  3. Wingman01Wingman02 都链接到 SpaceshipControl

 

为虚拟对象添加路径约束: 

  1. 在“顶”视口中,使用“最大化显示”查看场景。
  2. 单击“选择对象”将其启用,并且禁用“选择并链接”。
  3. 选择 SpaceshipControl
  4. 从“动画”菜单中,选择“约束”>“路径约束”。拖动光标并单击 flightpathSpaceshipControl 会跳到路径的起点。太空战斗机会随之移动,因为它们已经链接到虚拟对象。
  5. 在“路径参数”卷展栏中,进行下列设置。
    • 启用“跟随”、“倾斜”和“恒定速度”。
    • 在“轴”组中,启用“Y”和“翻转”。
    • 将“倾斜量”设置为 7.0,将“平滑度”设置为 1.0
  6. 激活“SpaceCam”视口并播放动画。所有三架太空战斗机都将沿 flightpath 移动。
  7. 将场景另存为 MyFlight01.max

 

  

二、使摄影机跟随运动

在本练习中,将使用“链接约束”使摄影机在飞行编队掠过时跟随它们。从上一课继续,或打开 flyingspacefighter04.max

为摄影机添加链接约束:  
  1. 打开“显示”面板,并禁用“按类别隐藏”卷展栏中的“摄影机”。摄影机 SpaceCam 将出现。
  2.  在“顶”视口中,使用“最大化显示”查看场景。选择摄影机目标。同时确保将时间滑块设置为第 0 帧(零)。
  3. 从主菜单中,选择“动画”>“约束”>“链接约束”。单击 flightpath 以在第 0 帧(零)设置第一个链接参数。 (注意:为了执行该步骤以及以下步骤,需要启动自动关键点,因为链接约束处于活动状态。)
  4. 将时间滑块移动到第 80 帧,并单击“链接参数”卷展栏中的“添加链接”按钮。单击 SpaceshipControl
  5. 单击“添加链接”将其禁用。
  6. 激活“SpaceCam”视口并播放动画。 摄影机目标链接到从第 0 帧到第 79 帧的 flightpath。在第 80 帧处,摄影机目标开始特别追踪 SpaceshipControl 对象。
  7. 将场景另存为 MyFlight02.max

 

三、飞行编队队长过于自信

您的飞行编队队长非常大胆。当飞行编队从 SpaceCam 的最佳视点掠过时,他或她觉得应该做一个 V 型滚转。在本练习中,将使用“方向约束”控制飞行编队队长的太空战斗机在表演桶滚的旋转。从上一课继续,或打开 flyingspacefighter05.max

  1. 在“顶”视口中,使用“缩放区域”查看三架太空战斗机。
  2.  在“创建”面板上单击“辅助对象”,然后单击“虚拟对象”。在 FlightLeader 旁边创建一个新的虚拟对象,并将其命名为 barrelroll
  3.  单击“选择并链接”,将 barrelroll 链接到 SpaceshipControl
  4. 从“工具”菜单中选择“对齐”,然后单击 SpaceshipControl。 将出现“对齐当前选择 (SpaceshipControl)”对话框。
  5. 在“对齐位置(屏幕)”组中,禁用 X、Y 和 Z 位置。
  6. 在“对齐方向(局部)”组中,启用“X 轴”、“Y 轴”和“Z 轴”控件,并单击“确定”。 barrelroll 虚拟对象具备与 SpaceshipControl 相同的方向。
  7.  在“运动”面板上,打开“指定控制器”卷展栏(如果其未打开),并选择“旋转:Euler XYZ 控制器。
  8.  单击“指定控制器”按钮,并从“指定旋转控制器”对话框中选择“TCB 旋转”。 (注意:不要遗漏本步。它允许您沿着本地 Y 轴旋转 barrelroll 虚拟对象。)

 

设置 V 型滚转的动画: 

  1. 在“顶”视口中选择 FlightLeader
  2. 打开“动画”菜单,并选择“约束”>“方向约束”。将光标移动到 barrelroll 虚拟对象上并选择它。您会看到 barrelroll 被添加到“运动”面板上的“方向约束目标”列表中。
  3. 选择 barrelroll,并确保时间滑块位于第 0(零)帧。
  4. 启用“设置关键点”切换,并单击“设置关键点”按钮。
  5. 将时间滑块移到第 110 帧,并再次单击“设置关键点”。您已经添加了两个关键点,它们会使 FlightLeader 正常地从第 0 帧飞行到第 110 帧。
  6. 激活 SpaceCam 视口,并将时间滑块移动到第 130 帧。
  7. 单击“选择并旋转”,并将“参考坐标系”更改为“局部”。
  8. 单击 barrelroll 虚拟对象并将其绕 Y 轴旋转大约 180 度,然后单击“设置关键点”按钮。
    注意如果希望精确一些,则可以在状态栏上的 Y 轴输入字段中输入旋转度数。
  9. 将时间滑块移动到第 150 帧,并将 barrelroll 虚拟对象绕 Y 轴旋转另一个 180 度,然后单击“设置关键点”按钮。完成后,禁用“设置关键点”切换。
  10. 将场景另存为 MyFlight03.max,并播放动画。

 

四、遇到麻烦的僚机

FlightLeader 表演特技时,Wingman01 好像遇到了一些麻烦。他看起来不像其他人飞行得那样平稳。在本练习中,将使用“噪波”控制器为 Wingman01 的飞行动态添加一些湍流。从上一课继续,或打开 flyingspacefighter06.max

注意如果从上一课继续,请确保时间滑块已返回到第 0(零)帧。

添加湍流: 

  1. 在“顶”视口中,使用“缩放区域”查看三架太空战斗机(如果尚未执行该操作)。您可能必须先使用“最大化显示”,再使用“缩放区域”来查看三架战斗机。
  2. 选择 Wingman01
  3. 在“动画”菜单上,选择“位置控制器”>“噪波”。执行该操作会为 Wingman01 自动添加“列表”控制器。“位置列表”包含原始的“线性位置”和新的“噪波位置”控制器,它们的默认“权重”设置为 100.0%。
  4. 播放动画,并注意 Wingman01 的无规律飞行。
  5. 停止播放,并将“噪波位置”控制器的“权重”更改为 25.0%。现在 Wingman01 太空战斗机的飞行路径会受到轻微战斗损伤的影响。
  6. 将场景另存为 MyFlight04.max

 

五、调离僚机

现在看起来 Wingman02 好像收到一条信息,并正准备奉命离开编队飞往别处。您将重新访问“链接约束”,以便让 Wingman02 跟随 FlightLeader 飞行一小会儿,然后飞往另一条路径。从上一课继续,或打开 flyingspacefighter07.max

为 Wingman02 更改路线:  

  1. 将时间滑块重置为第 0 帧(零),并在“顶”视口中缩放到三架太空战斗机。
  2. Wingman02 旁边创建一个虚拟对象,并将其命名为 WingmanControl
  3. 右键单击任意视口,并从四元菜单中选择“按名称取消隐藏”。选择 wingmanpath 并单击“取消隐藏”。 在 Wingman02 前面会出现一条黄色的路径。
  4. 确保新的虚拟对象,WingmanControl 仍处于选定状态,然后从“动画”菜单中选择“约束”>“路径约束”。将光标拖动到 wingmanpath 上并拾取它。 WingmanControl 会跳到 wingmanpath 的起点。
  5. 在“路径参数”卷展栏中复制先前的设置。
  • 启用“跟随”、“倾斜”和“恒定速度”。 
  • 在“轴”组中,启用“Y”和“翻转”。
  • 将“倾斜量”设置为 7.0,将“平滑度”设置为 1.0。如果播放动画,会看到 WingmanControl 在它自己的路径上。
    提示:为了更好地观看 Wingman02 飞走,请转至第 0 帧并播放动画,激活 SpaceCam 视口,启用“视野导航”按钮并向下拖动 SpaceCam 视口直到 0 帧,您可以在视口的右边看见 wingmanpath 的整个环以及一点 FlightLeader

 

 

使 Wingman02 更改路径: 

  1.  在“顶”视口中,选择 Wingman02,并单击“断开当前选择链接”按钮。Wingman02 将不再链接到 SpaceshipControl 虚拟对象上。
  2. 从“动画”菜单中选择“约束”>“链接约束”,并选择 SpaceshipControlWingman02 会像以前一样飞行,但链接约束为您提供了灵活性,可以让它跟随不同的路径。
  3. 将时间滑块移动到第 45 帧,并单击“运动”面板上的“链接参数”卷展栏中的“添加链接”按钮。
  4. 单击 WingmanControl 虚拟对象。您将看到 WingmanControl 已添加到“目标”列表中,并且当 Wingman02 到达第 45 帧时,太空战斗机开始跟随 WingmanControl 虚拟对象到另一条路径上。
  5. 将场景另存为 MyFlight05.max,并播放动画。

 

使 Wingman02 滚转出编队: 

若要使 Wingman02 滚转出编队,您将再次使用“方向约束”。

  1. 如果时间滑块不在第 0 帧,将其移动回第 0 帧(零)。
  2. 在“顶”视口中的 Wingman02 旁边创建另一个虚拟对象,并将其命名为 wingmanroll
  3. 使用“选择并移动”将 wingmanroll 放置在 Wingman02 旁边。观察“前”和“右”视口以帮助您放置它。这将有助于您在场景中有组织地放置对象。
  4. 单击“选择并链接”,将 wingmanroll 链接到 WingmanControl
  5. 从“工具”菜单中选择“对齐”,然后单击 WingmanControl。将出现“对齐当前选择 (WingmanControl)”对话框。
  6. 在“对齐方向(局部)”组中,确保禁用“X 轴”、“Y 轴”和“Z 轴”位置控件
  7. 在“对齐方向(局部)”组中,启用“X 轴”、“Y 轴”和“Z 轴”控件,并单击“确定”。wingmanroll 虚拟对象会与 WingmanControl 对齐。
    注意:这是很重要的,因为要确保稍后赋予 wingmanroll 的旋转值将基于 WingmanControl 的初始方向。否则,赋予 wingmanroll 的任何旋转值会导致太空船的翻转失去控制。
  8. 在“运动”面板上,打开“指定控制器”卷展栏,并选择“旋转:Euler XYZ 控制器。
  9. 单击“指定控制器”按钮,并从“指定旋转控制器”对话框中选择“TCB 旋转”。
    注意:如果未指定“TCB 旋转”控制器,将无法使 wingmanroll 绕局部轴旋转。
  10. 在“顶”视口中选择 Wingman02
  11. 打开“动画”菜单,并选择“约束”>“方向约束”。将光标移动到 wingmanroll 上并选择它。您会看到 wingmanroll 被添加到“运动”面板上的“方向约束”卷展栏中的“方向约束”目标列表中。
  12. 在“顶”视口中选择 wingmanroll
  13.  启用“设置关键点”切换,并单击“设置关键点”按钮。
  14. 将时间滑块移到第 60 帧,并再次单击“设置关键点”。您已经添加了两个关键点,它们会使 Wingman02 正常地从第 0 帧飞行到第 60 帧。
  15. 激活 SpaceCam 视口,并将时间滑块移动到第 85 帧。
  16. 单击“选择并旋转”,并将“参考坐标系”更改为“局部”。
  17. 在这一步中要创建两个旋转:
    • 在“X 轴坐标显示输入”字段中输入 -15,并单击“设置关键点”按钮。
    • 在“Y 轴坐标显示输入”字段中输入 90,并单击“设置关键点”按钮。
  18. 将时间滑块移动到第 100 帧,以执行下面两个旋转:
    • 绕 Z 轴旋转 5 度,并单击“设置关键点”按钮。
    • 绕 Y 轴旋转 90 度,并再次单击“设置关键点”按钮。
  19. 将时间滑块移动到第 115 帧,以执行下面两个旋转:
    • 绕 Z 轴旋转 10 度,并单击“设置关键点”按钮。
    • 绕 Y 轴旋转 90 度,并再次单击“设置关键点”按钮。
  20. 完成后,禁用“设置关键点”切换。将场景另存为 MyFlight06.max,并播放动画。

 

>>控制火星及其卫星与空间站

到目前为止,您已经使用过虚拟对象来帮助设置太空战斗机的动画。虚拟对象另一个方便的用途是作为可选用的轴点。任何对象都可用作轴点,但虚拟对象最适合,因为它们不渲染。

设置课程: 

打开 spacestation.max 文件。

该场景包括下列各项:

  • 三个天体,Mars 和它的两个卫星,DeimosPhobos
  • 一个名为 SpaceStation 的太空站
  • 一台名为 SpaceCam 的(隐藏)摄影机

请花一点时间熟悉场景中的对象的名称。这将使您在学习该课程的过程中更容易选择对象。

旋转火星及其卫星: 

该课程的第一部分只涉及您在场景中看到的三个天体。您将设置虚拟对象来控制火星和它的卫星 Deimos 和 Phobos 的旋转。

  1. 在“左”视口中的火星周围创建一个虚拟对象。将虚拟对象命名为 MarsControl。使得虚拟对象比行星稍大从而更容易拾取。
  2. 在保持选定虚拟对象的情况下,选择“工具”菜单 >“对齐”并单击 Mars
  3. 在“对齐当前选择 (Mars)”对话框中,执行下列操作:
    • 在“对齐位置(屏幕)”组中启用“X 位置”、“Y 位置”和“Z 位置”。
    • 在“对齐方向(局部)”组中启用“X 轴”、“Y 轴”和“Z 轴”。
    • 单击“确定”以接受设置。 

    MarsControl 现在与火星的中心对齐并以火星的中心定位。
     

  4. 选择 MarsControl
  5. 转至“运动”面板并展开“指定控制器”卷展栏。选择旋转:Euler XYZ。 
  6. 单击“指定控制器”按钮并选择“TCB 旋转”然后单击“确定”。“TCB 旋转”可以使对象绕它们的“局部”轴旋转,而不是“世界”轴。当您的对象绕倾斜轴(例如某个行星的旋转轴)旋转时,这很有用。
  7. 选择 Mars,然后单击“选择并链接”。将橡皮圈拖动到 MarsControl。当光标改变时松开鼠标按钮。
  8. 将两个卫星 DeimosPhobos 链接到 MarsControl。火星和它的两个卫星现在已经链接到 MarsControl 上。您对 MarsControl 所作的任何移动或旋转将会影响所有的行星体。
  9. 单击“选择并旋转”,然后选择 MarsControl
  10. 将“参考坐标系”从“视图”更改为“局部”。
  11. 启用“自动关键点”按钮并将时间滑块移动到第 100 帧。
  12. 在时间滑块下面的 Z 轴字段中,输入 60。 这将使 MarsControl 绕其局部 Z 轴旋转 60 度。因为行星和卫星已链接到 MarsControl 上,所以它们也会旋转。
  13. 禁用“自动关键点”,并将您的工作另存为 MySpaceStation
  14. 激活“SpaceCam”视口并播放动画。您将看到火星绕其轴旋转;然后,在第 60 帧时,Deimos 旋转着进入视图并掠过火星,但在摄影机中仍然看不到 Phobos。如果您愿意的话,您可以缩小显示以在播放时看到两颗卫星。
  15. 在继续下一步之前将时间滑块返回到第 0 帧。

 

将空间站放入轨道中: 

由于火星绕它自己的轴自旋,Deimos 和 Phobos 绕火星运行,您可以将空间站放入一条环绕火星的同步轨道(与该行星的旋转保持一致的轨道)中。您将使用相同的方法来控制空间站。

  1. 在“顶”视口中添加一个新虚拟对象,并将其命名为 StationControl。您在哪放置虚拟对象都没有关系,因为几个步骤之后将使它与火星对齐。
  2. 打开“运动”面板上的“指定控制器”卷展栏,并选择“旋转:Euler XYZ。
  3.  单击“指定控制器”按钮,并选择“TCB 旋转”。单击“确定”。
  4. 在保持选定 StationControl 的情况下,选择“工具”菜单 >“对齐”并单击 Mars
  5. 在“对齐当前选择 (Mars)”对话框中,执行下列操作:
    • 在“对齐位置(屏幕)”组中启用“X 位置”、“Y 位置”和“Z 位置”。
    • 在“对齐方向(局部)”组中启用“X 轴”、“Y 轴”和“Z 轴”。
    • 单击“确定”以接受设置。

    这与您在上一节中将 MarsControl 与火星对齐时所作的设置相同。

  6.  在“左”视口中,将 SpaceStation 链接到 StationControl
  7.  启用“选择并旋转”,然后选择 StationControl。如果“参考坐标系”还没有更改的话,将其从“视图”更改为“局部”。
    提示您必须始终在选择“参考坐标系”之前选择变换(在该例中为“选择并旋转”)。不同的变换可以有不同的“参考坐标系”。如果您先选择坐标系,当您选择其他变换时坐标系可能会改变。
  8.  启用“自动关键点”按钮并将时间滑块移动到第 100 帧。
  9. 在时间滑块下面的 Z 轴字段中,输入 40。 
  10. 禁用“自动关键点”,并将您的工作另存为 MySpaceStation01。若要创建增量保存文件,请使用“另存为”命令,单击“ +”按钮。
  11. 播放动画。现在空间站绕火星运行,但它运行的速度较低。

 

为空间站添加人造重力: 

要为全体人员生成一定级别的人造重力,空间站必须绕其轴自转。最后一节将解决这个问题。

  1. 在“SpaceCam”视口中,选择 SpaceStation 并打开“运动”面板。
  2. 打开“指定控制器”卷展栏并选择“旋转:Euler XYZ。
  3.  单击“指定控制器”按钮并选择“TCB 旋转”然后单击“确定”。
  4.  如果“选择并旋转”没有激活,则启用它。将“参考坐标系”从“视图”设置为“局部”。 
  5.  启用“自动关键点”按钮并将时间滑块移动到第 100 帧。
  6. 在时间滑块下面的 Z 轴字段中,输入 90
  7. 禁用“自动关键点”。
  8. 播放动画。 现在空间站在环绕火星的同步轨道中运行的同时,也绕它自己的轴旋转。最大化“SpaceCam”视口以更好地查看。
  9. 将工作另存为 MySpaceStation02
分类
3ds Max

3DS MAX 2009 之动画教程

3DS MAX 2009 之动画教程

对动画师新手来说,反弹球是常用的第一个项目。此经典示例是 3ds Max 中用于说明基本动画过程的绝好工具。

素材下载

 

>>使用自动关键点设置动画:反弹球

在本教程中,您将学习如何执行下列操作:

  • 使用变换创建动画。
  • 在轨迹栏中复制关键点。
  • 使用重影来显现中间帧。
  • 使用“功能曲线编辑器”中的切线控制柄控制中间帧。
  • 使用参数超出范围类型创建循环动画。
  • 使用虚拟对象设置动画。
  • 使用“布局”模式。
  • 应用增强曲线。
  • 使用“摄影表编辑器”加速动画和反转时间。
  • 使用“设置关键点”模式设置动画。

一、使用“自动关键点”创建动画

在本课程中,您将开始学习如何在 3ds Max 中制作动画。

设置课程: 

  1. 选择“文件”>“打开”,打开素材中的 bounce_start.max。
  2. 单击“自动关键点”,启用此功能。“自动关键点”按钮和时间滑块背景变成红色,表示您处于动画模式中。视口的轮廓也变成红色。现在,当您移动、旋转或缩放对象时,将自动创建关键帧。
  3. 在“透视”视口中单击以选择球。它将显示为被白色的选择框包围,表明已将其选定。
  4. 右键单击球,并从四元菜单的“变换”区域中选择“移动”。变换 Gizmo 出现在视口中。使用变换 Gizmo 可以轻松地执行受约束的移动。当在变换 Gizmo 上移动光标时,不同的轴及其标签会变成黄色。
  5. 将鼠标光标放在 Z 轴上,当其变成黄色后,单击并向上拖动将球提升到空中。在您执行该操作时,将创建位置关键点。关键点显示在轨迹栏上。
  6. 将时间滑块移至第 15 帧。若要将球精确地向下移动到桌子表面,请将光标放在坐标显示的 Z 字段中,并将值更改为 0。
  7. 将鼠标放在时间滑块的帧指示器上(灰色方框,当前读数 15/100),并单击右键。
  8. 在弹出的“创建关键点”对话框中,将“源时间”更改为 1 并将“目标时间”更改为 30,然后单击“确定”。这将复制从第 1 帧到第 30 帧的关键点。
  9. 单击“播放动画”,或将时间滑块在第 1 帧到第 30 帧之间来回拖动可播放动画。球在第 1 帧和第 30 帧之间上下移动,并在第 30 帧到第 100 帧之间的空中停留不动。
  10. 如果单击了“播放动画”,请单击“停止”(同一按钮)以结束播放。下一步,要将活动时间段的长度设置为 30 帧。
  11. 在时间控件中,单击“时间配置”。
  12. 在“时间配置”对话框 >“动画”组中,将“开始时间”设置为 1,“结束时间”设置为 30不要 单击“重缩放时间”按钮。单击“确定”。活动时间段是较大动画的一部分。在此,您是将第 0 帧到第 30 帧作为活动时间段。请注意,时间滑块此时只显示这些帧。其他帧仍然存在,只不过它们此刻不是活动时间段的一部分。
  13. 播放动画。球会上下移动。因为第一帧和最后一帧相同,所以动画播放时看起来像是来回循环。但仍没有“反弹”。
  14. 停止动画播放。

 

二、控制中间帧

若要使球反弹更真实,需要更改第 15 帧关键点上的插值。您将使用“曲线编辑器”上的切线控制柄。曲线的切线将确定中间帧的空间位置。使用“重影”可以看到中间帧被放置的位置。

使用重影来显现中间帧:

  1. 将时间滑块移至第 15 帧。
  2. 在“视图”菜单中单击“显示重影”以启用该功能。
  3. 转至“自定义”菜单 >“首选项”>“视口”选项卡,将“重影帧”设置为 4,并将“显示第 N 帧”设置为 3。单击“确定”退出该对话框。
  4. 播放动画,然后停止。
  5. 现在,若要控制中间帧,请在视口中右键单击球并选择“曲线编辑器”。“曲线编辑器”由两个窗口组成,左侧的“控制器”窗口用于显示轨迹的名称,右侧的“关键点”窗口用于显示关键点和曲线。
  6. 在左侧的“控制器”窗口中,单击以仅选择 Z 位置轨迹。此时,“关键点”窗口中显示的唯一曲线就是您要操作的曲线。
  7. 移动轨迹视图的时间滑块(“关键点”窗口中的浅绿色双线)。如果仔细观察,会发现在第 15 帧的曲线上有一个黑点。
  8. 围绕黑点(位置关键点)拖动以选择它。选定的关键点在曲线上变成白色。现在可以使用切线控制柄操纵曲线。要访问控制柄,必须更改切线类型。
  9. 在“轨迹视图”工具栏上,单击“将切线设置为自定义”。如果仔细观察,会发现曲线上出现了一对黑色的切线控制柄。
  10. 按住 Shift 键,并在“关键点”窗口中将左侧的左控制柄向上拖动。使用 Shift 键可以独立于右控制柄操纵左控制柄。

 

使用交互式更新: 

  1. 在“轨迹视图选项”菜单中启用“交互式更新”。此时将时间滑块移动到第 15 帧,然后操纵切线控制柄,同时观察重影中的效果。当您进行操作时,可以清楚地看到变化。
  2. 设置切线控制柄,以便在大多数情况下将中间帧朝提升位置拖曳(请参见下图)。如果启用了交互式更新,则可以使用非常精细的控制来执行该操作。
  3. 将时间滑块移动到第 30 帧,然后调整右切线控制柄,使其与左控制柄大致相称。通过操纵该控制柄,可以获得不同的效果。球从桌面反弹时的向上运动将确定对于球重量的感知。如果两个控制柄类似的话,球看起来很有弹性,像网球一样。如果足够多的中间帧被拉近到顶端位置,则球看起来像悬在空中。
  4. 禁用“视图”>“显示重影”,然后播放动画。请注意球的运动。当播放动画时,进一步调整曲线控制柄,并观察效果。
  5. 播放动画,然后停止。此时球具有弹跳运动。看起来重力在起作用。
  6. 将工作另存为 mybounce.max。当您在视口中看到令人满意的内容时,这即是应保存工作的提示。因为当您充满创意时很容易忘记保存。

 

三、添加参数曲线超出范围类型

可以使用多种方法不断重复一连串的关键点,而无须制作它们的副本并将它们沿时间线放置。在本课程中,会将“参数曲线超出范围类型”添加到球的位置关键点。使用“参数曲线超出范围类型”可以选择在当前关键点范围之外重复动画的方式。其优点是,当对一组关键点进行更改时,更改会反映到整个动画中。

重复关键帧运动: 

  1. 从上一课继续,或打开 bounce_repeat.max。这是一个 3ds Max 场景,其中球反弹一次。
  2. 如果未显示“曲线编辑器”,请在任意视口中选择球,然后右键单击,从四元菜单中选择“曲线编辑器”。
  3. 在“控制器”窗口中,确保仅选择了 Z 位置轨迹。 在您重复关键帧之前,需要延伸动画的长度。
  4. 单击“时间配置”。该按钮位于动画播放控件中的“转至结尾”按钮下,动画播放控件位于界面(而不是“轨迹视图”)的右下角。
  5. 将“动画”>“结束时间”更改为 120。这会在现有的 30 帧基础上添加 90 个空白帧。而不会将 30 帧拉伸为 120 帧。这样每次球经过第 1 帧到第 30 帧便反弹一次。
  6. 现在返回到“轨迹视图”,单击工具栏上的“参数曲线超出范围类型”按钮。
  7. 单击“周期”图下面的两个框,为“输入”和“输出”选择“周期”方式。单击“确定”。
  8. 单击轨迹视图窗口右下角的“导航:轨迹视图”工具栏上的“水平方向最大化显示”。“关键点”窗口将缩小,以便可以看到整个时间段。参数超出范围曲线显示为虚线。由于第 30 帧后没有关键点,对原始关键点进行的任何更改都会在循环中反映出来。
  9. 播放动画。球会反复反弹。
  10. 将工作另存为 mybounce_repeat.max

 

四、用虚拟对象设置动画

在本课程中,会将反弹球链接到辅助对象。然后,可以为辅助对象设置动画,以使球在一些文本的上方反弹。此动画方法非常有用,因为可以独立地控制球的反弹及其移动运动。

设置课程: 

  1. 在“文件”菜单上选择“打开”。
  2. 打开素材中的 bounce_start.max。 该文件类似于在上一课程中创建的反弹球。唯一的区别是,该文件在场景中为您准备好了一个文本对象,且具有更长的活动时间段。如果要继续使用自己的反弹球,可以使用“文件”>“合并”从 bounce_dummy.max 文件将文本对象合并入场景。或者创建自已的文本对象。
  3. 如果没有打开 bounce_dummy.max,则需将活动时间段扩展至 240 帧。单击“时间配置”按钮,然后在“动画”组中将“结束时间”更改为 240

 

创建虚拟对象: 

  1. 转至第 0 帧。
  2. 单击“顶”视口将其激活,然后放大球和长方体。
  3. 在“创建”面板上,单击“辅助对象”按钮,然后在“对象类型”卷展栏上单击“虚拟对象”。
  4. 在“顶”视口中,将光标移动到球上。请将“层”工具栏和“附加”工具栏从“顶”视口中移开。
  5. 按住鼠标按钮并向外拖动,以创建虚拟对象。如果从“前”视口观察,会看到当球在空中上升时,虚拟对象位于与长方体相同的高度。接下来将对齐虚拟对象,以便从顶部查看时,它位于球上方的正中位置。
  6. 在工具栏上,单击“对齐”。然后,在“顶”视口中单击球。将显示“对齐当前选择”对话框。
  7. 在“对齐当前选择”对话框中,启用“X 位置”和“Y 位置”,但使“Z 位置”处于禁用状态。单击“确定”。您会看到虚拟对象移动了位置,以便与球对齐。下面要将虚拟对象的轴点与其底部对齐,并要将虚拟对象放置于长方体的顶部。这个想法用于设置虚拟对象,以便其轴点与球反弹的位置相匹配。然后及时将虚拟对象放置在任意帧上,这将确保正确的对齐。
  8. 选择虚拟对象,然后转到“层次”面板。通过使用“仅影响对象”(而不是移动轴)来移动对象。这将移动对象,而轴保持不动。
  9. 在“调整轴”卷展栏上,单击“仅影响对象”以启用它。轴图标将显示在视口中。现在,可以移动对象更改它与轴点的关系。
  10. 启用“选择并移动”,并提升虚拟立方体,以便其底部与三角轴等高。使用变换 Gizmo,以便虚拟对象仅向上移动。可以反复按键盘上的 = 键增加变换 Gizmo 的大小,直到该大小符合您的要求为止。
  11. 禁用“仅影响对象”。

 

将球链接到虚拟对象:

  现在,要将球链接到虚拟对象。虚拟对象将成为反弹球的父对象。

  1. 在“前”视口中放大显示,以便可以看到虚拟对象和球。
  2. 在主工具栏上,启用“选择并链接”。
  3. 将光标移到球上,然后按住鼠标按钮。光标将变为两个互相链接的方框。
  4. 将鼠标移向虚拟对象。光标后跟着一根橡皮带线。当光标越过虚拟对象时,它再次发生变化。一个方框为白色,说明该对象(虚拟对象)将成为第一个对象(球)的父对象。当光标改变后,松开鼠标按钮。
  5. 您刚才将球链接到虚拟对象。接下来测试一下以确保实际的结果与您的设想一致。

 

验证是否已经创建了层次: 

  1. 在工具栏上,启用“选择对象”。
  2. H 键打开“从场景选择”对话框。在对象列表中,Sphere01 对象应缩进式地显示在 Dummy01 下方。(要查看整个列表,可能需要单击“场景根”旁边的加号 (+) 图标。)
  3. 可以通过变换父对象测试链接。在视口中旋转虚拟对象。球也相应地旋转。
  4. 测试链接之后撤销变换。

 

  对虚拟对象设置动画: 

  现在,可以为虚拟对象设置动画了。将先使用简单的“自动关键点”动画,以便您能够理解动画过程。

  1. 选择视口之间的分隔线并拖动它们,将透视视口变成宽屏幕。
  2. 启用“自动关键点”。
  3. 在主工具栏上,启用“选择并移动”。
  4. 在第 1 帧处移动虚拟对象,使其在“透视”视口中位于长方体的左侧。
  5. 使用时间滑块移动到第 15 帧,或在“转到帧”字段中输入 15
  6. 使用变换 Gizmo 移动虚拟对象,使球与长方体接触。
  7. 转至第 30 帧并将虚拟对象重新移动到长方体的右侧,以便球继续反弹开去,而不是笔直向上弹向空中。如果播放动画,将看到球在长方体上反弹,就像被抛起来了一样。
  8. 在主工具栏上,启用“选择对象”。使用“选择对象”可确保您不会意外地对对象进行“移动”、“旋转”等操作。
  9. 选择球,然后右键单击它。
  10. 从四元菜单中选择“对象属性”。
  11. 在“对象属性”对话框的“显示属性”组中,启用“轨迹”。
  12. 播放动画。会看到球沿着轨迹在长方体上弹跳起来。

 

尝试使用“布局”模式: 

如果禁用“自动关键点”并移动虚拟对象,则将在空间中移动整个动画。当“自动关键点”和“设置关键点”都被禁用时,您即在称为“布局”模式的条件下工作。在此将使用“布局”模式,以便球从字母 F 上弹跳起来,而不是从块上反弹。

  1.  禁用“自动关键点”模式。时间滑块背景中的红色和视口轮廓中的红色将消失。
  2. 将虚拟对象朝文本的方向移回。
  3. 观察轨迹的位置并移动虚拟对象,直到轨迹的反弹点与字母 F 的顶部相交为止。

 

使球从字母上反弹: 

现在,将重复您所学习的知识,实现在字母上反弹球。

球将反弹 8 次,分别在第 15 帧、第 45 帧、第 75 帧、第 105 帧、第 135 帧、第 165 帧、第 195 帧和第 220 帧处与字母接触。

  1. 启用“自动关键点”。
  2. 在轨迹栏中,选择第 30 帧处的关键点并将其删除。
  3. 将时间滑块移动到第 45 帧(或在“当前帧”字段中输入 45)。
  4. 放置虚拟对象,以便球在单词“Follow”的双 L 字母上反弹。
  5. 移动时间滑块,然后移动虚拟对象,以便球在以下各帧处从相应的字母上反弹。
    • F,在第 15 帧 
    • ll,在第 45 帧 
    • w,在第 75 帧 
    • th,在第 105 帧 
    • b,在第 135 帧 
    • u,在第 165 帧 
    • c,在第 195 帧 
    • ba,在第 225 帧
  6. 在第 240 帧时移动虚拟对象,以便球从字母上移开。
  7. 播放动画并观察结果。
  8. 将工作另存为 mybounce_text.max。如果您遇到任何问题,可以打开 bounce_text.max 文件来查看到目前为止的正确动画。

 

添加增强曲线: 

  1. 在视口中选择球,右键单击并选择“曲线编辑器”。将显示“曲线编辑器”窗口(如果其尚未可见)。
  2. 在“控制器”窗口中,单击 Z 位置轨迹。
  3. 在“曲线”菜单上,选择“应用 – 增强曲线”。在“控制器”窗口中,单击加号图标。单击“增强曲线”以将其高亮显示,然后按住 Ctrl 键并单击 Z 位置轨迹。使用该方法只能显示这两种曲线。在“控制器”窗口中,增强曲线将被添加到 Z 位置轨迹下方。在右侧的“关键点”窗口中,这不太容易被察觉。增强轨迹的比例非常小,因此对关键点进行相当微小的更改都可能会导致动画发生巨大变化。您可以通过放大增强轨迹来抵消这种效果。
  4. 在“导航:轨迹视图”工具栏(位于“关键点”窗口右下方)中,单击“缩放区域”按钮。围绕增强轨迹的第 240 帧的关键点拖出一个缩放区域窗口。
  5. 在“选项”菜单上启用“交互式更新”。
  6. 在“轨迹视图”工具栏上单击“移动关键点”以将其启用,然后向下移动增强关键点,同时在“透视”视口中观察轨迹上产生的效果。注意不要将其移动到水平零值以下,否则会得到一些奇怪的效果。也可以在“关键点状态:轨迹视图”工具栏上输入精确值。使用增强曲线时,如果不确定是否对结果感到满意,则可以将它们禁用。在“控制器”窗口中选择增强曲线,然后在“曲线”菜单上选择“启用禁用”。
  7. 在“导航”工具栏上单击“水平方向最大化显示”以再次观察整条曲线。

 

五、使用摄影表编辑器

轨迹视图还有一种模式称作“摄影表”,可用于处理关键点和范围。在本课程中,将使用范围功能以使动画运动得更快。还将使用“时间”工具来反转动画。

加速动画: 

反弹球没有足够的活力。若要加速动画,将使用“摄影表”模式中的“编辑范围”。

  1. 从上一课继续,或打开 bounce_multiplied.max
  2. 在视口中选择虚拟对象。然后,在“图表编辑器”菜单上选择“轨迹视图 – 摄影表”。
  3. 在“关键点:摄影表”工具栏上,单击“编辑范围”。默认情况下,“关键点:摄影表”工具栏位于左上方。“关键点”窗口此时将显示动画的范围。
  4. 在“控制器”窗口中,高亮显示项标签 Dummy01。这样,将同时调整所有虚拟对象的轨迹范围。在对虚拟对象做出更改之前,需要确保同时将对反弹球进行更改。因为反弹球是虚拟对象的子对象,所以将使用“修改子对象关键点”按钮。
  5. 在“显示:摄影表”工具栏上,单击“修改子关键点”以将其启用。此时对虚拟对象范围所做的更改也将被应用到反弹球上。
  6. 单击虚拟对象范围的末端,并将其向左拖动到大约第 100 帧处。这将压缩虚拟对象和反弹球的动画,使得其发生在 100 帧之内。也可以将时间标尺从“关键点”窗口底部向上提升,以获得更大的精度。
  7. 播放动画。动画的播放速度较快。球在动画的结尾处继续反弹。有几种不同的方法可用于纠正这种效果。可以尝试使用减缓曲线来停止动画,也可以在超出范围曲线中创建关键点,然后删除这些关键点。还可以将活动时间段设置为 100 帧。
  8. 单击动画播放控件下方的“时间配置”按钮。
  9. 将“动画”>“结束时间”更改为 100

 

反转时间: 

通过使用“摄影表”模式中的“时间”工具可以反转动画。这很容易做到。

  1.  在“关键点: 摄影表”工具栏上,单击“编辑关键点”。范围栏将替换为关键点。
  2. 在“时间”菜单上,选择“选择”。当使用“时间”命令时,请先选择时间,然后对其做出更改。
  3. 在“关键点”窗口中的虚拟对象轨迹上,将鼠标从第 0 帧拖动到第 100 帧以选择时间。时间在虚拟对象轨迹中显示为淡黄色的窄带。
  4. 在“时间”菜单上,选择“反转”。动画将向后播放。球将从右向左而不是从左向右反弹,最后一次反弹现在发生在字母 F 上,而不是发生在单词“ball”的双 L 字母上。
    提示 使用“时间配置”菜单中的控件,可以很容易地反转动画的播放。但如果需要反转关键点本身,这是要使用的方法。
 小结

这些“动画”教程介绍了创建动画的技术。您学习了如何使用“自动关键点”按钮和变换对反弹球进行动画处理,如何使用关键点插值和重影控制中间帧,以及如何使用“轨迹视图”控件循环动画。最后,学习了使用虚拟对象设置动画,使用“摄影表”编辑器和权重列表控制器。

分类
未分类

3DS MAX 2009 之放样教程

3DS MAX 2009 之放样教程

放样(Loft Object)是将一个二维形体对象作为沿某个路径的剖面,而形成复杂的三维对象。同一路径上可在不同的段给予不同的形体。我们可以利用放样来实现很多复杂模型的构建。

 

一、创建放样路径与截面

  1. 右键单击“前”视口以其变为当前视口。
  2. 在“创建”面板上,单击“图形”,然后单击“圆环”。
  3. 在“前”视口中创建一个圆环。
  4. 在“创建”面板上,单击“图形”,然后单击“线”。
  5. 在“前”视口中,创建一条光滑的曲线。
  6. 单击创建面板中的“几何体”按钮。
  7. 选择“复合对象”,然后单击“放样”按钮。
  8. 单击“创建方法”卷展栏中的“获取图形”按钮,然后在“前”视口中单击选中圆环即可。

 

二、增加放样截面

我们在制作一些如台布、床罩、窗帘等的模型时,可以利用一条放样路径,增加多个不同的截面,这样可以减少模型制作的复杂程度,节省时间。下面我们将练习制作一个圆形台布,用两条手绘的曲线创建放样造型。

  1. 右键单击“顶”视口以其变为当前视口。
  2. 在“创建”面板上,单击“图形”,然后单击“圆形”。
  3. 在“顶”视口中创建一个圆形,设置半径为 40。
  4. 在“创建”面板上,单击“图形”,然后单击“星形”。
  5. 在“顶”视口中创建一个星形,设置半径1 为 45 ,半径2 为50,圆角半径1 为 4 ,圆角半径2 为 5 。
  6. 在“创建”面板上,单击“图形”,然后单击“线”。
  7. 在“前”视口中,创建一条竖直的直线。
  8. 单击创建面板中的“几何体”按钮。
  9. 选择“复合对象”,然后单击“放样”按钮。
  10. 单击“创建方法”卷展栏中的“获取图形”按钮,然后在“顶”视口中单击选中圆形。
  11. 将路径设置为 100 ,
  12. 单击“创建方法”卷展栏中的“获取图形”按钮,然后在“顶”视口中单击选中星形即可。
分类
Dreamweaver

用 CSS 布局

创建基于 CSS 的页面布局

许多 Web 站点都使用基于表格的布局显示其页面上的信息。表格对于显示表格数据(如重复元素的行和列)很有用,并且很容易在页面上创建。但表格往往还会生成大量难于阅读和维护的代码。此外,由于所需的标签数量很大,并且可能需要进行“嵌套”,因此表格可能会给使用屏幕读取器查看 Web 页的残障人士带来不便。

基于 CSS 的布局(即,使用块元素代替表格行和列的布局)所包含的代码数量要比具有相同特性的基于表格的布局中的代码数量少很多。基于 CSS 的布局通常使用 <div> 标签,而不是 <table> 标签来创建用于布局的 CSS 布局块。可以将这些 CSS 布局块放置在页面上的任意位置,并为它们指定属性,如边框、边距、背景颜色等。此外,由于代码更为简单和短小,因此使用屏幕读取器查看 Web 页的用户可以更容易地浏览使用 CSS 构建的页面。

分类
3ds Max

3ds Max 2009 建模教程

3ds Max 建模教程

你可以将 3D 中的建模比喻成雕塑。你可以使用许多不同的技术在场景中创建对象。

本节教程包括以下内容:

  • 创建基本体对象
  • 使用修改器改变对象的图形。
  • 创建并编辑样条线对象
  • 使用修改器将样条线转化为几何体
  • 使用背景图像设置视口背景
  • 在子对象层级编辑模型
  • “可编辑多边形”中的功能
  • 使用“合并”和“外部参照”将外部对象引入到场景中
  • 素材下载

     

    >>建造国际象棋的模型

    一、建造兵的模型

    在本课程中,将建造国际象棋棋子中兵的模型。在标准设计的木制国际象棋中,兵是在车床上加工而成的。将使用 3ds Max 执行下列类似操作:绘制兵的轮廓,然后使用“车削”修改器填充其几何体。“车削”修改器将轮廓围绕一个中心点旋转来创建图形,就像在机床上对木头进行加工的方法一样。

    本课程中介绍的功能和技术:

    • 使用样条线图形绘制对象的轮廓。本课程还简要介绍样条线编辑。样条线是一种插补在两个端点和两个或两个以上切向向量之间的曲线。该术语得名于 1756 年,源自用于在建筑和船舶设计中草绘曲线的细木或金属条。
    • 编辑图形顶点和边,以更好地控制样条线的绘制。
    • 使用“车削”修改器将 2D 轮廓转换为 3D 模型。

      

    设置视口背景: 

    要创建兵(或其他棋子)的剖面,需要将参考图像加载到视口中,以便可以对其进行跟踪。

    1. 右键单击“前”视口以其变为当前视口。
    2. 从“视图”菜单中选择“视口背景”。“视口背景”对话框出现。
    3. 单击“文件”按钮。打开素材文件夹中,然后双击 ref-chess.jpg 将其加载。
    4. 在“纵横比”组中,选择“匹配位图”。从而确保视口中的图像不会扭曲。
    5. 在该对话框的右侧,启用“锁定缩放/平移”。从而确保背景图像对缩放和平移作出反应(在进行视口导航时会用到)。
    6. 单击“确定”退出该对话框。位图现在出现在“前”视图中。按 G 键可禁用栅格,因为您在本练习中并不需要它。

    现在可以开始进行绘制了。

     

    开始绘制兵的轮廓: 

    将从顶部的“圆球”开始绘制兵的轮廓。

    1. 在“前”视口中,对兵参考图像进行放大。
    2. 在“创建”面板上,单击“图形”,然后单击“线”。
    3. 在“创建方法”卷展栏上,将“初始类型”和“拖动类型”设置为“角点”。从而确保所有线分段都是线性的。
    4. 在“前”视口中,单击顶部中心附近的点。按住 Shift 键以将线条约束到垂直轴,然后单击兵基部上的第二个点。
    5. 仍然按住 Shift 键,同时单击基部右底边上的一个点。
    6. 从这个位置,单击参考图像右轮廓上的几个点,以创建大致的剖面,直至图像侧面。此时不需要特别精确,因为以后可以对剖面进行编辑。要闭合样条线并结束该命令,单击第一个点。
    7. 提示时,单击是即可关闭样条线。

     

    编辑兵的轮廓: 

    1. 仍然选定样条线,转到“修改”面板。
    2. 在“选择”卷展栏上,单击“顶点”按钮。
    3. 在“前”视口中,放大创建的剖面底部。
    4. 使用“选择并移动”工具来调整顶点。
    5. 选择最右侧的两个顶点,然后激活“修改”面板 >“几何体”卷展栏中的“圆角”按钮。
    6. “圆角”命令处于活动状态时,将光标放在选中的顶点之一,然后单击并拖动以使两个角变圆。
    7. 向上平移以处理剖面的中间部分。
    8. 选择您刚刚创建的圆角上的顶点。如有必要,基于参考图像将其移到更好的位置。
    9. 选中顶点后,在视口中右键单击,并从显示的四元菜单中,选择“平滑”。
    10. 调整顶点位置以匹配参考图像。
    11. 向上平移到下一组顶点。在一些情况下,您可能需要添加顶点。
    12. 在“修改”面板 >“几何体”卷展栏上,选择“优化”。
    13. 单击需要插入顶点的线条。新顶点已添加至样条线。
    14. 使用“移动”工具,调整顶点的位置。
    15. 就像前面的操作一样,选择伸出右侧的顶点,并对其进行圆角处理,以创建一条曲线。
    16. 向上平移剖面。选择两个顶点。
    17. 就像前面的操作一样,使用四元菜单,将两个选定顶点转换为平滑顶点。移动它们以对其位置进行微调。
    18. 向上平移到剖面的顶部。选择圆球右侧的两个顶点,并使它们成为平滑顶点。再次使用“选择并移动”工具微调它们的位置。
    19. 放大圆球基部。
    20. 如果在圆球基部只有一个顶点,则像前面的操作一样,使用“优化”工具来添加其他顶点。
    21. 选择两个顶点并右键单击,以访问四元菜单。
    22. 使用四元菜单即可将这两个顶点转换为“Bezier 角点”。
    23. 使用“选择并移动”可调整顶点及其控制柄的位置,以围绕圆球基部获得更正确的曲率。
    24. 在剖面的最顶部,选择创建的第一个顶点。使用四元菜单即可将其转换为“Bezier 角点”。
    25. 调整控制柄,以与参考图像上的曲率匹配。
    26. 继续优化剖面,调整顶点位置和类型,以与参考图像匹配。
    27. 完成后,单击“修改”面板“选择”卷展栏中的顶点按钮可退出子对象层级。

     

    车削轮廓: 

    此时可以使用在前面步骤中创建的文件继续,也可以打开 pawn_outline_edited.max 文件并从该文件继续。

    1. 选择兵,并单击修改器堆栈显示上方的“修改器列表”。这是一个包含各种修改器的下拉列表。
    2. 从该列表中选择“车削”。兵模型的外观可能与预期不同,但是这只是因为轴旋转默认情况下基于样条线的轴点,而不是剖面的左侧。在接下来的步骤中将对其进行修复。
    3. 在“车削”修改器的“参数”卷展栏上,找到“对齐”组,然后单击“最小化”。兵的外观现在看上去好多了,虽然还是有一点“扭曲”。
    4. 在“车削”修改器的“参数”卷展栏上,将“分段”值增加到 32
    5. 在“车削”修改器的“参数”卷展栏上,启用“焊接内核”。从而会将模型中心处的所有顶点组合为一个。

    在本课程中学习了样条线的创建和编辑。还学习了使用“车削”修改器创建 3D 几何体。

    在“材质和贴图简介”教程中,将为国际象棋棋子提供更合理的颜色和纹理,并创建亮面、反光木纹棋盘。

     

    二 、建造象的模型

    在本课程中,将建造国际象棋中象的模型。对于大部分零件,会根据剖面图形和车削修改器采用与兵相同的方式对象进行建模。不同之处是在象头上显示的间距。使用布尔对象获得结果。

    本课程中介绍的功能和技术:

    • 使用样条线图形绘制对象的轮廓。
    • 使用“车削”修改器将 2D 轮廓转换为 3D 模型。
    • 使用“布尔”减去几何体。

      

    设置课程: 

    1. 采用与上一节课中的兵相同的方式对象的基本图形进行精确构建。按照“建造兵的模型”练习中的步骤执行操作,或打开素材文件夹中的 bishop_outline_edited.max 文件以使用完成的图形。此文件包含象的剖面和参考背景图像。如果看不到参考图像,请执行以下步骤。
    2. 确保已选中“前”视口,然后按 ALT+B 组合键打开“视口背景”对话框。
    3. 在该对话框中,单击“文件”按钮。
    4. 在素材文件夹中找到 ref-chess.jpg 图像,然后双击它。

     

    车削象 

    1.  在主工具栏上,单击“选择”工具。选择在任何视口中代表象剖面的样条线。
    2. 在选定样条线的情况下,转到“修改”面板。从“修改器”列表中选择“车削”。
    3. 在“参数”卷展栏上,单击“对齐”组中的“最小”按钮。
    4. 将“分段”设置为 32,然后启用“焊接内核”选项。

     

    创建和定位框: 

    要在象头中创建缺口,可以创建一个简单的框,然后从象模型中减去它。

    1. 放大靠近象头的“前”视口。
    2. 从“创建”菜单上,选择“标准基本体”>“长方体”。
    3. 在“前”视口中,单击并拖动以定义框的出发点。不必担心特定尺寸,随后可以更改这些尺寸。
    4. 定义出发点之后,移动鼠标,然后单击以定义高度。
    5. 转到“修改”面板并设置框的尺寸,如下所示:
      • 长度 = 15.0
      • 宽度 = 2.0
      • 高度 = 50.0
    6. 在主工具栏上,单击“选择并旋转”按钮。旋转“前”视口中的矩形,以便其与象头中的缺口对齐(在参考图像中)。
    7. 使用“选择并移动”,将矩形定位在缺口的顶部。
    8. 在“顶”视口中,移动 Y 轴(绿色轴)上的矩形,直到在象的两侧可以看到它为止。

     

    使用“布尔”操作创建切片: 

    1. 在任何视口中选择象。
    2. 在“创建”菜单上,选择“复合”>“布尔”。该象现在是布尔对象,而且命令面板将自动切换到“创建”面板,显示新转换对象的参数。
    3. 在“拾取布尔”卷展栏上单击“拾取操作对象 B”,然后在任何视口中单击长方体。在执行“布尔”操作时,第一个选定的对象(在本例中为象)被认为是“操作对象 A”,第二个选定的对象(在本例中为框)被认为是“操作对象 B”。然后可以选择要执行的操作类型,不管它是并集、交集还是差集,在后面的情况下,此操作对象从中减去它。

    在本课程中,您学习了通过在对象中使用“布尔”值剪一个孔来移除几何体。

     

    三、建造车的模型

    在本课程中,将建造国际象棋中车的模型。您以以前课程中的相同方式建造车的模型,创建一个兵和象,除了顶部的城垛之外。如果是要生成木制国际象棋,则不能对该部分使用车削,而应该使用 3D 模型:尽管兵和象的底座结构与车的底座结构一样为车削样条线,但其顶部却使用另外的建模技术。

    本课程中介绍的功能和技术:

    • 使用面挤出更改几何体。
    • 调整平滑组以便获得更好的效果。

     

    设置课程: 

    1. 打开 rook_outline_edited.max 文件。此文件包含车的基本图形。如果您喜欢从头开始建造车,则删除剖面并像在以前课程中建造兵和象一样重新创建它。但是,确保您没有考虑车顶部的城垛,因为您将随后使用多边形挤出创建它们。“前”视口应该包含参考图像。如果看不到图像,请执行以下步骤:
    2. 确保“前”视口处于活动状态,然后按 ALT+B 组合键打开“视口背景”对话框。
    3. 在该对话框中,单击“文件”按钮。
    4. 素材文件夹中找到 ref-chess.jpg 图像并双击。

     

    车削基本图形: 

    1. 在主工具栏上,选择“选择”工具。选择在任何视口中表示车剖面的样条线。
    2.  在选定样条线的情况下,转到“修改”面板。从“修改器”列表中选择“车削”。
    3. 在“参数”卷展栏上,单击“对齐”组中的“最小”按钮。
    4. 将“分段”设置为 36,然后启用“焊接内核”。

     

    准备城垛的顶部: 

    1. 仍然选中车的情况下,确保您仍然在“修改”面板中。从“修改器”列表中,选择“编辑多边形”。
    2. 在“选择”卷展栏上,单击“多边形”按钮。
    3. 尝试选择车的顶部。您可以只选择该区域的一部分,应该为顶部区域的 1/36。
    4. 在“选择”卷展栏上,单击“顶点”按钮。
    5. 选择车顶部中心区域中的顶点。
    6. 按下 Ctrl 键,同时再次单击“选择”卷展栏上的“多边形”按钮。连接到选定顶点的所有多边形将自动选中。
    7. 如有必要,按 F4 键启用“边面”显示。这将允许您查看着色的对象及其基本几何体。
    8. 在“编辑多边形”卷展栏上,单击“插入”旁边的“设置”按钮。
    9. 在出现的对话框中,将“插入量”设为 100
    10. 单击“确定”关闭对话框并保存插入。

     

    创建城垛: 

    1. 如有必要,打开“修改”面板。
    2. 在“选择”卷展栏上,确保您处于“多边形”子对象层级。
    3. 使用“选择”工具选择外环中的四个相邻的多边形。
    4. 跳到下面的两个多边形,然后选择它们后面的四个。在圆周上重复该步骤,直到选择的对象与下图相似:
    5. 在“编辑多边形”卷展栏上,单击“挤出”旁边的“设置”按钮。在出现的对话框中,将“挤出高度”值设为 45,以与“前”视口中参考图像的城垛高度相匹配(如有必要,可更改该值)。完成后,单击“确定”保存挤出并退出该对话框。
    6. 在“选择”卷展栏上,单击“多边形”按钮以退出该层级。
    7. F4 退出“边面”显示。注意影响城垛的面状。此后将修正这个错误。

     

    调整平滑组: 

    1. 确保仍然选中车对象,并且您仍然处于“修改”面板。
    2. 从“修改器”列表中,选择“平滑”。整个车现在呈现面状。
    3. 在“参数”卷展栏中,启用“自动平滑”并且使“阈值”处于默认值 30.0。任何两个夹角小于该值的相邻面将由相同的平滑组组成,并且它们之间没有出现边。

    现在车看上去更平滑了。

    在本课程中,您学习了使用面挤出创建新的几何体。您还学习了如何使用平滑组使对象呈现更平滑的外观。

     

    四、建造马的模型

    在本课程中,将使用自定义样条线和“曲面”修改器创建国际象棋中的马。“曲面”修改器通过一系列交叉样条线生成 3D 曲面。

    建造马的模型要面临一系列艰难挑战:它独特的轮廓需要小心塑形。“曲面”修改器是此类建模的理想工具。

    本课程中介绍的功能和技术:

    • 构建样条线框架。
    • 使用新线段优化和连接样条线顶点。
    • 应用和调整“曲面”修改器。
    • 使用“对称”修改器。
    • 使用“编辑面片”修改器挤出面片。

     

    设置课程: 

    1. 从素材 文件夹中加载文件 Knight_Start.max场景是空的,只有背景图片,在构建马的模型时将此图片作为参考。如果看不到参考图片,请执行以下步骤。
    2. 确保选中“前”视口,然后按 ALT+B
    3. 在出现的对话框中,单击“文件”按钮。
    4. 素材文件夹中找到 ref-chess.jpg 图像,然后双击它。

     

    绘制马的轮廓: 

    1. 按下 ALT+W 以最大化“前”视图。
    2. 在“创建”面板上,单击“图形”,然后单击“线”。
    3. 在“创建”面板 >“创建方法”卷展栏上,将“初始类型”和“拖动类型”设置为“平滑”。这将帮助您设置基本剖面,提供棋子的曲线性质。
    4. 单击以创建马的轮廓。目前不要考虑马的鬃毛或基部。切记这种建模不需要大量细节,因此尽量使顶点数量最少。以后可以进行调整。
    5. 确保通过单击起始点闭合样条线。
    6.  转至“修改”面板。在“选择”卷展栏上,单击“顶点”。
    7. 围绕马的图形调整顶点的位置。选择后面的顶点。
    8. 右键单击并从四元菜单中选择“Bezier 角点”。
    9. 使用“选择并移动”工具调整顶点控制柄,以便剖面更好地适配参考图像。

     

    创建内部样条线框架: 

    1. 您将开始在头部与颈部相交的位置添加细节。在“修改”面板 >“几何体”卷展栏上,启用“连接”,然后单击“优化”。注意:“优化”会向样条线添加顶点。如果启用“连接”选项,则所有插入的顶点将按照创建的顺序由线段连接起来。
    2. 在头部和颈部前边的相交处单击“Bezier 角点”顶点。此时,将打开一个对话框。该对话框显示出,您单击的位置上已存在顶点。您仍然可以选择优化样条线、在与现有顶点非常接近的位置处添加另一个顶点或只是使用现有顶点,并将其连接到即将插入的其他顶点上。通常,在出现该警告时使用“仅连接”方法。
    3. 启用“不再显示该信息”选项,然后单击“仅连接”。
    4. 单击颈部后面右侧的点。
    5. 右键单击以完成命令。现在您拥有一条从颈部前面连接到后面的线段。
    6. 向颈部添加两个以上的“层级”,如下图所示。
    7. 使用“优化/连接”可以添加一条从颈部连接到头部的细节垂直线。
    8. 继续添加细节,直至样条线框架的外观类似于下图。

     

    删除不需要的顶点: 

    下一步是确保样条线框架上没有松散的顶点。在这种建模方法中,基本上样条线框架只由三面区域或四面区域构成。

    1. 确保仍然选定样条线,并且您仍然处于顶点子对象层级。
    2. 查找松散的顶点,并将它们选中。
    3. Delete 可删除不需要的顶点。确保四边形不会超过四个顶点(线段在此相交)。

     

    微调样条线框架: 

    下一步是调整样条线框架以获得流畅的线段流向。优化样条线框架时,将引入许多相交线段,从而带来大量相交顶点。注意在空间中共享相同位置的顶点将移到一起是非常重要的。

    1. 确保仍然选定样条线,并且您仍然处于顶点子对象层级。
    2. 在“选择”卷展栏中,启用“区域选择”,并将值保留为 0.1。从而确保在通过单击选中某个顶点时,位于域值指定距离范围内的所有顶点也同时被选中。
    3. 使用“选择并移动”工具重新定位顶点,以在样条线框架中获得流畅的线段流向。

     

    提供样条线线框体积: 

    到目前为止,您已经在“前”视口中构建了所有内容。因此,线段的集合位于同一平面中。在此步骤中,您将调整样条线框架,以便其开始塑形为 3D 体积。

    1. 如果“前”视口仍然最大化,则按 ALT+W 即可返回到四向视口布局。
    2. 单击“所有视图最大化显示”,在所有四个视口中查看样条线框架。
    3. 使用“选择”工具和 Ctrl 键,选择所有内部顶点以及底部线段的两个中心顶点。
    4. 在“顶”视口中,将 Y 轴(绿色轴)上的选定顶点向下移动。
    5. 继续调整这些内部顶点的位置,以赋予体积更多相交图形(更狭窄的口鼻部、更粗的颈部底部等等)。可随意进行试验,但是不要移动周界周围的其他顶点;您需要在以后镜像对象时用到它们。

     

    调整周界上的切线: 

    1. 选择颈部后面沿线的所有顶点,顶部的那个顶点除外。
    2. 在视口中右键单击,然后将选定顶点转换为“Bezier 角点”。
    3. 移动成角度的切线,以使它们占据更多顶点位置。从而在线段与镜像线条接触时赋予它们更大的迎角。提示:如果尝试移动切线并查找一个轴或其他轴上锁定的方向,则按 F8 可将运动约束到 XY 平面。
    4. 对嘴部附近的两个顶点重复此过程,这两个顶点跨越颈部的前面。
    5. 对头顶沿线的顶点重复此步骤,然后使用“前”视口使切线水平。

     

    测试“曲面”修改器 

    最后将镜像此样条线排列,以生成马的另一面,但是在执行此操作之前需要检查当前设置,以查看“曲面”修改器是否能够对其进行操作。

    “曲面”修改器会在每一组由样条线构成的三面或四面多边形上放置一个 3D 曲面。

    这些多边形必须完全闭合,“曲面”修改器才能生成 3D 曲面。通过现在测试“曲面”修改器,可以在镜像样条线之前修正曲面中的任何“孔洞”。

    1. 选中 Line01 后,退出“顶点”子对象层级。
    2. 在“修改器列表”中,选择“对象空间修改器”部分的“曲面”。根据构建样条线框架的方式,在“透视”视口中马的外观可能是实心或空心的。
    3. 在“参数”卷展栏中,尝试启用或禁用“翻转法线”选项,直至马出现,如上图右侧所示。
    4. 展开修改器中的“线”条目,然后单击“顶点”。启用“显示最终结果”,以使您可以使用样条线框架,并同时查看“曲面”修改器的效果。
    5. 在“前”视口中,选择颈部的顶点,在此可以看到肌肉张力下降一点。右键单击并将该顶点转换为“Bezier 角点”。
    6. 在“顶”视口中,将控制柄调整为尖头朝下的 V。这样可以帮助您模拟颈部的肌肉张力。密切注意“透视”视口,以便参考。
    7. 使用这个顶点和其他顶点进行试验,以塑造外观更真实的颈部。可以对其他部分(如口鼻部或头部)也使用这种方法。

     

    优化鬃毛线条: 

    1. 调整“透视”视口,以使您看到颈部的后面。
    2. 使用“连接/优化”,从头顶处的顶点开始,一直向下,以优化鬃毛线条,如下图所示。在优化线段时,曲面面片会暂时从视图中消息,但是完成该命令后就会重新出现。这是因为您引入了其他顶点,从而创建了顶点超过四个的面片区域。然而,完成样条线框架的细化之后,最终结果将再次由四方体构成,因此显示是正确的。
    3. 退出“顶点”子对象层级,然后单击“曲面”修改器以转到堆栈的顶部。

     

    镜像样条线排列: 

    1. 如果尚未执行此操作,则在修改器堆栈上突出显示“曲面”修改器。
    2. 从“修改器”列表中选择“对称”。
    3. 在“参数”卷展栏上,将“镜像轴”设置为 Z。
    4. 在“透视”视口中围绕对象环游,以查看整个 3D 对象。

     

    挤出并调整鬃毛: 

    1. 在修改器堆栈上突出显示“曲面”修改器。从“修改器”列表中选择“编辑面片”。这将在“曲面”修改器上面及“对称修改器”下面插入一个“编辑面片修改器”。
    2. 如有必要,禁用“显示最终结果”。您在所有视口中应该只能查看马的一半。
    3. 在“面片”修改器的“选择”卷展栏上,选择“面片”按钮。
    4. 在“透视”视口中,选择构成马鬃毛的面片。
    5. 在“几何体”卷展栏 >“挤出和倒角”组上,单击“挤出”按钮。
    6. 使光标靠近透视视图中的选定面片,然后单击并拖动以挤出面片。密切注意“前”视口,以便参考。
    7. 在“选择”卷展栏上,从“面片”切换到“顶点”,然后启用“显示最终结果”。由于挤出的方向,您需要调整顶点的位置,以为“对称”修改器提供一点帮助。
    8. 在“前”视口中,在“顶”视口中,向上移动选定顶点,直至它们沿着镜像线条相交。密切注意其他视口,以查看“对称”修改器是否可以正常焊接缝。使用区域选择来选择鬃毛外边缘上的所有顶点。如有必要使用 Ctrl 键。
    9. 在“顶”视口中,向上移动选定顶点,直至它们沿着镜像线条相交。密切注意其他视口,以查看“对称”修改器是否可以正常焊接缝。注意:与调整镜像线条相比,这种方式更加简单。理想情况下,您要单独或成组移动顶点,同时调整切线以获得更好的效果。
    10. 在“前”视口中调整顶点和切线的位置,以遵循参考图像并创建流畅的鬃毛。

     

    创建基部: 

    即使您将基部创建为同一样条线框架的一部分,将其构建作为单独的对象,然后将两个对象连接在一起,作为一个单独的网格也更加容易。基部是一个简单车削的对象,于在前面的课程中创建的对象非常类似。

    1. 从“创建”菜单中,选择“图形”>“线”。
    2. 在“创建方法”卷展栏上,将“初始类型”和“拖动类型”设置为“角点”。
    3. 在“前”视口中,马的正下方,单击基部顶部中心的一个点。
    4. 按住 Shift 键以将线条约束到垂直位置,然后单击基部底部中心上的一个点。
    5. 移到右侧,并单击基部右下角处的一个点。
    6. 释放 Shift 键并上升右侧,以创建基部的大致剖面。确保在完成后闭合样条线。
    7. 转至“修改”面板。在“选择”卷展栏上,选择“顶点”。
    8. 在“几何体”卷展栏上,选择“圆角”。
    9. 使用“圆角”工具使需要它的顶点变圆。
    10. 退出“顶点”子对象层级。
    11. 从“修改器”列表中选择“车削”。
    12. 将“分段”设置为 32,然后启用“焊接内核”。在“对齐”组中,单击“最小化”。注意如果需要有关如何创建车削对象的详细信息,请参阅本教程中的第一个课程:建造兵的模型。

     

    将两个对象变为一个网格: 

    1. 确保仍然选定基部。右键单击它,然后从四元菜单中选择“转化为”>“转化为可编辑网格”。
    2. 在“编辑几何体”卷展栏上,单击“附加”,然后单击任意视口中的马。
    3. 将对象的名称更改为 Knight现在,马即已完成,如果您想添加嘴部,您可以通过使用“优化”来添加顶点然后移动顶点来完成。

     

    在这些课程中,创建了四个国际象棋棋子,从而在每种情况下学习了不同的工具和方法。创建兵时讲授了如何使用样条线和车削修改器。创建象和车时讲授了如何编辑几何体,以及如何使用“布尔”复合对象加上或减去相应部分。最后,您学习了对样条线对象使用“曲面”修改器这种样条线框架方法来建模。

    分类
    3ds Max

    创建 and 编辑 基本体 Objects

    创建 and 编辑 基本体 Objects

    Max is all about 创建 objects and scenes, so it’s appropriate that one of the first things to learn is how to create objects. Although you can create complex models and objects, Max includes many simple, default geometric objects, called 基本体s, that you can use as a starting point. 创建 these 基本体 objects can be as easy as 单击 and 拖曳 in a viewport.

     

    创建 基本体 Objects

    1.    Open the 创建面板, 单击 the “几何体” button, and select “扩张基本体” from the subcategory drop-down list. 单击 the “异面体” button to enter “异面体” creation mode, or select the 创建➪ “扩张基本体” ➪ “异面体” 菜单命令.

    2.    单击 in the 顶视口, and 拖曳 to the left to create a simple 四面体 object. After the object is created, you can adjust its settings by 更改 the settings in the 参数 卷展栏.

    3.    Select the “四面体” option in the 参数 卷展栏, set the P value in the “系列参数” section to 1.0, and enter a value of 50 for the “半径”. Be sure to press the Enter key after entering a value to update the object. Enter the name 四面体 in the Object Name field.

    4.    单击 and 拖曳 again in the 顶视口 to create another “异面体” object. In the 参数 rollout, select the “立方体/八面体” option, and enter a value of 1.0 in the Family Parameter’s P field and a value of 50 in the “半径” field. Name this object 八面体.

    5.    拖曳 in the 顶视口 to create another object. The “立方体/八面体” option is still selected. Enter a value of 1.0 in the Family Parameter’s Q field this time, and set the “半径” to 50. Name this object 立方体.

    6.    拖曳 in the 顶视口 again to create the fourth “异面体” object. In the 参数 卷展栏, select the “十二面体/二十面体” option, enter a value of 1.0 in the P field, and set the “半径” value to 50. Name the object 二十面体.

    7.    拖曳 in the 顶视口 to create the final object. With the “十二面体/二十面体” option set, enter 1.0 for the Q value, and set the “半径” to 50. Name this object 十二面体.

    8.    To get a good look at the objects, 单击 the 透视视口, press the”最大化显示” button, and maximize the viewport by 单击 the “最大化视口切换” (or press Alt+W) in the lower-right corner of the window.

     

    分类
    Flash professional

    匹配游戏制作

    匹配游戏制作

    游戏玩法:

    开始游戏后,有若干张背景卡片,其中有两张是相同的。当鼠标点击任意一张卡片后,该卡片自动翻转,然后再点击下一张卡片,翻转后若两张卡片相同,分数加100分,并在屏幕上移除这两张卡片;若不相同,分数会减5分;待所有的卡片都匹配完成后,游戏结束,最后显示出所得分数和所用时间。

    制作步骤(主要分成游戏元素的组合,游戏代码的实现两部分):

    分类
    Flash professional

    Flash CS4 Professiona 的组件

    Flash CS4 Professiona 的组件

    Adobe® Flash® CS4 Professional 组件是带参数的影片剪辑,您可以修改它们的外观和行为。组件可以是一个简单的用户界面控件(如 RadioButton 或 CheckBox),也可以包含内容(如 List  或 DataGrid)。

    组件使您可以方便而快速地构建功能强大且具有一致外观和行为的应用程序。您可以使用Flash 组件实现这些控件,而不用创建自定义按钮、组合框和列表。只需将这些组件从“组
    件”面板拖到应用程序文档中即可。您还可以方便地自定义这些组件的外观和直观感受,从而适合您的应用程序设计。

    即使对 ActionScript 没有深入的理解您也可以进行所有这些工作,还可以使用 ActionScript 3.0 修改组件的行为或实现新的行为。每个组件都有一组唯一的 ActionScript 方法、属性和事件,它们构成了此组件的“应用程序编程接口”(API)。API 允许您在应用程序运行时创建并操作组件。

    API 还允许您创建自己的新的自定义组件。您可以从 Adobe Exchange (网址为 http://www.adobe.com/go/flash_exchange_cn)下载由 Flash 社区成员构建的组件。有关创建组件的信息,请参阅 www.adobe.com/go/learn_fl_creating_components_cn

    ActionScript 3.0 组件体系结构包括所有组件基于的类、允许您自定义外观的外观和样式、事件处理模型、焦点管理、辅助功能接口等等。

    在文档中添加和删除组件

    将基于 FLA 的组件从“组件”面板拖到舞台上时, Flash 会将一个可编辑的影片剪辑导入到库中。将基于 SWC 的组件拖到舞台上时, Flash 会将一个已编译的剪辑导入到库中。将组件导入到库中后,您可以将组件的实例从“库”面板或“组件”面板拖到舞台。

    通过从“组件”面板拖动组件,可以将组件添加到文档中。在“属性”检查器的“参数”选项卡或“组件”检查器中的“参数”选项卡中可以设置组件每个实例的属性。

    使用“组件”面板向 Flash 文档添加组件:

    1. 选择“窗口” > “组件”。
    2. 双击“组件”面板中的组件,或将组件拖到舞台。
    3. 在舞台上选择该组件。
    4. 如果看不到“属性”检查器,请选择“窗口” > “属性” > “属性”。
    5. 在“属性”检查器中,输入组件实例的实例名称。
    6. 单击“参数”选项卡,然后为实例指定参数。
    7. 通过编辑宽度 (W:) 和高度 (H:) 的值,按需更改组件的大小。
    8. 选择“控制” > “测试影片”或按 Ctrl+Enter 编译文档并查看设置的结果。

    您还可以更改组件的颜色和文本格式,方法是设置组件的样式属性,或通过编辑组件的外观自定义其外观。

    你也可以在 ActionScript 在运行时添加组件。

    若要使用 ActionScript 在运行时将组件添加到文档,当编译 SWF 文件时,组件必须先位于应用程序的“库”(“窗口” > “库”)中。若要将组件添加到“库”中,请将组件从“组件”面板拖到“库”面板中。

    您还必须导入组件的类文件,以使应用程序可以使用组件的 API。组件类文件安装在包含一个或多个类的包 中。若要导入组件类,请使用 import 语句并指定包名称和类名称。例如,您可以使用下列 import 语句导入 Button 类:

    复制代码

    1. import fl.controls.Button;

    若要创建组件的一个实例,必须调用组件的 ActionScript 构造函数方法。例如,下面的语句创建一个名为 aButton 的 Button 实例:

    复制代码

    1. var aButton:Button = new Button();

    最后一个步骤是调用静态的 addChild() 方法将组件实例添加到舞台或应用程序容器。例如,下面的语句添加 aButton 实例:

    复制代码

    1. addChild(aButton);

    此时,您可以使用组件的 API 动态指定组件的大小和在舞台上的位置、侦听事件,并设置属性以修改组件的行为。

    删除组件

    在创作时若要从“舞台”删除组件实例,只需选择该组件,然后按 Delete 键即可。这会从“舞台”删除实例,但不会从应用程序中删除该组件。

    在您将组件放置在舞台上或“库”中之后,若要从 Flash 文档删除组件,您必须从“库”中删除组件及与它关联的“资源”。从“舞台”中删除组件是不够的。如果您未从“库”中删除组件,则在您编译时组件会包括在应用程序中。

    从文档中删除组件:

    1. 在“库”面板中,选择组件的元件。
    2. 单击“库”面板底部的“删除”按钮,或从“库”面板菜单中选择“删除”。

    重复这些步骤以删除所有与组件关联的资源。

    例:使用 Button 组件

    Button 组件是一个可调整大小的矩形按钮,用户可以通过鼠标或空格键按下该按钮以在应用程序中启动操作。可以给 Button 添加一个自定义图标。也可以将 Button 的行为从按下改为切换。在单击切换 Button 后,它将保持按下状态,直到再次单击时才会返回到弹起状态。Button 是许多表单和 Web 应用程序的基础部分。每当您需要让用户启动一个事件时,都可以使用按钮实现。例如,大多数表单都有“提交”按钮。您也可以给演示文稿添加“上一个”和“下一个”按钮。

    创建具有 Button 组件的应用程序:

    1. 创建一个新的 Flash 文件 (ActionScript 3.0) 文档。
    2. 将一个 Button 组件从“组件”面板拖到舞台上,并在“属性”检查器中为该组件输入以下值:

    ■ 输入实例名称 aButton。
    ■ 为 label 参数输入 Show。

    3. 在舞台上添加 ColorPicker,并为它指定实例名称 aCp。
    4. 打开“动作”面板,在主时间轴中选择第 1 帧,然后输入以下 ActionScript 代码:

    复制代码

    1. aCp.visible = false;
    2. aButton.addEventListener(MouseEvent.CLICK, clickHandler);
    3. function clickHandler(event:MouseEvent):void {
    4. switch(event.currentTarget.label) {
    5. case “Show”:
    6. aCp.visible = true;
    7. aButton.label = “Disable”;
    8. break;
    9. case “Disable”:
    10. aCp.enabled = false;
    11. aButton.label = “Enable”;
    12. break;
    13. case “Enable”:
    14. aCp.enabled = true;
    15. aButton.label = “Hide”;
    16. break;
    17. case “Hide”:
    18. aCp.visible = false;
    19. aButton.label = “Show”;
    20. break;
    21. }
    22. }

    第二行代码将函数 clickHandler() 注册为 MouseEvent.CLICK 事件的事件处理函数。用户单击 Button 时,事件将发生,从而使 clickHandler() 函数根据 Button 的值执行以下操作之一:

    复制代码

    1. ■ Show 使 ColorPicker 可见,并将 Button 的标签更改为 Disable。
    2. ■ Disable 禁用 ColorPicker,并将 Button 的标签更改为 Enable。
    3. ■ Enable 启用 ColorPicker,并将 Button 的标签更改为 Hide。
    4. ■ Hide 使 ColorPicker 不可见,并将 Button 的标签更改为 Show。

    5. 选择“控制” > “测试影片”,运行应用程序。

    使用 ActionScript 代码创建 Button:

    1. 创建一个新的 Flash 文件 (ActionScript 3.0) 文档。

    2. 将 Button 组件从“组件”面板拖到当前文档的“库”面板中。此操作将组件添加到库中,但不会在应用程序中显示它。

    3. 打开“动作”面板,在主时间轴中选择第 1 帧,然后输入以下代码创建一个 Button 实例 :

    复制代码

    1. import fl.controls.Button;
    2. var aButton:Button = new Button();
    3. addChild(aButton);
    4. aButton.label = “Click me”;
    5. aButton.toggle = true;
    6. aButton.move(50, 50);

    move() 方法将按钮放在舞台的 50 (x 坐标) , 50 (y 坐标)位置。

    4. 现在,添加以下 ActionScript 来创建一个事件侦听器和一个事件处理函数:

    复制代码

    1. aButton.addEventListener(MouseEvent.CLICK, clickHandler);
    2. function clickHandler(event:MouseEvent):void {
    3. trace(“Event type: ” + event.type);
    4. }

    5. 选择“控制” > “测试影片”。

    单击按钮时, Flash 会在“输出”面板中显示消息“事件类型: 单击”。

     

    创建 Greetings 应用程序

    下列步骤使用 Flash 创作工具创建 FLA 文件、将组件放置在“舞台”上、向“时间轴”添加 ActionScript 代码,从而创建 Greetings 应用程序。

    在 FLA 文件中创建 Greetings 应用程序:

    1. 选择“文件” > “新建”。

    2. 在“新建文档”对话框中,选择“Flash 文件 (ActionScript 3.0)”,然后单击“确定”。打开一个新的 Flash 窗口。

    3. 选择“文件”>“保存”,将 Flash 文件命名为 Greetings.fla,然后单击“保存”按钮。

    4. 在 Flash 组件面板中,选择一个 TextArea 组件,并将其拖到“舞台”上。

    5. 在“属性”窗口中,选择“舞台”上的 TextArea 后,请键入 aTa 作为实例名,然后输入下列信息:

    ■ 输入 230 作为 W 值(宽)。

    ■ 输入 44 作为 H 值(高)。

    ■ 输入 165 作为 X 值(水平位置)。

    ■ 输入 57 作为 Y 值(垂直位置)。

    ■ 在“参数”选项卡上输入“Hello World!”作为文本参数。

    6. 将 ColorPicker 组件拖到舞台上,放在 TextArea 的左侧,并为其指定实例名称“txtCp”。在“属性”检查器中输入下列信息:

    ■ 输入 96 作为 X 值。

    ■ 输入 72 作为 Y 值。

    7. 将三个 RadioButton 组件拖到“舞台”上,分别为组件指定实例名称 smallRb、largerRb 和 largestRb。在“属性”检查器中为它们输入下列信息:

    ■ 为每个组件输入 100 作为 W 值,输入 22 作为 H 值。

    ■ 输入 155 作为 X 值。

    ■ 输入 120 作为 smallRb 的 Y 值,输入 148 作为 largerRb 的 Y 值,输入 175 作为largestRb 的 Y 值。

    ■ 输入 fontRbGrp 作为每个组件的 groupName 参数。

    ■ 在组件的“参数”选项卡输入 Small、Larger 和 Largest 作为标签。

    8. 将一个 ComboBox 拖到“舞台”上,并为其指定实例名称 msgCb。在“属性”检查器中为其输入下列信息:

    ■ 输入 130 作为 W 值。

    ■ 输入 265 作为 X 值。

    ■ 输入 120 作为 Y 值。

    ■ 在“参数”选项卡上,输入“Greetings”作为提示参数。

    ■ 双击 dataProvider 参数的文本字段以打开“值”对话框。

    ■ 单击加号,然后用“Hello World!”替换标签值

    ■ 重复上一步骤,添加 Have a nice day! 和 Top of the Morning! 标签值

    ■ 单击“确定”以关闭“值”对话框。

    9. 保存该文件。

    10. 如果尚未打开,请通过按 F9 或从“窗口”菜单选择“动作”以打开“动作”面板。单击主时间轴的第 1 帧,然后在“动作”面板中输入下面的代码:

    复制代码

    import flash.events.Event;

    import fl.events.ComponentEvent;

    import fl.events.ColorPickerEvent;

    import fl.controls.RadioButtonGroup;

    var rbGrp:RadioButtonGroup = RadioButtonGroup.getGroup(“fontRbGrp”);

    rbGrp.addEventListener(MouseEvent.CLICK, rbHandler);

    txtCp.addEventListener(ColorPickerEvent.CHANGE,cpHandler);

    msgCb.addEventListener(Event.CHANGE, cbHandler);

     

    前三行导入应用程序使用的事件类。用户与组件之一进行交互时,会发生事件。接下来的五行为应用程序希望侦听的事件注册事件处理函数。用户单击 RadioButton 时发生 click 事件。用户在 ColorPicker 中选择其它颜色时发生 change 事件。用户从 ComboBox 的下拉列表选择其它问候时发生 change 事件。第四行导入 RadioButtonGroup 类以便应用程序可以为一组 RadioButton 分配事件侦听器,而不是分别为每个按钮分配侦听器。

    11. 将下面一行代码添加到“动作”面板以创建 tf TextFormat 对象,应用程序使用此对象更改 TextArea 中文本的 size 和 color 样式属性。

    复制代码

    var tf:TextFormat = new TextFormat();

     

    12. 添加下列代码以创建 rbHandler 事件处理函数。在用户单击其中一个 RadioButton 组件时,此函数处理 click 事件。

    复制代码

    function rbHandler(event:MouseEvent):void {

    switch(event.target.selection.name) {

    case “smallRb”:

    tf.size = 14;

    break;

    case “largerRb”:

    tf.size = 18;

    break;

    case “largestRb”:

    tf.size = 24;

    break;

    }

    aTa.setStyle(“textFormat”, tf);

    }

     

    此函数使用 switch 语句检查 event 对象的 target 属性,以确定哪个 RadioButton 触发了事件。currentTarget 属性包含触发事件的对象名称。根据用户单击的是哪个 RadioButton,应用程序将 TextArea 中文本的大小更改为 14、18 或 24 磅。

    13. 添加下列代码以实现 cpHandler() 函数,此函数处理 ColorPicker 中的值的更改:

    复制代码

    function cpHandler(event:ColorPickerEvent):void {

    tf.color = event.target.selectedColor;

    aTa.setStyle(“textFormat”, tf);

    }

     

    此函数将 tf TextFormat 对象的 color 属性设置为 ColorPicker 中选定的颜色,然后调用 setStyle() 将此颜色应用到 aTa TextArea 实例中的文本。

    14. 添加下列代码以实现 cbHandler() 函数,此函数处理 ComboBox 中选择的更改:

    复制代码

    function cbHandler(event:Event):void {

    aTa.text = event.target.selectedItem.label;

    }

     

    此函数只是将 TextArea 中的文本替换为 ComboBox 中选择的文本(event.target.selectedItem.label)。

    15. 选择“控制”>“测试影片”或按 Ctrl+Enter 编译代码,然后测试 Greetings 应用程序。

    第一帧的全部代码:

    复制代码

    import flash.events.Event;

    import fl.events.ComponentEvent;

    import fl.events.ColorPickerEvent;

    import fl.controls.RadioButtonGroup;

    var rbGrp:RadioButtonGroup=RadioButtonGroup.getGroup(“fontRbGrp”);

    rbGrp.addEventListener(MouseEvent.CLICK, rbHandler);

    txtCp.addEventListener(ColorPickerEvent.CHANGE,cpHandler);

    msgCb.addEventListener(Event.CHANGE, cbHandler);

    var tf:TextFormat = new TextFormat();

    function rbHandler(event:MouseEvent):void {

    switch (event.target.selection.name) {

    case “smallRb” :

    tf.size=14;

    break;

    case “largerRb” :

    tf.size=18;

    break;

    case “largestRb” :

    tf.size=24;

    break;

    }

    aTa.setStyle(“textFormat”, tf);

    }

    function cpHandler(event:ColorPickerEvent):void {

    tf.color=event.target.selectedColor;

    aTa.setStyle(“textFormat”, tf);

    }

    function cbHandler(event:Event):void {

    aTa.text=event.target.selectedItem.label;

    }

     

    下面的部分向您演示如何使用外部的 ActionScript 类,以及其“库”中只有必需组件的 FLA文件构建相同的应用程序。

     

     

    使用外部类文件创建 Greetings2 应用程序:

    1. 选择“文件” > “新建”。

    2. 在“新建文档”对话框中,选择“Flash 文件 (ActionScript 3.0)”,然后单击“确定”。打开一个新的 Flash 窗口。

    3. 选择“文件” > “保存”,将 Flash 文件命名为“Greetings2.fla”,然后单击“保存”按钮。

    4. 将下列各个组件从“组件”面板拖到“库”中:

    ■ ColorPicker

    ■ ComboBox

    ■ RadioButton

    ■ TextArea

    因为编译的 SWF 文件会使用所有资源,所以您需要将资源都添加到“库”中。将组件拖到“库”面板的底部。在您将这些组件添加到“库”中时,会自动添加其它资源(List、

    TextInput 和 UIScrollBox)。

    5. 在“属性”窗口中,为“文档类”键入 Greetings2。

    如果 Flash 显示一个“无法找到该文档类的定义”的警告,请忽略。您将按下面步骤定义 Greetings2 类。此类定义应用程序的主要功能。

    6. 保存 Greetings2.fla 文件。

    7. 选择“文件” > “新建”。

    8. 在“新建文档”对话框中,选择“ActionScript 文件”,然后单击“确定”。打开一个新的脚本窗口。

    9. 在脚本窗口中添加下列代码:

    package {

    import flash.display.Sprite;

    import flash.events.Event;

    import flash.events.MouseEvent;

    import flash.text.TextFormat;

    import fl.events.ComponentEvent;

    import fl.events.ColorPickerEvent;

    import fl.controls.ColorPicker;

    import fl.controls.ComboBox;

    import fl.controls.RadioButtonGroup;

    import fl.controls.RadioButton;

    import fl.controls.TextArea;

    public class Greetings2 extends Sprite {

    private var aTa:TextArea;

    private var msgCb:ComboBox;

    private var smallRb:RadioButton;

    private var largerRb:RadioButton;

    private var largestRb:RadioButton;

    private var rbGrp:RadioButtonGroup;

    private var txtCp:ColorPicker;

    private var tf:TextFormat = new TextFormat();

    public function Greetings2() {

    脚本定义一个名为 Greetings2 的 ActionScript 3.0 类。脚本进行以下操作:

    ■ 导入我们将要在文件中使用的类。通常情况下,您可以在代码中引用其它类时添加这些导入语句,但为了简便起见,此示例将所有这些语句在一个步骤中导入。

    ■ 声明变量以表示我们将要添加到代码中的组件对象的不同类型。另一个变量创建 tfTextFormat 对象。

    ■ 为类定义构造函数 Greetings2()。我们将这些行添加到此函数中,并按下列步骤向类添加其它方法。

    10. 选择“文件” > “保存”,将文件命名为“Greetings2.as”,然后单击“保存”按钮。

    11. 向 Greeting2() 函数添加下列代码行:

    createUI();

    setUpHandlers();

    }

    此函数现在应该如下所示:

    public function Greetings2() {

    createUI();

    setUpHandlers();

    }

    12. 在 Greeting2() 方法的右括号后添加下列代码行:

    private function createUI() {

    bldTxtArea();

    bldColorPicker();

    bldComboBox();

    bldRadioButtons();

    }

    private function bldTxtArea() {

    aTa = new TextArea();

    aTa.setSize(230, 44);

    aTa.text = “Hello World!”;

    aTa.move(165, 57);

    addChild(aTa);

    }

    private function bldColorPicker() {

    txtCp = new ColorPicker();

    txtCp.move(96, 72);

    addChild(txtCp);

    }

    private function bldComboBox() {

    msgCb = new ComboBox();

    msgCb.width = 130;

    msgCb.move(265, 120);

    msgCb.prompt = “Greetings”;

    msgCb.addItem({data:”Hello.”, label:”English”});

    msgCb.addItem({data:”Bonjour.”, label:”Français”});

    msgCb.addItem({data:”¡Hola!”, label:”Español”});

    addChild(msgCb);

    }

    private function bldRadioButtons() {

    rbGrp = new RadioButtonGroup(“fontRbGrp”);

    smallRb = new RadioButton();

    smallRb.setSize(100, 22);

    smallRb.move(155, 120);

    smallRb.group = rbGrp; //”fontRbGrp”;

    smallRb.label = “Small”;

    smallRb.name = “smallRb”;

    addChild(smallRb);

    largerRb = new RadioButton();

    largerRb.setSize(100, 22);

    largerRb.move(155, 148);

    largerRb.group = rbGrp;

    largerRb.label = “Larger”;

    largerRb.name = “largerRb”;

    addChild(largerRb);

    largestRb = new RadioButton();

    largestRb.setSize(100, 22);

    largestRb.move(155, 175);

    largestRb.group = rbGrp;

    largestRb.label = “Largest”;

    largestRb.name = “largestRb”;

    addChild(largestRb);

    }

    这些行执行下列操作:

    ■ 实例化应用程序中使用的组件。

    ■ 设置每个组件的大小、位置和属性。

    ■ 使用 addChild() 方法将各个组件添加到舞台上。

    13. 在 bldRadioButtons() 方法的右括号后,添加 setUpHandlers() 方法的下列代码:

    private function setUpHandlers():void {

    rbGrp.addEventListener(MouseEvent.CLICK, rbHandler);

    txtCp.addEventListener(ColorPickerEvent.CHANGE,cpHandler);

    msgCb.addEventListener(Event.CHANGE, cbHandler);

    }

    private function rbHandler(event:MouseEvent):void {

    switch(event.target.selection.name) {

    case “smallRb”:

    tf.size = 14;

    break;

    case “largerRb”:

    tf.size = 18;

    break;

    case “largestRb”:

    tf.size = 24;

    break;

    }

    aTa.setStyle(“textFormat”, tf);

    }

    private function cpHandler(event:ColorPickerEvent):void {

    tf.color = event.target.selectedColor;

    aTa.setStyle(“textFormat”, tf);

    }

    private function cbHandler(event:Event):void {

    aTa.text = event.target.selectedItem.data;

    }

    }

    }

    这些函数定义组件的事件侦听器。

    14. 选择“文件” > “保存”以保存文件。

    15. 选择“控制”>“测试影片”或按 Ctrl+Enter 编译代码,然后测试 Greetings2 应用程序。

     

     

    创建 Greetings 应用程序

    下列步骤使用 Flash 创作工具创建 FLA 文件、将组件放置在“舞台”上、向“时间轴”添加 ActionScript 代码,从而创建 Greetings 应用程序。

    在 FLA 文件中创建 Greetings 应用程序:
    1. 选择“文件” > “新建”。
    2. 在“新建文档”对话框中,选择“Flash 文件 (ActionScript 3.0)”,然后单击“确定”。打开一个新的 Flash 窗口。
    3. 选择“文件”>“保存”,将 Flash 文件命名为 Greetings.fla,然后单击“保存”按钮。
    4. 在 Flash 组件面板中,选择一个 TextArea 组件,并将其拖到“舞台”上。
    5. 在“属性”窗口中,选择“舞台”上的 TextArea 后,请键入 aTa 作为实例名,然后输入下列信息:

    ■ 输入 230 作为 W 值(宽)。
    ■ 输入 44 作为 H 值(高)。
    ■ 输入 165 作为 X 值(水平位置)。
    ■ 输入 57 作为 Y 值(垂直位置)。
    ■ 在“参数”选项卡上输入“Hello World!”作为文本参数。

    6. 将 ColorPicker 组件拖到舞台上,放在 TextArea 的左侧,并为其指定实例名称“txtCp”。在“属性”检查器中输入下列信息:

    ■ 输入 96 作为 X 值。
    ■ 输入 72 作为 Y 值。

    7. 将三个 RadioButton 组件拖到“舞台”上,分别为组件指定实例名称 smallRb、largerRb 和 largestRb。在“属性”检查器中为它们输入下列信息:

    ■ 为每个组件输入 100 作为 W 值,输入 22 作为 H 值。
    ■ 输入 155 作为 X 值。
    ■ 输入 120 作为 smallRb 的 Y 值,输入 148 作为 largerRb 的 Y 值,输入 175 作为largestRb 的 Y 值。
    ■ 输入 fontRbGrp 作为每个组件的 groupName 参数。
    ■ 在组件的“参数”选项卡输入 Small、Larger 和 Largest 作为标签。

    8. 将一个 ComboBox 拖到“舞台”上,并为其指定实例名称 msgCb。在“属性”检查器中为其输入下列信息:

    ■ 输入 130 作为 W 值。
    ■ 输入 265 作为 X 值。
    ■ 输入 120 作为 Y 值。
    ■ 在“参数”选项卡上,输入“Greetings”作为提示参数。
    ■ 双击 dataProvider 参数的文本字段以打开“值”对话框。
    ■ 单击加号,然后用“Hello World!”替换标签值
    ■ 重复上一步骤,添加 Have a nice day! 和 Top of the Morning! 标签值
    ■ 单击“确定”以关闭“值”对话框。

    9. 保存该文件。
    10. 如果尚未打开,请通过按 F9 或从“窗口”菜单选择“动作”以打开“动作”面板。单击主时间轴的第 1 帧,然后在“动作”面板中输入下面的代码:

    复制代码

    1. import flash.events.Event;
    2. import fl.events.ComponentEvent;
    3. import fl.events.ColorPickerEvent;
    4. import fl.controls.RadioButtonGroup;
    5. var rbGrp:RadioButtonGroup = RadioButtonGroup.getGroup(“fontRbGrp”);
    6. rbGrp.addEventListener(MouseEvent.CLICK, rbHandler);
    7. txtCp.addEventListener(ColorPickerEvent.CHANGE,cpHandler);
    8. msgCb.addEventListener(Event.CHANGE, cbHandler);

    前三行导入应用程序使用的事件类。用户与组件之一进行交互时,会发生事件。接下来的五行为应用程序希望侦听的事件注册事件处理函数。用户单击 RadioButton 时发生 click 事件。用户在 ColorPicker 中选择其它颜色时发生 change 事件。用户从 ComboBox 的下拉列表选择其它问候时发生 change 事件。第四行导入 RadioButtonGroup 类以便应用程序可以为一组 RadioButton 分配事件侦听器,而不是分别为每个按钮分配侦听器。

    11. 将下面一行代码添加到“动作”面板以创建 tf TextFormat 对象,应用程序使用此对象更改 TextArea 中文本的 size 和 color 样式属性。

    复制代码

    1. var tf:TextFormat = new TextFormat();

    12. 添加下列代码以创建 rbHandler 事件处理函数。在用户单击其中一个 RadioButton 组件时,此函数处理 click 事件。

    复制代码

    1. function rbHandler(event:MouseEvent):void {
    2. switch(event.target.selection.name) {
    3. case “smallRb”:
    4. tf.size = 14;
    5. break;
    6. case “largerRb”:
    7. tf.size = 18;
    8. break;
    9. case “largestRb”:
    10. tf.size = 24;
    11. break;
    12. }
    13. aTa.setStyle(“textFormat”, tf);
    14. }

    此函数使用 switch 语句检查 event 对象的 target 属性,以确定哪个 RadioButton 触发了事件。currentTarget 属性包含触发事件的对象名称。根据用户单击的是哪个 RadioButton,应用程序将 TextArea 中文本的大小更改为 14、18 或 24 磅。
    13. 添加下列代码以实现 cpHandler() 函数,此函数处理 ColorPicker 中的值的更改:

    复制代码

    1. function cpHandler(event:ColorPickerEvent):void {
    2. tf.color = event.target.selectedColor;
    3. aTa.setStyle(“textFormat”, tf);
    4. }

    此函数将 tf TextFormat 对象的 color 属性设置为 ColorPicker 中选定的颜色,然后调用 setStyle() 将此颜色应用到 aTa TextArea 实例中的文本。
    14. 添加下列代码以实现 cbHandler() 函数,此函数处理 ComboBox 中选择的更改:

    复制代码

    1. function cbHandler(event:Event):void {
    2. aTa.text = event.target.selectedItem.label;
    3. }

    此函数只是将 TextArea 中的文本替换为 ComboBox 中选择的文本(event.target.selectedItem.label)。
    15. 选择“控制”>“测试影片”或按 Ctrl+Enter 编译代码,然后测试 Greetings 应用程序。

    第一帧的全部代码:

    复制代码

    1. import flash.events.Event;
    2. import fl.events.ComponentEvent;
    3. import fl.events.ColorPickerEvent;
    4. import fl.controls.RadioButtonGroup;
    5. var rbGrp:RadioButtonGroup=RadioButtonGroup.getGroup(“fontRbGrp”);
    6. rbGrp.addEventListener(MouseEvent.CLICK, rbHandler);
    7. txtCp.addEventListener(ColorPickerEvent.CHANGE,cpHandler);
    8. msgCb.addEventListener(Event.CHANGE, cbHandler);
    9. var tf:TextFormat = new TextFormat();
    10. function rbHandler(event:MouseEvent):void {
    11.     switch (event.target.selection.name) {
    12.         case “smallRb” :
    13.             tf.size=14;
    14.             break;
    15.         case “largerRb” :
    16.             tf.size=18;
    17.             break;
    18.         case “largestRb” :
    19.             tf.size=24;
    20.             break;
    21.     }
    22.     aTa.setStyle(“textFormat”, tf);
    23. }
    24. function cpHandler(event:ColorPickerEvent):void {
    25.     tf.color=event.target.selectedColor;
    26.     aTa.setStyle(“textFormat”, tf);
    27. }
    28. function cbHandler(event:Event):void {
    29.     aTa.text=event.target.selectedItem.label;
    30. }
     
     
    分类
    Flash professional

    Adding Game Effects

     Adding Game Effects

    Let’s spruce up this simple matching game with some special effects. Although they won’t change the basic game play, they will make the game seem a lot more interesting to players.

    Animated Card Flips

    Because this animation affects the cards, and only the cards, it makes sense to put it inside the Card class.

    However, we don’t have a Card class. Now it is time to create Card class.

    This class will enable an animated flip of the card, rather than just changing the card instantly. It will replace all the gotoAndStop functions in the main class. Instead, it will
    tell the card to fanPai. It also passes in the frame which the card should show when the flip is over. The Card class will then set up some variables, set up an event listener,
    and proceed to animate the card over the next ten frames:

    Card1.as

    复制代码

    1. package {
    2.     import flash.display.*;
    3.     import flash.events.*;
    4.     public dynamic class Card1 extends MovieClip {
    5.         private var buS:uint;
    6.         private var fan:Boolean=false;
    7.         private var zhenS:uint;
    8.         // begin the flip, remember which frame to jump to
    9.         public function fanPai(frame:uint) {
    10.             fan=true;
    11.             buS=10;
    12.             zhenS=frame;
    13.             this.addEventListener(Event.ENTER_FRAME, bianPai);
    14.         }
    15.         // take 10 steps to flip
    16.         public function bianPai(event:Event) {
    17.             buS–;// next step
    18.             if (buS>5) {// first half of flip
    19.                 this.scaleX = .2*(buS-6);
    20.             } else {// second half of flip
    21.                 this.scaleX = .2*(5-buS);
    22.             }
    23.             // when it is the middle of the flip, go to new frame
    24.             if (buS==5) {
    25.                 this.gotoAndStop(zhenS);
    26.             }
    27.             // at the end of the flip, stop the animation
    28.             if (buS==0) {
    29.                 this.removeEventListener(Event.ENTER_FRAME, bianPai);
    30.             }
    31.         }
    32.     }
    33. }

     

     Limited Card-Viewing Time

    Another nice touch to this game is to automatically turn over pairs of mismatched cards after the player has had enough time to look at them. For instance, the player chooses two cards. They don’t match, so they remain face up for the player to inspect. After two seconds, however, the cards turn over, even if the player hasn’t begun to select another pair.

    To accomplish this, we’ll use a Timer. To start, we’ll need to import the Timer class into our main class:

    复制代码

    1. import flash.utils.Timer;

    Next, we create a timer variable at the start of the class:

    复制代码

    1. private var puPaiT:Timer;

    Later on in the fanPai function, we add some code right after the player has chosen the second card, not made a match, and his or her score has been decreased. This Timer code will set up the new timer, which will simply call a function when two seconds have gone by:

    复制代码

    1. puPaiT = new Timer(2000,1);
    2. puPaiT.addEventListener(TimerEvent.TIMER_COMPLETE,puPai);
    3. puPaiT.start();

    The TimerEvent.TIMER_COMPLETE event is triggered when a timer is done. Typically, a Timer runs a certain number of times, triggering a TimerEvent.TIMER each time. Then,
    on the last event, it also triggers the TimerEvent.TIMER_COMPLETE. Because we only want to trigger a single event at some point in the future, we just set the number of  imer
    events to one, and then look for TimerEvent.TIMER_COMPLETE.

    When two seconds go by, the  puPai function is called. This is a new function that works just like the later part of the old clickCard function. It flips both the first and second selections back to the face-down state, and then sets the firstCard and secondCard values to null. It also removed the listener:

    复制代码

    1. public function puPai(e:TimerEvent) {
    2. fpai1.fanPai(1);
    3. pai2.fanPai(1);
    4. pai1=null;
    5. pai2=null;
    6. puPaiT.removeEventListener(TimerEvent.TIMER_COMPLETE,puPai);
    7. }
    复制代码

    1. package {
    2.     import flash.display.*;
    3.     import flash.events.*;
    4.     import flash.text.*;
    5.     import flash.utils.getTimer;
    6.     import flash.utils.Timer;
    7.     public class Mygame1 extends MovieClip {
    8.         private static const paiKuan:Number=84+2;
    9.         private static const paiGao:Number=125+2;
    10.         private static const jiafen:int=100;
    11.         private static const jianfen:int=-5;
    12.         private var paiX:uint=Math.floor((stage.stageWidth-340)/paiKuan);
    13.         private var paiY:uint=Math.floor((stage.stageHeight-260)/paiGao);
    14.         private var bianX:Number=(stage.stageWidth-(paiX-1)*paiKuan)/2-1;
    15.         private var bianY:Number=(stage.stageHeight-(paiY-1)*paiGao)/2-1;
    16.         private var pai1:Card1;
    17.         private var pai2:Card1;
    18.         private var cardsLeft:uint=0;
    19.         private var paiShu:uint=10;
    20.         private var fenshu:TextField;
    21.         private var defen:int;
    22.         private var geshi:TextFormat;
    23.         private var jishi:TextField;
    24.         private var kaishiT:uint;
    25.         private var youxiT:uint;
    26.         private var puPaiT:Timer;
    27.         public function Mygame1():void {
    28.             var pai:Card1=new Card1();
    29.             paiShu=pai.totalFrames;
    30.             var myCards:Array=new Array();
    31.             for (var j:uint=2; j<paiShu+2; j++) {
    32.                 myCards.push(j);
    33.             }
    34.             var cardlist:Array=new Array();
    35.             /*if (paiX*paiY/2!=0) {
    36.             paiY–;
    37.             bianY+=paiGao/2;
    38.             }*/
    39.             for (var i:uint=0; i<paiX*paiY/2; i++) {
    40.                 var r0:uint=Math.floor(Math.random()*myCards.length);
    41.                 cardlist.push(myCards[r0]);
    42.                 cardlist.push(myCards[r0]);
    43.                 myCards.splice(r0,1);
    44.             }
    45.             //trace(cardlist);
    46.             for (var x:uint=0; x<paiX; x++) {
    47.                 for (var y:uint=0; y<paiY; y++) {
    48.                     var c:Card1 = new Card1();
    49.                     c.stop();
    50.                     c.buttonMode=true;
    51.                     c.height=paiGao-2;
    52.                     c.width=paiKuan-2;
    53.                     c.x=x*paiKuan+bianX;
    54.                     c.y=y*paiGao+bianY;
    55.                     var r:uint=Math.floor(Math.random()*cardlist.length);
    56.                     c.cardface=cardlist[r];
    57.                     cardlist.splice(r,1);
    58.                     //c.gotoAndStop(c.cardface);
    59.                     addChild(c);
    60.                     cardsLeft++;
    61.                     c.addEventListener(MouseEvent.CLICK,fanPai);
    62.                 }
    63.             }
    64.             //trace(myCards);
    65.             defen=0;
    66.             fenshu = new TextField();
    67.             fenshu.width=200;
    68.             addChild(fenshu);
    69.             xiandefen();
    70.             jishi = new TextField();
    71.             jishi.x=stage.stageWidth-200;
    72.             jishi.width=200;
    73.             addChild(jishi);
    74.             kaishiT=getTimer();
    75.             youxiT=0;
    76.             addEventListener(Event.ENTER_FRAME,xianT);
    77.         }
    78.         public function fanPai(evt:MouseEvent) {
    79.             var paiN:Card1=(evt.target as Card1);
    80.             if (pai1==null) {
    81.                 pai1=paiN;
    82.                 paiN.fanPai(paiN.cardface);
    83.             } else if (pai2==null) {
    84.                 if (paiN==pai1) {
    85.                     pai1.fanPai(1);
    86.                     pai1=null;
    87.                 } else {
    88.                     pai2=paiN;
    89.                     paiN.fanPai(paiN.cardface);
    90.                     if (pai1.cardface==pai2.cardface) {
    91.                         removeChild(pai1);
    92.                         removeChild(pai2);
    93.                         pai1=null;
    94.                         pai2=null;
    95.                         defen+=jiafen;
    96.                         xiandefen();
    97.                         cardsLeft-=2;
    98.                         if (cardsLeft<2) {
    99.                             MovieClip(root).fenShu=defen;
    100.                             MovieClip(root).shiJian=fenmiaoT(youxiT);
    101.                             MovieClip(root).gotoAndStop(“gameover”);
    102.                         }
    103.                     } else {
    104.                         defen+=jianfen;
    105.                         xiandefen();
    106.                         puPaiT=new Timer(2000,1);
    107.                         puPaiT.addEventListener(TimerEvent.TIMER_COMPLETE,puPai);
    108.                         puPaiT.start();
    109.                     }
    110.                 }
    111.             } else {
    112.                 puPai(null);
    113.                 pai1=paiN;
    114.                 pai2=null;
    115.                 paiN.fanPai(paiN.cardface);
    116.             }
    117.         }
    118.         public function xiandefen() {
    119.             fenshu.text=”你的得分: “+String(defen);
    120.             geshi= new TextFormat( );
    121.             geshi.color=0xff0000;
    122.             geshi.bold=true;
    123.             geshi.size=24;
    124.             fenshu.setTextFormat(geshi);
    125.         }
    126.         public function xianT(evt:Event) {
    127.             youxiT=getTimer()-kaishiT;
    128.             jishi.text=”使用时间:”+fenmiaoT(youxiT);
    129.             geshi= new TextFormat( );
    130.             geshi.color=0xff0000;
    131.             geshi.bold=true;
    132.             geshi.size=24;
    133.             jishi.setTextFormat(geshi);
    134.         }
    135.         public function fenmiaoT(fm:int) {
    136.             var miao:int=Math.floor(fm/1000);
    137.             var fen:int=Math.floor(miao/60);
    138.             miao-=fen*60;
    139.             //var fenmiaoZ:String=fen+”:”+miao;
    140.             var fenmiaoZ:String=fen+”:”+String(miao+100).substr(1,2);
    141.             return fenmiaoZ;
    142.         }
    143.         public function puPai(e:TimerEvent) {
    144.             pai1.fanPai(1);
    145.             pai2.fanPai(1);
    146.             pai1=null;
    147.             pai2=null;
    148.             puPaiT.removeEventListener(TimerEvent.TIMER_COMPLETE,puPai);
    149.         }
    150.     }
    151. }

    Sound Effects

    ActionScript 3.0 makes adding sound relatively easy, although there are quite a few steps involved.

    The first step is to import your sounds. I’ve created three sounds and want to bring them each into the library:

    复制代码

    1. Dan.aiff
    2. Cuo.aiff
    3. Dui.aiff

    After we have imported them, they need to have properties changed. Name them all after their filenames, but minus the .aiff. Also, check the Export for ActionScript option
    and give them the same class name as symbol name.

    Next, we set up the main game class to play the sounds at the right time. First, we need to import two new classes so that we can use sound:

    复制代码

    1. import flash.media.Sound;
    2. import flash.media.SoundChannel;

    Then, we create class variables to hold references to these sounds:

    复制代码

    1. var yinDan:Dan = new Dan();
    2. var yinCuo:Cuo = new Cuo();
    3. var yinDui:Dui = new Dui();

    I like to pass all sound playback through a single function. Let’s call it playSound and add it to the end of the class:

    复制代码

    1. public function playSound(snd:Object) {
    2. var shengDao1:SoundChannel = snd.play();
    3. }

    Now, when we want a sound to play, we just call playSound with the sound variable we want to use, as follows:

    复制代码

    1. playSound(yinDui);
    package {
        import flash.display.*;
        import flash.events.*;
        import flash.text.*;
        import flash.utils.getTimer;
        import flash.utils.Timer;
        import flash.media.Sound;
        import flash.media.SoundChannel;

        public class Mygame1 extends MovieClip {
            private static const paiKuan:Number=84+2;
            private static const paiGao:Number=125+2;
            private static const jiafen:int=100;
            private static const jianfen:int=-5;

            private var paiX:uint=Math.floor((stage.stageWidth-340)/paiKuan);
            private var paiY:uint=Math.floor((stage.stageHeight-260)/paiGao);
            private var bianX:Number=(stage.stageWidth-(paiX-1)*paiKuan)/2-1;
            private var bianY:Number=(stage.stageHeight-(paiY-1)*paiGao)/2-1;
            private var pai1:Card1;
            private var pai2:Card1;
            private var cardsLeft:uint=0;
            private var paiShu:uint=10;
            private var fenshu:TextField;
            private var defen:int;
            private var geshi:TextFormat;
            private var jishi:TextField;
            private var kaishiT:uint;
            private var youxiT:uint;
            private var puPaiT:Timer;
            var yinDan:Dan = new Dan();
            var yinCuo:Cuo = new Cuo();
            var yinDui:Dui = new Dui();

            public function Mygame1():void {
                var pai:Card1=new Card1();
                paiShu=pai.totalFrames;
                var myCards:Array=new Array();
                for (var j:uint=2; j<paiShu+2; j++) {
                    myCards.push(j);
                }
                var cardlist:Array=new Array();
                /*if (paiX*paiY/2!=0) {
                paiY–;
                bianY+=paiGao/2;
                }*/
                for (var i:uint=0; i<paiX*paiY/2; i++) {
                    var r0:uint=Math.floor(Math.random()*myCards.length);
                    cardlist.push(myCards[r0]);
                    cardlist.push(myCards[r0]);
                    myCards.splice(r0,1);
                }
                //trace(cardlist);
                for (var x:uint=0; x<paiX; x++) {
                    for (var y:uint=0; y<paiY; y++) {
                        var c:Card1 = new Card1();
                        c.stop();
                        c.buttonMode=true;
                        c.height=paiGao-2;
                        c.width=paiKuan-2;
                        c.x=x*paiKuan+bianX;
                        c.y=y*paiGao+bianY;
                        var r:uint=Math.floor(Math.random()*cardlist.length);
                        c.cardface=cardlist[r];
                        cardlist.splice(r,1);
                        //c.gotoAndStop(c.cardface);
                        addChild(c);
                        cardsLeft++;
                        c.addEventListener(MouseEvent.CLICK,fanPai);
                    }
                }
                //trace(myCards);
                defen=0;
                fenshu = new TextField();
                fenshu.width=200;
                addChild(fenshu);
                xiandefen();
                jishi = new TextField();
                jishi.x=stage.stageWidth-200;
                jishi.width=200;
                addChild(jishi);

                kaishiT=getTimer();
                youxiT=0;
                addEventListener(Event.ENTER_FRAME,xianT);
            }
            public function fanPai(evt:MouseEvent) {
                var paiN:Card1=(evt.target as Card1);
                if (pai1==null) {
                    pai1=paiN;
                    playSound(yinDan);
                    paiN.fanPai(paiN.cardface);
                } else if (pai2==null) {
                    if (paiN==pai1) {
                        pai1.fanPai(1);
                        pai1=null;
                    } else {
                        pai2=paiN;
                        paiN.fanPai(paiN.cardface);
                        if (pai1.cardface==pai2.cardface) {
                            playSound(yinDui);
                            removeChild(pai1);
                            removeChild(pai2);
                            pai1=null;
                            pai2=null;
                            defen+=jiafen;
                            xiandefen();
                            cardsLeft-=2;
                            if (cardsLeft<2) {
                                MovieClip(root).fenShu=defen;
                                MovieClip(root).shiJian=fenmiaoT(youxiT);
                                MovieClip(root).gotoAndStop(“gameover”);
                            }
                        } else {
                            playSound(yinCuo);
                            defen+=jianfen;
                            xiandefen();
                            puPaiT=new Timer(2000,1);
                            puPaiT.addEventListener(TimerEvent.TIMER_COMPLETE,puPai);
                            puPaiT.start();
                        }
                    }
                } else {
                    playSound(yinDan);
                    puPai(null);
                    pai1=paiN;
                    pai2=null;
                    paiN.fanPai(paiN.cardface);

                }
            }
            public function xiandefen() {
                fenshu.text=”你的得分: “+String(defen);
                geshi= new TextFormat( );
                geshi.color=0xff0000;
                geshi.bold=true;
                geshi.size=24;
                fenshu.setTextFormat(geshi);
            }
            public function xianT(evt:Event) {
                youxiT=getTimer()-kaishiT;
                jishi.text=”使用时间:”+fenmiaoT(youxiT);
                geshi= new TextFormat( );
                geshi.color=0xff0000;
                geshi.bold=true;
                geshi.size=24;
                jishi.setTextFormat(geshi);
            }
            public function fenmiaoT(fm:int) {
                var miao:int=Math.floor(fm/1000);
                var fen:int=Math.floor(miao/60);
                miao-=fen*60;
                //var fenmiaoZ:String=fen+”:”+miao;
                var fenmiaoZ:String=fen+”:”+String(miao+100).substr(1,2);
                return fenmiaoZ;
            }
            public function puPai(e:TimerEvent) {
                pai1.fanPai(1);
                pai2.fanPai(1);
                pai1=null;
                pai2=null;
                puPaiT.removeEventListener(TimerEvent.TIMER_COMPLETE,puPai);
            }
            public function playSound(snd:Object) {
                var shengDao1:SoundChannel=snd.play();
            }
        }
    }

    MyGame.swf (1675 K) 下载次数:6 [试播]

    分类
    Flash professional

    游戏的封装

     游戏的封装

    .fla:

    create a new class variable named cardsLeft:

    复制代码

    1. private var cardsLeft:uint;

    Then, set it to zero just before the for loops that create the cards. And, add one to this variable for every card created:

    复制代码

    1. cardsLeft = 0;
    2. for…
    3. addChild(c);
    4. cardsLeft++;
    5. }
    6. }

    Then, in the clickCard function, we need to add new code when the user makes a match and the cards are removed from the screen: This goes in the clickCard function.

    复制代码

    1. cardsLeft -= 2;
    2. if (cardsLeft == 0) {
    3. gotoAndStop(“gameover”);
    4. }

    第一帧:(startgame)
    stop();
    game0Button.addEventListener(MouseEvent.CLICK,playgame1);
    function playgame0(event:MouseEvent) {
        gotoAndStop(“game0”);
    }

    第二帧:(game0)

    左上角放置 Mygame0 的实例。

    第三帧:(gameover)
    playAgainButton.addEventListener(MouseEvent.CLICK,playAgain);
    function playAgain(event:MouseEvent) {
        gotoAndStop(“startgame”);
    }

    复制代码

    1. package {
    2.     import flash.display.*;
    3.     import flash.events.*;
    4.     public class Mygame0 extends MovieClip {
    5.         private static const paiKuan:Number=100+2;
    6.         private static const paiGao:Number=150+2;
    7.         private var paiX:Number=Math.floor((stage.stageWidth-200)/paiKuan);
    8.         private var paiY:uint=Math.floor((stage.stageHeight-160)/paiGao);
    9.         private var bianX:Number=(stage.stageWidth-paiX*paiKuan)/2;
    10.         private var bianY:Number=(stage.stageHeight-paiY*paiGao)/2;
    11.         private var pai1:Card;
    12.         private var pai2:Card;
    13.         private var cardsLeft:uint=0;
    14.         private var paiShu:uint=10;
    15.         public function Mygame0():void {
    16.             var pai:Card=new Card();
    17.             paiShu=pai.totalFrames;
    18.             var myCards:Array=new Array();
    19.             for (var j:uint=2; j<paiShu+2; j++) {
    20.                 myCards.push(j);
    21.             }
    22.             var cardlist:Array=new Array();
    23.             /*if (paiX*paiY/2!=0) {
    24.             paiY–;
    25.             bianY+=paiGao/2;
    26.             }*/
    27.             for (var i:uint=0; i<paiX*paiY/2; i++) {
    28.                 var r0:uint=Math.floor(Math.random()*myCards.length);
    29.                 cardlist.push(myCards[r0]);
    30.                 cardlist.push(myCards[r0]);
    31.                 myCards.splice(r0,1);
    32.             }
    33.             //trace(cardlist);
    34.             for (var x:uint=0; x<paiX; x++) {
    35.                 for (var y:uint=0; y<paiY; y++) {
    36.                     var c:Card = new Card();
    37.                     c.stop();
    38.                     c.height=paiGao-2;
    39.                     c.width=paiKuan-2;
    40.                     c.x=x*paiKuan+bianX;
    41.                     c.y=y*paiGao+bianY;
    42.                     var r:uint=Math.floor(Math.random()*cardlist.length);
    43.                     c.cardface=cardlist[r];
    44.                     cardlist.splice(r,1);
    45.                     //c.gotoAndStop(c.cardface);
    46.                     addChild(c);
    47.                     cardsLeft++;
    48.                     c.addEventListener(MouseEvent.CLICK,fanPai);
    49.                 }
    50.             }
    51.             //trace(myCards);
    52.         }
    53.         public function fanPai(evt:MouseEvent) {
    54.             var paiN:Card=(evt.target as Card);
    55.             if (pai1==null) {
    56.                 pai1=paiN;
    57.                 paiN.gotoAndStop(paiN.cardface);
    58.             } else if (pai2==null) {
    59.                 if (paiN==pai1) {
    60.                     pai1.gotoAndStop(1);
    61.                     pai1=null;
    62.                 } else {
    63.                     pai2=paiN;
    64.                     paiN.gotoAndStop(paiN.cardface);
    65.                     if (pai1.cardface==pai2.cardface) {
    66.                         removeChild(pai1);
    67.                         removeChild(pai2);
    68.                         pai1=null;
    69.                         pai2=null;
    70.                         cardsLeft-=2;
    71.                         if (cardsLeft<2) {
    72.                             MovieClip(root).gotoAndStop(“gameover”);
    73.                         }
    74.                     }
    75.                 }
    76.             } else {
    77.                 pai1.gotoAndStop(1);
    78.                 pai2.gotoAndStop(1);
    79.                 pai1=paiN;
    80.                 pai2=null;
    81.                 paiN.gotoAndStop(paiN.cardface);
    82.             }
    83.         }
    84.     }
    85. }

    Adding Scoring and a Clock

    Two elements commonly seen in casual games are scoring and timers. Even though the matching game concept doesn’t really need them, let’s go ahead and add them to the game anyway to make it as full-featured as we can.

    Adding Scoring

    To do this, we need  a special Flash class that we need to import at the start of our program:

    复制代码

    1. import flash.text.*;
    复制代码

    1. private static const jiafen:int = 100;
    2. private static const jianfen:int = -5;

    To display the score, we need a text field.

    复制代码

    1. private var fenshu:TextField;

    Then, we need to create that text field and add it as a child:

    复制代码

    1. fenshu = new TextField();
    2. addChild(fenshu);

    The score itself will be a simple integer variable named gameScore. We’ll declare it at the start of the class:

    复制代码

    1. private var defen:int;

    And then we’ll set it to zero in the constructor function:

    复制代码

    1. defen = 0;

    In addition, it would be a good idea to immediately show the score in the text field:

    fenshu.text =”你的得分: “+String(defen);

    However, we realize at this point that there are at least several places in the code where we will set the text of gameScoreField. The first is in the constructor function. The second will be after the score changes during game play. Instead of copying and pasting the previous line of code in two places, let’s move it to a function of its own. Then, we can call the same function from each of the places in the code where we need to update the score:

    复制代码

    1. public function xiandefen() {
    2. fenshu.text =”你的得分: “+String(defen);
    3. }

    We need to change the score in two places in the code. The first is right after we find a match, just before we check to see whether the game is over:

    复制代码

    1. defen += jiafen;

    Then, we add an else clause to the if statement that checks for a match, and subtract points if the match is not found:

    复制代码

    1. defen += jianfen;

    We also put in the xiandefen() function call after each change to the score.

    复制代码

    1. package {
    2.     import flash.display.*;
    3.     import flash.events.*;
    4.     import flash.text.*;
    5.     public class Mygame1 extends MovieClip {
    6.         private static const paiShu:uint=77;
    7.         private static const paiKuan:Number=100+2;
    8.         private static const paiGao:Number=100+2;
    9.         private static const jiafen:int=100;
    10.         private static const jianfen:int=-5;
    11.         private var paiX:Number=Math.floor((stage.stageWidth-40)/paiKuan);
    12.         private var paiY:uint=Math.floor((stage.stageHeight-40)/paiGao);
    13.         private var bianX:Number=(stage.stageWidth-paiX*paiKuan)/2;
    14.         private var bianY:Number=(stage.stageHeight-paiY*paiGao)/2;
    15.         private var pai1:Card1;
    16.         private var pai2:Card1;
    17.         private var fenshu:TextField;
    18.         private var defen:int;
    19.         private var geshi:TextFormat;
    20.         public function Mygame1():void {
    21.             var myCards:Array=new Array();
    22.             for (var j:uint=2; j<paiShu+2; j++) {
    23.                 myCards.push(j);
    24.             }
    25.             var cardlist:Array=new Array();
    26.             if (paiX*paiY/2!=0) {
    27.                 paiY–;
    28.                 bianY+=paiGao/2;
    29.             }
    30.             for (var i:uint=0; i<paiX*paiY/2; i++) {
    31.                 var r0:uint=Math.floor(Math.random()*myCards.length);
    32.                 cardlist.push(myCards[r0]);
    33.                 cardlist.push(myCards[r0]);
    34.                 myCards.splice(r0,1);
    35.             }
    36.             //trace(cardlist);
    37.             for (var x:uint=0; x<paiX; x++) {
    38.                 for (var y:uint=0; y<paiY; y++) {
    39.                     var c:Card1 = new Card1();
    40.                     c.stop();
    41.                     c.height=100;
    42.                     c.width=100;
    43.                     c.x=x*paiKuan+bianX;
    44.                     c.y=y*paiGao+bianY;
    45.                     var r:uint=Math.floor(Math.random()*cardlist.length);
    46.                     c.cardface=cardlist[r];
    47.                     cardlist.splice(r,1);
    48.                     //c.gotoAndStop(c.cardface);
    49.                     addChild(c);
    50.                     c.addEventListener(MouseEvent.CLICK,fanPai);
    51.                 }
    52.             }
    53.             //trace(myCards);
    54.             fenshu = new TextField();
    55.             addChild(fenshu);
    56.             fenshu.width=300;
    57.             defen=0;
    58.             xiandefen();
    59.         }
    60.         public function fanPai(evt:MouseEvent) {
    61.             var paiN:Card1=(evt.target as Card1);
    62.             if (pai1==null) {
    63.                 pai1=paiN;
    64.                 paiN.gotoAndStop(paiN.cardface);
    65.             } else if (pai2==null) {
    66.                 if (paiN==pai1) {
    67.                     pai1.gotoAndStop(1);
    68.                     pai1=null;
    69.                 } else {
    70.                     pai2=paiN;
    71.                     paiN.gotoAndStop(paiN.cardface);
    72.                     if (pai1.cardface==pai2.cardface) {
    73.                         removeChild(pai1);
    74.                         removeChild(pai2);
    75.                         pai1=null;
    76.                         pai2=null;
    77.                         defen+=jiafen;
    78.                         xiandefen();
    79.                     } else {
    80.                         defen+=jianfen;
    81.                         xiandefen();
    82.                     }
    83.                 }
    84.             } else {
    85.                 pai1.gotoAndStop(1);
    86.                 pai2.gotoAndStop(1);
    87.                 pai1=paiN;
    88.                 pai2=null;
    89.                 paiN.gotoAndStop(paiN.cardface);
    90.             }
    91.         }
    92.         public function xiandefen() {
    93.             fenshu.text=”你的得分:”+String(defen);
    94.             geshi= new TextFormat( );
    95.             geshi.color=0x0000ff;
    96.             geshi.bold=true;
    97.             geshi.size=24;
    98.             fenshu.setTextFormat(geshi);
    99.         }
    100.     }
    101. }

    MyGame.swf (1668 K) 下载次数:1 [试播]

     
     
     
     
     
     
     

    To have a clock, we need to use the getTimer() function. This will return the time since the Flash movie started, in milliseconds. This is a special function that requires a special Flash class that we need to import at the start of our program:

    复制代码

    1. import flash.utils.getTimer;

    The getTimer function measures the number of milliseconds since the Flash movie started. However, it is never useful as a raw time measurement because the player won’t ever be starting a game the instant the movie appears on his or her screen. Instead, getTimer is useful when you take two measurements and subtract the later one from the earlier one.

    Now we will need some new variables. We need one to record the time the game started and one to store the game time:

    复制代码

    1. private var kaishiT:uint;
    2. private var youxiT:uint;

    We also need to define a new text field to display the time to the player:

    复制代码

    1. private var jishi:TextField;

    In the constructor function, we add a new text field to display the time. We also move to the right side of the screen so that it won’t be on top of the score display:

    复制代码

    1. jishi = new TextField();
    2. jishi.x = stage.stageWidth-200;
    3. jishi.width=200;
    4. addChild(jishi);

    Before the constructor function is done, we’ll want to set the gameStartTime variable. We can also set the gameTime to zero:

    复制代码

    1. kaishiT = getTimer();
    2. youxiT= 0;

    Now we need to figure out a way for the game time to update. we can create a Timer object, or we can  just have the ENTER_FRAME event trigger a function that updates the clock. In a default Flash movie, this will happen 24  times a second, which is certainly enough:

    复制代码

    1. addEventListener(Event.ENTER_FRAME,xianT);

    All that is left is to make the xianT function. It will calculate the current time based on the current value of getTimer() and the value of kaishiT.  Then, it will put it in the text field for display:

    复制代码

    1. public function xianT(evt:Event) {
    2. youxiT= getTimer()-kaishiT;
    3. jishi.text = “使用时间:”+youxiT;
    4. }

    or:

    复制代码

    1. public function xianT(evt:Event) {
    2.             youxiT=getTimer()-kaishiT;
    3.             jishi.text=”使用时间:”+youxiT;
    4.             geshi= new TextFormat( );
    5.             geshi.color=0x0000ff;
    6.             geshi.bold=true;
    7.             geshi.size=24;
    8.             jishi.setTextFormat(geshi);
    9.         }

    As you can see, the showTime function displays the number of milliseconds since the game started. Typical players don’t care about milliseconds; they want to see a normal clock, with minutes and seconds displayed as they would on a digital watch.

    Let’s break this out in another function. Instead of just including the raw gameTime in the text field as in the preceding code example, we can call a function to return a nicer output:

    复制代码

    1. jishi.text=”使用时间:”+fenmiaoT(youxiT);

    The idea is that the old code would show this:

    Time: 123726

    The new code will show:

    Time: 2:03

    The clockTime function will take the time in raw milliseconds and convert it to minutes and whole seconds. In addition, it will format it to use a colon (:) and make sure that a zero is placed correctly when the number of seconds is fewer than ten.

    The function will start off by simply dividing the number of milliseconds by 1,000 to get the number of seconds. It will then divide that by 60 to get the number of minutes.

    复制代码

    1. public function fenmiaoT(fm:int) {
    2.             var miao:int=Math.floor(fm/1000);
    3.             var fen:int=Math.floor(miao/60);
    4.             miao-=fen*60;
    5.             //var fenmiaoZ:String=fen+”:”+miao;
    6.             var fenmiaoZ:String=fen+”:”+String(miao+100).substr(1,2);
    7.             return fenmiaoZ;
    8.         }
    复制代码

    1. package {
    2.     import flash.display.*;
    3.     import flash.events.*;
    4.     import flash.text.*;
    5.     import flash.utils.getTimer;
    6.     public class Mygame1 extends MovieClip {
    7.         private static const paiKuan:Number=84+2;
    8.         private static const paiGao:Number=125+2;
    9.         private static const jiafen:int=100;
    10.         private static const jianfen:int=-5;
    11.         private var paiX:uint=Math.floor((stage.stageWidth-40)/paiKuan);
    12.         private var paiY:uint=Math.floor((stage.stageHeight-60)/paiGao);
    13.         private var bianX:Number=(stage.stageWidth-(paiX-1)*paiKuan)/2-1;
    14.         private var bianY:Number=(stage.stageHeight-(paiY-1)*paiGao)/2-1;
    15.         private var pai1:Card1;
    16.         private var pai2:Card1;
    17.         private var cardsLeft:uint=0;
    18.         private var paiShu:uint=10;
    19.         private var fenshu:TextField;
    20.         private var defen:int;
    21.         private var geshi:TextFormat;
    22.         private var jishi:TextField;
    23.         private var kaishiT:uint;
    24.         private var youxiT:uint;
    25.         public function Mygame1():void {
    26.             var pai:Card1=new Card1();
    27.             paiShu=pai.totalFrames;
    28.             var myCards:Array=new Array();
    29.             for (var j:uint=2; j<paiShu+2; j++) {
    30.                 myCards.push(j);
    31.             }
    32.             var cardlist:Array=new Array();
    33.             /*if (paiX*paiY/2!=0) {
    34.             paiY–;
    35.             bianY+=paiGao/2;
    36.             }*/
    37.             for (var i:uint=0; i<paiX*paiY/2; i++) {
    38.                 var r0:uint=Math.floor(Math.random()*myCards.length);
    39.                 cardlist.push(myCards[r0]);
    40.                 cardlist.push(myCards[r0]);
    41.                 myCards.splice(r0,1);
    42.             }
    43.             //trace(cardlist);
    44.             for (var x:uint=0; x<paiX; x++) {
    45.                 for (var y:uint=0; y<paiY; y++) {
    46.                     var c:Card1 = new Card1();
    47.                     c.stop();
    48.                     c.height=paiGao-2;
    49.                     c.width=paiKuan-2;
    50.                     c.x=x*paiKuan+bianX;
    51.                     c.y=y*paiGao+bianY;
    52.                     var r:uint=Math.floor(Math.random()*cardlist.length);
    53.                     c.cardface=cardlist[r];
    54.                     cardlist.splice(r,1);
    55.                     //c.gotoAndStop(c.cardface);
    56.                     addChild(c);
    57.                     cardsLeft++;
    58.                     c.addEventListener(MouseEvent.CLICK,fanPai);
    59.                 }
    60.             }
    61.             //trace(myCards);
    62.             defen=0;
    63.             fenshu = new TextField();
    64.             fenshu.width=200;
    65.             addChild(fenshu);
    66.             xiandefen();
    67.             jishi = new TextField();
    68.             jishi.x=stage.stageWidth-200;
    69.             jishi.width=200;
    70.             addChild(jishi);
    71.             kaishiT=getTimer();
    72.             youxiT=0;
    73.             addEventListener(Event.ENTER_FRAME,xianT);
    74.         }
    75.         public function fanPai(evt:MouseEvent) {
    76.             var paiN:Card1=(evt.target as Card1);
    77.             if (pai1==null) {
    78.                 pai1=paiN;
    79.                 paiN.gotoAndStop(paiN.cardface);
    80.             } else if (pai2==null) {
    81.                 if (paiN==pai1) {
    82.                     pai1.gotoAndStop(1);
    83.                     pai1=null;
    84.                 } else {
    85.                     pai2=paiN;
    86.                     paiN.gotoAndStop(paiN.cardface);
    87.                     if (pai1.cardface==pai2.cardface) {
    88.                         removeChild(pai1);
    89.                         removeChild(pai2);
    90.                         pai1=null;
    91.                         pai2=null;
    92.                         defen+=jiafen;
    93.                         xiandefen();
    94.                         cardsLeft-=2;
    95.                         if (cardsLeft<2) {
    96.                             MovieClip(root).gotoAndStop(“gameover”);
    97.                         }
    98.                     } else {
    99.                         defen+=jianfen;
    100.                         xiandefen();
    101.                     }
    102.                 }
    103.             } else {
    104.                 pai1.gotoAndStop(1);
    105.                 pai2.gotoAndStop(1);
    106.                 pai1=paiN;
    107.                 pai2=null;
    108.                 paiN.gotoAndStop(paiN.cardface);
    109.             }
    110.         }
    111.         public function xiandefen() {
    112.             fenshu.text=”你的得分: “+String(defen);
    113.             geshi= new TextFormat( );
    114.             geshi.color=0x0000ff;
    115.             geshi.bold=true;
    116.             geshi.size=24;
    117.             fenshu.setTextFormat(geshi);
    118.         }
    119.         public function xianT(evt:Event) {
    120.             youxiT=getTimer()-kaishiT;
    121.             jishi.text=”使用时间:”+fenmiaoT(youxiT);
    122.             geshi= new TextFormat( );
    123.             geshi.color=0x0000ff;
    124.             geshi.bold=true;
    125.             geshi.size=24;
    126.             jishi.setTextFormat(geshi);
    127.         }
    128.         public function fenmiaoT(fm:int) {
    129.             var miao:int=Math.floor(fm/1000);
    130.             var fen:int=Math.floor(miao/60);
    131.             miao-=fen*60;
    132.             var fenmiaoZ:String=fen+”:”+miao;
    133.             //var fenmiaoZ:String=fen+”:”+String(miao+100).substr(1,2);
    134.             return fenmiaoZ;
    135.         }
    136.     }
    137. }

    MyGame.swf (1668 K) 下载次数:7 [试播]

    Displaying Score and Time after the Game Is Over

    This is a little tricky because the gameover screen exists on the main timeline, outside of the game movie clip. To have the  main timeline even know what the score and time are, this data needs to be sent from the game to the root level.

    Just before we call the gotoAndStop command that will advance the movie to the gameover screen, we pass these two values up to root:

    复制代码

    1. MovieClip(root).fenShu=defen;
    2. MovieClip(root).shiJian=fenmiaoT(youxiT);

    At the root level, we need to define those new variables,  I’ve added this code to the first frame:

    复制代码

    1. var fenShu:int;
    2. var shiJian:String;

    Then, on the gameover frame, we use these variables to place values in new text fields:

    复制代码

    1. fenshu.text = “Score: “+String(fenShu);
    2. shijian.text = “Time: “+shiJian;

    We don’t need to use code to create the showScore and showTime dynamic text fields; we can simply do that on the stage with the Flash editing tools.

    To simplify things here, we’re including the “Score: “ and “Time: “ strings in with the Score and Time fields. But, a more professional way to do it would be to have the words Score and Time as static text or graphics on the screen, and only the actual  score and time in the fields.