译者注:

目前移动设备的跨平台游戏开发引擎基本都是采用Cocos2d-x或者Unity。一般而言2d用cocos2d-x 3d用unity,但是对于Windows Phone开发者,

cocos2d-x for wp8是微软维护的,版本升级十分缓慢,到现在还是 V2.0 preview,我们不可能拿一个不太稳定的版本去开发游戏。与之相反,Unity4.2发布之后,

支持WP8和Windows8,当然也包括其他平台,开发调试都是十分便捷,因此使用Unity来开发目标用户在WP上的游戏,是个很好的选择。

这是一篇译文,原文很长,于是我把它分成了两部分,而且加入了自己的一些修改和理解,点击一下链接观看第一部分效果。(需要安装最新的unity插件)

http://jeekun.sinaapp.com/share/flash/flash.html

原文:http://catlikecoding.com/unity/tutorials/runner/

介绍

在这篇教程里,我们将学习如何去制作一款简单的无尽跑酷游戏,在这里你将学到:

  • 生成一个分层的背景
  • 重用对象
  • 使用物理引擎
  • 通过检测输入来控制玩家跳跃
  • 实现能量增加
  • 一个简单的事件管理器
  • 按需控制物体的开关
  • 制作一个简单的GUI

游戏设计

在开始之前,我们应该先考虑一下在游戏里面加入什么。我们要做的是一个2D侧卷轴游戏,但是还是太宽泛了,让我们来缩小一下范围。

游戏的玩法:我们将控制一个人物不断的向屏幕右侧奔跑,从一个平台跳到另外一个平台,要跑的尽可能的远。这些平台有不同的特性,有的会让你加速,

有的会让你减速。我们还包含单一的能量球,可以让你在空中跳跃。

游戏图形:我们将使用纯Cube和标准的粒子系统来制作(程序员的悲哀。。。) 玩家,平台,包括背景,统统都是Cube,而粒子系统将被用于制作运动轨迹,

很多漂浮物将会给人更好的速度和深度的感觉。

另外,游戏不包括特效音和背景音。

建立场景

打开Unity,创建一个新的工程,不要导入任何的包。

我们是要做的2D视角的游戏,但是还想有一点3D的效果,Orthographic摄像机是不能用于3D游戏的,因此我们得采用默认的Perspective类型。这样的话,将物体放到离镜头不同

的距离,我们就能得到一个分层的滚动背景。

就让我们假定,前景是在距离0,第一个背景在距离50,第二个背景在距离100。让我们分别放三个Cube在这三个深度,并且将他们作为创建场景的引导者。我自己已经试过了一些角度和颜色组合,

觉得还可以,当然你也可以自己去实验一些新的数值。

下面正式开始:

首先添加一个平行光(GameObject->Create Other->Directional Light),设置旋转为(20,330,0)

然后设置摄像机的参数,颜色为(115,140,220)

其他数值见图:

创建3个Cube, Position 分别是(0,0,0) (0,0,50) (0,0,100),名字对应的是 Runner, Skyline Close, Skyline Far Away,后两个Skyline Cube 不需要

碰撞器(Box Collider),直接在属性面板里,右键移除组件即可。 Runner是这次游戏的猪觉,在这里我称之为 “奔跑者”,后面同之。

给3个Cube分别创建材质(Project 视图,Create-> Material),命名为Runner Mat, Skyline Close Mat, Skyline Far Away Mat. 然后分别拖放到对应的Cube上。

我使用了默认的 diffuse Shader , 颜色分别设为, White, (100, 120, 220), (110, 140, 220), 设置完成后的值如下:

           

为了使项目的组织架构更好,我们在Project视图里增加2个文件夹,Runner, Skyline, 然后把材质放到对应的文件夹里。

运行一下,可以看到3个Cube都出现在了视野里面。

开始跑步吧

到目前为止,我们做的还没什么奇特的,场景里面什么也没有发生,但是接下来就是见证奇迹的时刻了。

让我们来让 “奔跑者” 向右边移动来模拟一下这个游戏吧。

在Runner文件夹里创建一个C#脚本,Runner.cs

