2DToolkit官方文档中文版打地鼠教程
初始设置
创建一个Unity项目,并导入2D Toolkit插件。
导入完成后,在Project窗口会显示TK2DROOT文件夹(后续版本文件夹名称或许会有变动)。
导入素材游戏,你可以从这里下载。下载完成后,将素材导入到项目中。
设置摄像机
制作游戏的第一步,就是创建一个游戏摄像机。虽然Unity已经在Hierarchy窗口给我们提供了一个默认摄像机MainCamera,但为了简单,我们使用2D Toolkit中已经为2D游戏场景优化过的摄像机。
删除默认的Unity摄像机MainCamera,我们使用tk2dCamera。如果两个摄像机都在场景中,在未正确配置的情况下会产生冲突。
在创建tk2dCamera之前,设置Game窗口的分辨率,以便tk2dCamera能够自动匹配设置。在Game窗口左上角有一个下拉选项,单击并选择Standalone。如果你没有看到这项设置,可能当前并非PC Mac and Linux Standalone,请先进行切换,然后选择Standalone。
在Unity菜单栏中点击 GameObject > Create Other > tk2d > Camera 创建摄像机,默认名称为 tk2dCamera 。
如果Game窗口没有被设置为Standalone,那么你将看到一些警告,例如:the camera has not been able to detect some of the settings. 选中Hierarchy窗口中的tk2dCamera,查看Inspector窗口中的设置,如下图:
在本教程中将始终使用Standalone模式以及1024*768的分辨率。
Tk 2d Camera (Script)组件中的Native Resolution,是游戏开发阶段的分辨率。
Preview Resolution,是你的预览分辨率,你可以修改这里来预览不同分辨率下的显示效果。
2D游戏的投影模式为Orthographic模式,如果不是的话你需要通过下拉选项将其修改为Orthographic。当前游戏中,我们只有单屏幕以及没有滚动等其他效果,Pixels per Meter设置值为1即可。
Origin(原点)决定我们为游戏对象定位时的测量起点,我们将原点设置为屏幕的左下角,在Origin字段的下拉列表中选择Bottom Left。摄像机设置结束后,应该像下图一样:
Camera选项卡:
- Background Color背景颜色值将会显示在游戏的任何透明区域,你可以通过单击选择一个新的颜色。
- Clipping Planes值定义摄像机的Z轴可视深度,默认值为 Near:0.3 和 Far:10 。我们的所有游戏对象都应该在摄像机的可视范围内。
Sprite Collections 精灵集合
之前我们已经导入了游戏素材,在Project窗口,你可以看到Mole文件夹。打开里面的Textures文件夹,你会看到图片列表。
为了在项目中使用这些图形,我们将它们做成Sprite Collection精灵集合。
在Project窗口,新建一个文件夹,命名为Sprite Collections。
选中Sprite Collections文件夹,单击 Create > tk2d > Sprite Collection,在Sprite Collections文件夹创建一个SpriteCollection资源。
选中SpriteCollection资源,重命名为Land,用来存放land相关的图片。
注意:尽管我们的游戏相当非常简单,但是如果你想做更大更复杂的游戏的话,思考如何将精灵分组是非常重要的。Unity内置动态分配系统,会自动减少draw请求,通过Z值可以非常高效的组织Sprite。在多个精灵集合中存在重复精灵时将增加draw请求次数,请不要将精灵添加到多个精灵集合。
在Inspector窗口中,单击Open Editor将会打开SpriteCollection窗口。为了更方便的拖拽精灵到窗口中,你可以将窗口固定。
在Project窗口中,打开并选中 Mole > Textures 文件夹,拖拽下面的精灵到SpriteCollection窗口中Drop sprite here位置。你可以单独拖动一个,也可以多个一起拖动:
Cloud_01
Cloud_02
Cloud_03
Field_Background
Field_Foreground
Field_Midground
Field_Ploughed
Fields
Grass_01
Grass_02
Sky_Burst
Sky_Colour
Stone_01
Stone_02
Stone_03
Stone_04
Stone_05
Tree_01
Tree_02
在Sprites列表下,你可以选择其中一个精灵,它将会显示在主窗口中。
SpriteCollection窗口中,点击Settings按钮打开设置,这里的设置影响集合中的所有精灵。
在早期的2DToolkit版本中,为了让游戏对象正确的显示在屏幕上,你需要选中 Use tk2DCamera 选项。不过,在当前版本的2DToolkit中,精灵集合会自动检测tk2DCamera是否使用。单击 Commit 按钮保存我们所进行的修改。
你可能会看到一个弹窗警告:unable to fit textures in the requested atlas area ,单击OK按钮。这里提示我们纹理过多,合并后的图片可能超出大小,一般是指2048*2048这种。如果你做过图片合并压缩,可能会理解我的意思。
我们有两种途径解决此问题:在Atlas Settings中增加Atlas的大小,或者把大图分割成多个小图,或者两种办法同时使用。
在Spite列表中的选中一个精灵,能在主窗口的右下角看到图片的大小。通过查看各个sprite,我们可以看到 Field 精灵尺寸最大。
选中Field的多个精灵,在右边窗口中把 Render Mesh 值从 Default 修改为 Diced 。
它将会提供给我们两个可供改变的值:Dice X 和 Dice Y。修改他们两个的值为64并点击Apply按钮。这会将每个图片分割为64*64的块,不过不用担心,2d Toolkit会在他们需要显示时,将它们重新组合在一起。下面的图片展示了修改之前和之后的样子:
正如你所看到的,精灵被存储为未切割图谱的原始图像,而在切块图集中已进行切割。
返回Settings设置,并且将Atlas Settings中的Max Size值修改为2048并单击Commit,图集就会被创建。对于其他精灵图集你可能需要经过试验来找到合适的切片及图集大小。
重复步骤2开始创建包含以下详细内容的精灵集合:
Mole: Mole_Hit, Mole_Hole, Mole_Hole_Mud, Mole_Normal
Dust: Animated_Dust_01 to Animated_Dust_16
记住确定你的修改!
将精灵加入到游戏中
现在,我们已经创建好了精灵集合。
在Hierarchy窗口中,点击 Create > tk2d > Sprite 创建精灵。初始精灵可能会从2DToolkit中的Demo Sprite中选择一个。
在Hierarchy窗口中选中精灵对象,在Inspector窗口中修改Collection值为Land,并将Sprite值改为Fileds。将精灵名称修改为Landscape。
Transform > Postion 里面的Z值,在2D游戏中表示游戏对象的深度。tk2dCamera的默认Z值为-10,所以为了能够看到我们的精灵,这里的Z值要比摄像机的Z值大,Z值越大对象越远,这里Z值设置为10。
你可能还需要调整Transform > Position中的X和Y值,它们可以调整精灵在屏幕上的显示位置。默认的,Feild精灵的锚点被设置为精灵的中心点。你可以点击tk2d Script下面的e按钮来修改锚点位置,这里我们修改为Lower Left(记住Commit提交修改)。
重复上面的步骤来添加sky、trees、grass、rocks到游戏中。记得调整精灵的Transform Position的Z值来进行正确排序,越大的Z值离摄像机越远,你可以改变锚点让你更容易的放置精灵。像下图一样添加完成所有精灵。
:Static Sprite Batcher 静态精灵批处理
在Hierarchy窗口点击 Create > tk2d > Static Sprite Batcher,将名称改为Background。
在Hierarchy窗口,拖拽每一个之前创建的背景对象到你刚添加的Static Sprite Batcher里。
将所有对象添加到Static Sprite Batcher后,选中它,之后在Inspector中点击Commit按钮提交修改。
Hierarchy窗口中的所有背景精灵会消失,只留下Background这个Static Sprite Batcher。
如果之后你需要修改Static Sprite Batcher中的精灵,你可以在Inspector窗口中单击Edit按钮。所有单独的精灵会再次在Hierarchy窗口中出现,然后你就可以对其进行修改。
添加地鼠
我们已经有了背景,现在需要将地鼠加入游戏中。
每一个“地鼠”包括三个部分:地鼠、洞穴和洞旁边的泥。我们将这三种组合成一个单元Unit。
首先创建一个洞穴,在Hierarchy窗口中点击 Create > tk2d > Sprite ,在Mole精灵集合中选择Mole_Hole精灵,并命名为Hole。调整Scale及Position让他显示在土地中间。目前摄像机设置为1024*768分辨率,所以将X和Y值分别修改为512和260。记住修改Z值让洞显示在背景图片之前。
之后,确保在Hierarchy窗口中已经选中了Hole对象,点击Create > tk2d > Sprite,在Mole精灵集合中选择Mole_Hole_Mud精灵,调整Scale、Position并进行命名,让它显示在洞穴之前。这一步中,我们将泥创建为了Hole的子对象,所以所有的Transform值都是相对于洞穴的,它显示在洞穴的中间而不是游戏屏幕的左下角(决定于Sprite的锚点)。而Z值也同样相对于洞穴,调整Z值,让它显示在洞穴前面。
现在到了地鼠本身,因为地鼠会从洞里钻进钻出,所以我们遇到了一个问题:当地鼠钻到洞里后,你仍然可以在屏幕上的洞下面看到它, 因此为了实现地鼠消失在洞里,我们将使用裁剪后的精灵。在Hierarchy窗口选中洞穴对象,点击Create > tk2d > Clipped Sprite,然后从Mole精灵集合中选择Mole_Normal精灵。
调整地鼠的Position,让它显示在洞外面,可以将Y值设置为60。然后调整Z值让它显示洞前面、泥后面。同样,你需要给鼹鼠添加一个碰撞盒子,我们使用碰撞盒子来检测地鼠是否被打中。完成后应该如下图一样:
如果你点击了Unity中的Play按钮,游戏会运行,但不会显示任何东西。我们需要添加一些脚本到地鼠对象中来让他完成一些事情,之后我们会添加更多的地鼠。
如果你想将你的游戏工程与我们的进行对比,你可以从这里下载。
脚本
在Hierarchy窗口点击Create > tk2d > Empty GameObject,并重命名这个新对象为MoleUnit。在Inspector窗口修改Transform Position X/Y/Z值。在Hierarchy窗口,拖拽MoleHole到MoleUnit游戏对象,地鼠和泥游戏对象会自动跟随。
提示:如果你修改X和Y并不容易,这里有另外一种方法:
在Hierarchy窗口中拖拽这个空游戏对象到MoleHole对象上,空游戏对象的X和Y值将会改变。
选中空游戏对象,并将Inspector窗口中的X和Y值修改为0。
在Hierarchy窗口中,选中并拖拽空游戏对象到MoleHole上,它将会和MoleHole拥有同样的X和Y值。
选中并拖拽MoleHole对象到空游戏对象中。MoleHole将会成为空游戏对象的一个子对象,并且Hole的X和Y值会变成0。
在Project窗口中,新建文件夹并命名为Scripts。选中Scripts文件夹,创建C#,并命名为MoleScript。
编辑脚本文件,并将代码替换为下面文件中代码:MoleScript C# version。
当然,你也可以使用Javascript(UnityScript)代码。Javascript代码使用Create > Javascript来创建。Javascript版本的代码可以从这里找到。tk2d的代码是使用C#编写的,但同样可是使用你编写的任何Javascript文件,在Unity菜单栏中,选择2DToolkit > SetupForJs。
新建一个名为MainGameScript的C#脚本,之后编辑脚本并将MainGameScript这里的代码复制进去。我们会在下一节中看到脚本的更多信息,但现在我们只需要编译MoleScript。
你可以在这里找到MainGameScript的Javascript(UnityScript)版本。
当保存完所有的脚本之后,在Project窗口选中MoleScript并拖拽到Hierarchy窗口的MoleUnit对象上,脚本会被添加到游戏对象中。
由于tk2dClippedSprite中包含一个名为Sprite的公共变量,所以我们可以把这个脚本和MoleScript脚本关联起来。在Hierarchy窗口中,选中MoleUnit游戏对象并将它拖拽到Mole对象的MoleScript脚本中的Sprite字段中。
想了解MoleScript是如何工作的,点击这里。
如果你想将你的游戏工程与我们的进行对比,你可以从这里下载。
Prefabs 预设体
我们已经有了Mole游戏对象以及脚本来控制它移动,为了让后续更快速及简单的重复使用,我们将它制成Prefab预设体,本质上它是一个模板,我们使用它来制作副本。
在Project窗口,创建一个名为Prefabs的文件夹。
在Hierarchy窗口,选中MoleUnit对象并拖拽到Prefabs文件夹。Hierarchy窗口中的MoleUnit、Hole、Dirt和Mole对象会变成蓝色,这是因为这些对象已经是Prefab预设体了。
你可以从Project窗口拖拽MoleUnit到Hierarchy窗口来将它添加到游戏中。
你可以根据自己的需要添加不同数量的Hole和Mole游戏对象,记得修改每一个MoleUnit对象的X和Y坐标,直到你向下面一样添加完成:
创建精灵动画
到目前为止,除了Dust精灵集合,我们已经使用精灵创建了很多精灵集合。这些精灵与我们打地鼠时一个接一个显示的不同,它是一个动画。
在Project窗口,点击Create > Folder创建文件夹并命名为Animations。
选中Animations文件夹,点击Create > tk2d > Sprite Animation并命名为DustAnim。
选中DustAnim对象,点击Inspector窗口中的Open Editor按钮。
在新打开的Open Editor窗口中,点击Create > Clip创建动画剪辑。
将刚创建的动画剪辑命名为DustCloud,在Collection字段选择精灵集合Dust,然后设置Sprite字段为Animated_Dust_01。
点击Autofill 1..9按钮,将会自动添加后续编号的剪辑到动画剪辑中。
之后再Wrap Mode字段,选择Once。这个设置的意思是每次动画被触发时,动画只播放一遍然后停止。
最后,点击Play按钮来对动画进行预览。你可通过修改frame和time设置来对动画播放的快慢进行调整。
播放精灵动画
之前我们已经创建好了动画剪辑,我们可将动画精灵添加到场景了。
在Hierarchy窗口,点击Create > tk2d > Sprite With Animator。
在Inspector窗口中,为精灵动画设置一个名字:BigDust。
在Tk 2d Sprite组件中将Collection设置为Dust,将Sprite设置为Animated_Dust_01。
在Tk 2d Sprite Animator组件中,将Anim Lib值设置为刚才创建的DustAnim。因为我们只想在地鼠被敲时播放动画,所以不选中Play automatically复选框,选中会让动画在游戏开始时立即播放。动画的位置在这里并不重要,我们会在地鼠被敲时动态的改变它的位置。
游戏脚本
现在是时候来完成游戏的所有功能了,尽管我们已经控制了每一个地鼠,但我们仍然需要一些东西来控制整个游戏。
在Hierarchy窗口,点击Create > tk2d > Empty Game Object并命名为GameScript。
在Project窗口中,选中MainGameScript并拖拽到Hierarchy窗口的GameScript对象上。
这个脚本包含游戏摄像机的公共变量,以及一个动画。选中并拖拽摄像机到Game Cam字段中,同样拖拽BigDust到Dust Animator字段中。
如果你想了解游戏脚本是如何工作的,点击这里。
现在运行游戏,你就可以看到地鼠从洞里钻出,而你也可以敲他们了。被敲到的地鼠的精灵图片会改变,同时dust animation动画被播放。
添加文本
我们的游戏已经可以玩了。地鼠从洞里钻出来,打中他们后,会消失在一朵烟里。但你想知道你游戏玩得怎么样,就需要在屏幕上显示分数。
我们使用2D Toolkit中的一个演示字体,你也可以使用自己喜欢的字体包。
在我们添加分数文本之前,我们需要确保他能正确显示在屏幕上。我们添加一个anchor在我们的摄像机中,让分数文本能够更简单的定位。
在Hierarchy窗口,选中摄像机对象,并点击Create > tk2d > Camera Anchor。
在Hierarchy窗口中,一个Anchor对象被添加为摄像机的子对象。
我将把分数文本显示在游戏窗口的右上角,所以让场景的anchor到右上角。因此在Inspector窗口中的Tk 2d Camera Anchor(Script)的下面,点击Anchor下拉列表并选中UpperRight。注意设置完之后anchior的x和y会被设置为摄像机的宽和高,那就是屏幕的右上角。
我们的分数文本的位置将会相对于anchor,在Hierarchy窗口中选中Anchor,然后点击Create > tk2d > TextMesh。
在Hierarchy窗口中选中TextMesh,在Inspector窗口中你可以改变它的各种设置,这里需要修改的仍然是Anchor锚点。由于文本默认从左到右显示,如果我们选择TopRight,那么文本在屏幕上的位置将会改变。在分数变得更大时,为了容纳更多文本,它会变得更大。所以为了使分数显示在同一个地方,我们选择Upper Left作为Anchor设置。
从字体下拉列表中选择GradientFont,并设置它的Max Chars值,这里设置为11,这包括了Score这个词和后面的分数。注意,MaxChars值设置过大会浪费内存,设置过小会导致文本被裁剪。在文本框中输入一些文本,我们预览文本的显示效果,随后我们会在脚本中控制文本内容。
在TextureGradient中选择一个你喜欢的效果,我这里选择desert-horizon。
默认字体很小,所以我们需要对文本进行缩放以显示在屏幕上适合的大小,我们这里选择 600 * 500。
现在,我们有了显示分数的文本,我们需要能够改变分数文本。在Project窗口中,创建一个C#脚本命名为ScoreScript,并将这里的代码粘贴进去。ScoreScript让我们能够很简单的获取及修改current score分数值。
在Project窗口中,选中ScoreScript并将它拖动到Hierarchy窗口中的ScoreText对象上。脚本将会被到添加到score文本对象中。
当打中一个地鼠后,增加10分,但没有打中时,扣去5分。变量和函数我们已经写在了脚本中,ScoreScript类使用它时并不需要创建实例,我们可以简单的使用:
ScoreScript.Score += 10;
来更新分数。 因此当打中地鼠后( if(mole.sprite.gameObject.activeSelf && mole.ColliderTransform == hit.transform) ),我们通过在MainGameScript增加下面的代码来控制分数。我们将使用的方法的核心代码是:
ScoreScript.Score += mole.Whacked ? 0 : 10;
如果洞中的地鼠已被打中过,则0分。
为游戏添加声音
现在我们为游戏添加一些音效。当地鼠被打中、从洞里钻出以及钻回洞中时会播放。我们在Projects > Mole > Sounds中已经有了这些音效。关于可用和不可用的音效格式,你可以查看这里。
将声音片段添加到游戏中很容易!
取消每一个音效的3D Sound选项。
为beat_mole音效在MainGameScript添加一个AudioClip变量:
public AudioClip moleHit;
然后在打中地鼠的代码中,也就是分数增加的代码,增加如下代码:
AudioSource.PlayClipAtPoint(moleHit, new Vector3());
此函数接受一个AudioClip和Vector3作为参数。Vector3对3D音效有效果,但我们这里使用的2D声音,所以我们只新建一个空的Vector3。
现在在Hierarchy窗口中选中MainGameScript,将会出现一个MoleHit音效字段,我们可以将音效拖到上面。
添加mole_down和mole_up音效,在MoleScript脚本下声明变量。
public AudioClip moleUp;
public AudioClip moleDown;
在MoveUp函数的最开始,循环之前,添加以下代码:
AudioSource.PlayClipAtPoint(moleUp, new Vector3());
在MoveDown函数最结尾,循环之后,添加以下代码:
AudioSource.PlayClipAtPoint(moleDown, new Vector3());
同样,如果我们选中MoleUnit,在Inspector窗口中的MoleScript下面将会可以添加mole_up和mole_down音效。为每一个MoleUnit重复上述步骤。
tk2dCamera应该已经带有Listener,没有Listener,我们将无法听到任何声音。如果您使用的是旧版本的tk2dcamera没有附带Listener,或正在使用Unity相机,需要添加Listener:在Hierarchy窗口中,选中tk2dcamera对象,然后在Inspector窗口点击AddComponent按钮,然后选择Audio > Audio Listener,Listener将被添加到相机,这就是所有你需要完成的事。
现在我们已经做完开发一个游戏的所有工作了。好吧,虽然它不是Halo 4这样的游戏,但我们已经覆盖了创建游戏的所有要点:添加一个相机、添加精灵、添加文本、添加声音和脚本。如果你没有游戏美工和游戏音乐师,不用担心,网上有很多的资源你可以下载下来用到后续的游戏制作中。
转自:http://www.cnblogs.com/trlanfeng/p/4111843.html
2DToolkit官方文档中文版打地鼠教程的更多相关文章
- 2DToolkit官方文档中文版打地鼠教程(三):Sprite Collections 精灵集合
这是2DToolkit官方文档中 Whack a Mole 打地鼠教程的译文,为了减少文中过多重复操作的翻译,以及一些无必要的句子,这里我假设你有Unity的基础知识(例如了解如何新建Sprite等) ...
- 2DToolkit官方文档中文版打地鼠教程(二):设置摄像机
这是2DToolkit官方文档中 Whack a Mole 打地鼠教程的译文,为了减少文中过多重复操作的翻译,以及一些无必要的句子,这里我假设你有Unity的基础知识(例如了解如何新建Sprite等) ...
- 2DToolkit官方文档中文版打地鼠教程(一):初始设置
这是2DToolkit官方文档中 Whack a Mole 打地鼠教程的译文,为了减少文中过多重复操作的翻译,以及一些无必要的句子,这里我假设你有Unity的基础知识(例如了解如何新建Sprite等) ...
- 人工智能系统Google开源的TensorFlow官方文档中文版
人工智能系统Google开源的TensorFlow官方文档中文版 2015年11月9日,Google发布人工智能系统TensorFlow并宣布开源,机器学习作为人工智能的一种类型,可以让软件根据大量的 ...
- TensorFlow 官方文档中文版【转】
转自:http://wiki.jikexueyuan.com/project/tensorflow-zh/ TensorFlow 官方文档中文版 你正在阅读的项目可能会比 Android 系统更加深远 ...
- TensorFlow 官方文档中文版
http://wiki.jikexueyuan.com/list/deep-learning/ TensorFlow 官方文档中文版 你正在阅读的项目可能会比 Android 系统更加深远地影响着世界 ...
- TestNG官方文档中文版(2)-annotation(转)
1. 介绍 TestNG是一个设计用来简化广泛的测试需求的测试框架,从单元测试(隔离测试一个类)到集成测试(测试由有多个类多个包甚至多个外部框架组成的整个系统,例如运用服务器). 编写一个测试的 ...
- TensorFlow 官方文档中文版 --技术文档
1.文档预览 2.文档下载 TensorFlow官方文档中文版-v1.2.pdf 提取码:pt7p
- bootbox.js官方文档中文版
bootbox.js官方文档中文版简介:Bootbox.js是一个小型的JavaScript库,基于Bootstrap模态框开发,用于创建可编程的对话框. 不像原生的alert等对话框,所有的Boot ...
随机推荐
- redis(1)
一.Redis介绍 Redis 是一款开源的,基于 BSD 许可的,高级键值 (key-value) 缓存 (cache) 和存储 (store) 系统.由于 Redis 的键包括 string,ha ...
- database disk image is malformed
在Linux上使用yum安装软件的时候报如下错误: database disk image is malformed 根本原因是:yum的缓存出错, 需要清理缓存 使用如下命令来解决这个问题: yum ...
- 将JSON对象转化为数组对象
package web.helper; import java.util.ArrayList; import net.sf.json.JSONArray; import web.model.Abstr ...
- Attribute的理解和认识
1什么是Attribute? 在网上看到这样一段定义 MADN的定义为:公共语言运行时允许添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型.字段.方法和属性等.A ...
- Winform DataGridView直接导出Excel
/// <summary> /// 导出excel /// </summary> /// <param name="fileName">导出文件 ...
- Jmeter(四)-断言/检查点
断言就类似LoadRunner中的检查点.对上一个请求返回的信息,做字符串.数据包大小.HTML.XML.图片等做判断,确保返回的信息的准确性. 添加响应断言:欢迎您 如果登陆页登陆成功,则后台会返回 ...
- c#弱事件(weak event)
传统事件publisher和listener是直接相连的,这样会对垃圾回收带来一些问题,例如listener已经不引用任何对象但它仍然被publisher引用 垃圾回收器就不能回收listener所占 ...
- C# Oracle insert 中文乱码
问题描述: 在PL SQL中insert 中文数据,显示不乱码,通过后台insert的中文数据,显示问号. 解决分三步: 1.Select userenv('language') from dual; ...
- [WPF] 为Style 里的button添加鼠标点击响应事件
一个TabControl, 用的是PagedTabControl style, 在style中有个button, button在style里已经写了click事件,但是现在还需要加上一段功能,就是在响 ...
- EFI Shell 命令说明
EFI Shell 命令说明 引导命令 — EFI Shell 与 nPartition 引导有关的命令. autoboot 设置(查看)自动引导超时变量. bcfg 显示(或修改)驱 ...