using UnityEngine;
using System.Collections; public class Runner : MonoBehaviour { // Use this for initialization
void Start () { } // Update is called once per frame
void Update () {
transform.Translate(5f * Time.deltaTime, 0f, 0f);
}
}

把脚本拖到层次视图的Runner 上面,运行,怎么样,看到主角开始跑了吧。但是有个问题,摄像头没有跟随它在运动,没一会就跑出我们的视野了,

这样的游戏根本没法玩啊,也不是我们想要的。解决的方法很简单,把摄像机对象拖到Runner里,让他成为Runner的Child.

   现在再运行的话就没有问题了,而且我们可以发现,远处的Cube要比进出的Cube移动的好像快一些,当然这就是视差的问题了。

生成天际线                                                                                                                                        

现在我们已经有了基本的运动了,接下来让我们生成一行的Cube来实现无止境的天际线。首先有件事情我们必须意识到,名为无尽的,其实只需要一部分存在地图中就可以了,

因为随着镜头不断的右移,左侧的天际线不断消失在视野中,他们是可以被销毁的,没有必要再继续占用资源了。或者,我们可以将它移动位置,在右侧重建场景,省去了重复的

创建开支。

通过这个特性,我们只需要很少的资源就可以创建无止尽的天际线了。

在Skyline 文件夹中创建一个SkylineManager的脚本,因为要通过一个脚本创建两个天际线,所以需要传一个值进来,知道是要创建具体哪种。

public Transform prefab;

同样的,为了场景层次视图中的组织结构友好,我们需要设置一下层次。 首先新建一个空对象,起名Managers, 作为父容器。

然后给它创建一个子对象 Skyline Close Manager,然后把脚本拖到这个对象上来。

接下来把Skyline Close和Skyline Far Away 这两个Cube拖拽到Project中的Skyline文件夹下,使之成为Prefab,然后将层次视图中的两个对象删除,

设置好之后,层次视图和Project视图如下所示:

      

现在我们需要一个起点指示我们从哪里开始构建天际线,我们可以通过Manger对象本身的位置,而且我们需要一个数量值来决定多少个Cube组合起来才能填充完屏幕,

新建一个变量叫做 numberOfObjects ,另外声明一个变量 nextPosition ,指示左边的对象无效之后,应该在哪里重建。

public Transform prefab;
public int numberOfObjects; private Vector3 nextPosition; void Start()
{
nextPosition = transform.localPosition;
}

下一步是创建初始行的Cube,通过一个for循环来实现,实例化我们之前创建为prefab的Cube,每一个cube的位置都是nextPosition,而且随着没添加一个动态修改这个变量的值

void Start()
{
nextPosition = transform.localPosition; for (int i = ; i < numberOfObjects; i++)
{
Transform o = (Transform)Instantiate(prefab);
o.localPosition = nextPosition;
nextPosition.x += o.localScale.x;
}
}

现在设置Skyline Close Manager 的Position 为(0, -1, 0) 并且设置 numberOfObjects 变量的值为10 ,运行

可以看到出现了一连串的Cube了,有点“地平线”的影子了,但是有个问题就是“天际线”本身不会随着镜头运动,去往左侧就消失不见了。

我们回收重用Cube的策略是只回收那些离玩家超过一定距离的,因此一定要知道玩家跑了有多远,为了达到这个目的,我们在 Runner.cs 里

添加一个静态变量,而且时时更新它。

public static float distanceTraveled;

// Use this for initialization
void Start () { } // Update is called once per frame
void Update () {
  transform.Translate(5f * Time.deltaTime, 0f, 0f); //因为起始位置是 0
  distanceTraveled = transform.position.x;
}

现在我们将要把我们的组成地平线的物体放到一个队列里,并且不断的检查是否要回收,因为是队列,只需要检查第一个即可,如果是需要回收,

从队列中移除,修改位置,然后放到队列最后边就可以了。

我们用一个recycleOffset变量来配置具体物体落后玩家多远的话 可以回收,这里设置为 60 .

public class SkylineManager : MonoBehaviour {

    public Transform prefab;
public int numberOfObjects;
public float recycleOffset; private Vector3 nextPosition;
private Queue<Transform> objectQueue; void Start()
{
objectQueue = new Queue<Transform>(numberOfObjects);
nextPosition = transform.localPosition; for (int i = ; i < numberOfObjects; i++)
{
Transform o = (Transform)Instantiate(prefab);
o.localPosition = nextPosition;
nextPosition.x += o.localScale.x; objectQueue.Enqueue(o);
}
} // Update is called once per frame
void Update () {
if (objectQueue.Peek().localPosition.x + recycleOffset < Runner.distanceTraveled)
{
Transform o = objectQueue.Dequeue();
o.localPosition = nextPosition;
nextPosition.x += o.localScale.x;
objectQueue.Enqueue(o);
}
}
}

现在运行,在Scene视图里,可以看到Cube行 是随着 “奔跑者” 不断的重新修正自己的位置的。但是他现在看起来还不像天际线,为了生成更像实际的

没有规则的天际线,让我们在它生成或者充值的时候随机放大它。

首先考虑到会有重复的代码产生,首先写个函数Recycle ,在start或者update的时候都调用它。

public class SkylineManager : MonoBehaviour
{ public Transform prefab;
public int numberOfObjects;
public float recycleOffset; private Vector3 nextPosition;
private Queue<Transform> objectQueue; void Start()
{
objectQueue = new Queue<Transform>(numberOfObjects);
for (int i = ; i < numberOfObjects; i++)
{
objectQueue.Enqueue((Transform)Instantiate(prefab));
}
nextPosition = transform.localPosition;
for (int i = ; i < numberOfObjects; i++)
{
Recycle();
}
} void Update()
{
if (objectQueue.Peek().localPosition.x + recycleOffset < Runner.distanceTraveled)
{
Recycle();
}
} private void Recycle()
{
Transform o = objectQueue.Dequeue();
o.localPosition = nextPosition;
nextPosition.x += o.localScale.x;
objectQueue.Enqueue(o);
}
}

下一步,让我们加入两个变量分别表示允许的放大最大和最小值,当放大一个物体之后,我们要确定可以保证后面的物体和前面的

都是底部对齐的,

public class SkylineManager : MonoBehaviour
{
public Transform prefab;
public int numberOfObjects;
public float recycleOffset; public Vector3 minSize, maxSize; private Vector3 nextPosition;
private Queue<Transform> objectQueue; void Start()
{
objectQueue = new Queue<Transform>(numberOfObjects);
for (int i = ; i < numberOfObjects; i++)
{
objectQueue.Enqueue((Transform)Instantiate(prefab));
}
nextPosition = transform.localPosition;
for (int i = ; i < numberOfObjects; i++)
{
Recycle();
}
} void Update()
{
if (objectQueue.Peek().localPosition.x + recycleOffset < Runner.distanceTraveled)
{
Recycle();
}
} private void Recycle()
{
Vector3 scale = new Vector3(
Random.Range(minSize.x, maxSize.x),
Random.Range(minSize.y, maxSize.y),
Random.Range(minSize.z, maxSize.z)); Vector3 position = nextPosition;
position.x += scale.x * 0.5f;
position.y += scale.y * 0.5f; Transform o = objectQueue.Dequeue();
o.localScale = scale;
o.localPosition = position;
nextPosition.x += scale.x;
objectQueue.Enqueue(o);
}
}

为了得到一个漂亮的天际线效果,把这个Manager放到(-60,-60, 50),并且将MinSize 设置为(10,20,10) MaxSize设置为(30,60,10)Recycle Offset 设置为60

让我们继续添加第二个天际线层,选中Skyline Close Manager "CTRL+D " 复制一份,并且改名为 Skyline Far Away Manager, 将它的prefab属性改为 Skyline Far Away 这个预设。

它的位置设置为(-100,-100, 100) 它的Recycle Offset 为 75,MinSize为(10,50,10) MaxSize为(30,100,10) 当然你也可以照你自己的喜好来设置新的值

   

产生平台                                                                                                                   

生成平台跟生成天际线很像,稍微有点不同的是平台的高度需要随机设定,而且他们之间需要有沟壑。并且我们需要约束平台的高度,好让它不会影响天际线的显示,

如果平台超出这个范围了,我们需要给它纠正过来。

在Project视图里新建一个文件夹,取名字叫做Platform, 然后在里面创建一个C#脚本,叫做 PlatformManager, 然后把SkylineManager的脚本拷贝到这里来,

修改一部分源码如下:

public class PlatformManager : MonoBehaviour {

    public Transform prefab;
public int numberOfObjects;
public float recycleOffset; public Vector3 minSize, maxSize, minGap, maxGap;
public float minY, maxY; private Vector3 nextPosition;
private Queue<Transform> objectQueue; void Start()
{
objectQueue = new Queue<Transform>(numberOfObjects);
for (int i = ; i < numberOfObjects; i++)
{
objectQueue.Enqueue((Transform)Instantiate(prefab));
}
nextPosition = transform.localPosition;
for (int i = ; i < numberOfObjects; i++)
{
Recycle();
}
} void Update()
{
if (objectQueue.Peek().localPosition.x + recycleOffset < Runner.distanceTraveled)
{
Recycle();
}
} private void Recycle()
{
Vector3 scale = new Vector3(
Random.Range(minSize.x, maxSize.x),
Random.Range(minSize.y, maxSize.y),
Random.Range(minSize.z, maxSize.z)); Vector3 position = nextPosition;
position.x += scale.x * 0.5f;
position.y += scale.y * 0.5f; Transform o = objectQueue.Dequeue();
o.localScale = scale;
o.localPosition = position;
nextPosition.x += scale.x;
objectQueue.Enqueue(o); nextPosition += new Vector3(
Random.Range(minGap.x, maxGap.x) + scale.x,
Random.Range(minGap.y, maxGap.y),
Random.Range(minGap.z, maxGap.z)); if (nextPosition.y < minY)
{
nextPosition.y = minY + maxGap.y;
}
else if (nextPosition.y > maxY)
{
nextPosition.y = maxY - maxGap.y;
}
}
}

然后就要创建一个用于显示平台的形状了,在Skyline文件夹里,选中Skyline Close Mat ,Ctrl+D复制一份,颜色改为(255,60,255)然后拖放到Platform里,

改名为Platform Regular Mat, 然后创建一个Cube,把这个Meterial 拖放到Cube上,然后把Cube拖回到Platform文件夹里,使之成为预设,改名为Platform

在层次视图里创建一个 Empty GameObject,命名为Platform Manager, 同样也放到Managers 下面,成为它的子对象。把Platform Manager这个脚本拖放到对象上,成为它的

组件。参考下图设置一下脚本的各个变量的值。

跳跃和坠落                                                                                                                        

现在有平台了,是时候升级一下我们的“奔跑者”了,我们使用物理引擎来实现跑,跳,坠落等效果。选中在层次视图里选中“奔跑者”,然后Compnent->physics->rigid body,

给它添加物理引擎支持,因为我们不想让它旋转也不想跳出我们的视野,因此要给他添加 Z轴约束并且锁定所有的旋转方向。

因为运动将会在平台上平滑的移动来完成,让我们来创建一个没有摩擦的材质(Project 视图上 Platform文件夹上 Create->Physics Material)。 具体设置如下图所示。

将这个物理材质设置为层次试图里的 Runner的 Box Collider 组件的 Material 属性

把Runner的Position 设置为(0,2,0)这样的话 一开始 “跑步者” 就会降落在平台上,然后开始运动。

运行一下,可以看到“跑步者”落到平台,然后向右侧运动,跟设想的一模一样,但是假如它蹭到平台的边缘,就会发现运动有些奇怪。这是因为即使在这个情况下,Update也不会不断修改奔跑者”位置的,

让我们换一种方式,使用物理引擎,采用添加“力”来使物体位置改变。

把Runner.cs代码修改如下:

public class Runner : MonoBehaviour {

    public static float distanceTraveled;

    public float acceleration;

    private bool touchingPlatform;

    void Update()
{
distanceTraveled = transform.localPosition.x;
} void FixedUpdate()
{
     //碰撞的时候不会继续作用力
if (touchingPlatform)
{
rigidbody.AddForce(acceleration, 0f, 0f, ForceMode.Acceleration);
}
} void OnCollisionEnter()
{
touchingPlatform = true;
} void OnCollisionExit()
{
touchingPlatform = false;
}
}

设置acceleration的值为5

在Platform文件夹里,像刚才那样给Platform也创建物理材质,命名为 Platform Regular PMat, 设置如下,然后把它复制给Platform的预设(prefab)

现在平台有了一些摩擦力,但是因为有持续作用力,所以我们的“跑步者”能够克服这些阻力。下面再给Runner.cs 添加一个变量来控制“跑步者”的跳跃速度。

添加变量 jumpVeclocity 设置为 (1,7,0)

将 Runner.cs 代码改为如下:

public class Runner : MonoBehaviour {

    public static float distanceTraveled;
public Vector3 jumpVelocity; public float acceleration; private bool touchingPlatform; void Update()
{
if (touchingPlatform && Input.GetKeyDown(KeyCode.A))
{
Debug.Log();
rigidbody.AddForce(jumpVelocity, ForceMode.VelocityChange);
}
distanceTraveled = transform.localPosition.x;
} void FixedUpdate()
{
if (touchingPlatform)
{
rigidbody.AddForce(acceleration, 0f, 0f, ForceMode.Acceleration);
}
} void OnCollisionEnter()
{
touchingPlatform = true;
} void OnCollisionExit()
{
touchingPlatform = false;
}
}

现在运行,然后按下鼠标左键,就可以让我们的“跑步者”跳跃了。

但是玩一会就发现,假如“奔跑者”碰到平台的边缘,我们可以通过不断的按鼠标左键来防止坠落。

这是一个bug,需要修复一下。

解决方案很简单,一旦玩家按下鼠标左键,就将touchingPlatform变量的值设为false,就不可以连续的跳跃了。

    void Update()
{
if (touchingPlatform && Input.GetKeyDown(KeyCode.A))
{
touchingPlatform = false;
rigidbody.AddForce(jumpVelocity, ForceMode.VelocityChange);
}
distanceTraveled = transform.localPosition.x;
}

部署到Windows Phone

因为Unity的跨平台做的实在是太好了,我们只需要简单两步就可以生成Windows Phone的工程,在菜单栏 File-> Build Setting弹出对话框

然后选择 Player Setting

修改一下 Orientation ,连上你的WP8手机,然后点击 Build & Run ,会弹出一个选择文件夹的对话框,因为Unity会帮我们生成工程,所以这也就是工程的所在地,

新建文件夹 Projects->WP8 然后选择,等待一会编译完成,会发现游戏开始了,很兴奋吧!这么简单就可以做一款游戏,so easy, 老板再也不担心项目进度了。

但是!!!

还有问题,因为没有处理回退事件,所以现在的游戏是无法通过后退按钮退出的,找到编译出来的项目工程,打开,然后注释后退事件的代码:

private void PhoneApplicationPage_BackKeyPress(object sender, CancelEventArgs e)
{
//e.Cancel = UnityApp.BackButtonPressed();
}

OK,至此,第一部分项目完成了,请等待 后续 的到来。

附项目下载地址:点击下载

(译)【Unity教程】使用Unity开发Windows Phone上的横版跑酷游戏的更多相关文章

  1. 【使用Unity开发Windows Phone上的2D游戏】(1)千里之行始于足下

    写在前面的 其实这个名字起得不太欠当,Unity本身是很强大的工具,可以部署到很多个平台,而不仅仅是可以开发Windows Phone上的游戏. 只不过本人是Windows Phone 应用开发出身, ...

  2. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程:简介及目录》(附上完整工程文件)

    介绍:讲述如何使用Genesis-3D来制作一个横版格斗游戏,涉及如何制作连招系统,如何使用包围盒实现碰撞检测,软键盘的制作,场景切换,技能读表,简单怪物AI等等,并为您提供这个框架的全套资源,源码以 ...

  3. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程05:技能读表》

    5.技能读表 技能读表概述: 技能读表,作为实现技能系统更为快捷的一种方式,被广泛应用到游戏开发中.技能配表,作为桥梁连接着游戏策划者和开发者在技能实现上的关系.在游戏技能开发中,开发者只需要根据策划 ...

  4. Cocos2dx游戏开发系列笔记13:一个横版拳击游戏Demo完结篇

    懒骨头(http://blog.csdn.net/iamlazybone QQ:124774397 ) 写下这些东西的同时 旁边放了两部电影 周星驰的<还魂夜> 甄子丹的<特殊身份& ...

  5. Unity3D开发一个2D横版射击游戏

    教程基于http://pixelnest.io/tutorials/2d-game-unity/ , 这个例子感觉还是比较经典的, 网上转载的也比较多. 刚好最近也在学习U3D, 做的过程中自己又修改 ...

  6. 【使用Unity开发Windows Phone上的2D游戏】(2)初识工具

    下载工具 我们需要下载两个工具:Unity 和 2D Toolkit Unity 在我写这篇文章的时候,最新的Unity版本是4.2.1, 下载地址 Unity公司的开发效率实在是很高,我一个多月前开 ...

  7. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程07:UI》

    概述: UI即User Interface(用户界面)的简称.UI设计是指对软件的燃机交互.操作逻辑.界面美观的整体设计.好的UI设计不仅可以让游戏变得更有品位,更吸引玩家,还能充分体现开发者对游戏整 ...

  8. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程01: 资源导入》

    1. 资源导入 概述: 制作一款游戏需要用到很多资源,比如:模型.纹理.声音和脚本等.通常都是用其它相关制作资源软件,完成前期资源的收集工作.比如通常用的三维美术资源,会在Max.MAYA等相应软件中 ...

  9. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程08:虚拟键盘实现》--本系列完结

    8.虚拟键盘实现 概述: 硬键盘就是物理键盘,平时敲的那种.软键盘是虚拟的键盘,不是在键盘上,而是在"屏幕"上.虚拟按键就是虚拟键盘的一部分,根据功能需求,提供部分按键效果的UI可 ...

随机推荐

  1. Linux学习笔记-Ubuntu添加右键菜单打开终端

    1.进入个人目录(如/home/batsing,下文缩写成 ~ ):设置显示隐藏文件,或使用命令行:2.进入 ~/.gnome2/nautilus-scripts 文件夹,新建一个文件,名为 term ...

  2. 【leetcode】Gray Code (middle)

    The gray code is a binary numeral system where two successive values differ in only one bit. Given a ...

  3. 实现MFC菜单画笔画圆,并且打钩

    这个是用最简单的方法,移动客户区,圆会不见,所以下一篇我还要改进. 首先新建一个MFC单文件,在资源那里的菜单下,建立画笔,可以弹出红画笔,蓝画笔和绿画笔,,给出ID_RED,ID_BLUE,ID_G ...

  4. 测试GeoGebra博客

    已知函数 \(\textit{f}(\textit{x})=2\textit{m}\ln\textit{x}-\textit{x}^2\), \(\textit{g}(\textit{x})=\tex ...

  5. Poj 1255 覆盖的面积 2014-07-28 12:29 116人阅读 评论(0) 收藏

    覆盖的面积 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Sub ...

  6. C++重写与重载、重定义

    文章引用自:http://blog.163.com/clevertanglei900@126/blog/static/111352259201102441934870/ 重载overload:是函数名 ...

  7. 基于三层架构的增删改查Get知识点

    给DataGridView控件绑定datatable数据源之后总是会多一行,在属性里修改属性allowuserToaddrow值为false即可 不可编辑状态是设置成只读状态即可,英文属性readon ...

  8. 【20190221】HTTP-URI与URL

    URI(uniform resource identifier)统一资源标识符是由某个协议方案表示的资源的定位标识符, URI 用字符串标识某一互联网资源,而 URL 表示资源的地点(互联网上所处的位 ...

  9. js中的call、apply、bind

    在js中每个函数都包含两个非继承而来的方法:call()和apply() call和apply的作用都是在特定的作用域中将函数绑定到另外一个对象上去运行,即可以用来重新定义函数的执行环境,两者仅在定义 ...

  10. centos7.4 64位安装 google-chrome 与 chromedriver 运行 Python selenium 项目

    centos7.4 实例 利用 yum 命令安装 google-chrome 超级简单(安装最新版): yum install https://dl.google.com/linux/direct/g ...