65.9K
CodeProject 正在变化。 阅读更多。
Home

进入虫洞

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2014年10月16日

CPOL

10分钟阅读

viewsIcon

12827

在参加了早期的一项英特尔竞赛后,开发者 Dave Gannon 接受了这些挑战,凭借 Wormhole Pinball(在英特尔 2013 应用创新竞赛(与 Intel® Developer Zone 合作举办)的游戏类别中的获奖应用)强势回归。

Intel® Developer Zone 提供跨平台应用开发的工具和操作指南、平台和技术信息、代码示例以及同行专业知识,帮助开发者进行创新并取得成功。加入我们的社群,参与 物联网AndroidIntel® RealSense™ 技术Windows,下载工具,获取开发套件,与志同道合的开发者分享想法,并参与黑客松、竞赛、路演和本地活动。

相关文章
面向第四代英特尔®酷睿™处理器的英特尔®处理器显卡开发人员指南
触摸和传感器
如何创建可用的触摸UI
如何调整触摸控件

多点触控一体机 (AIO) 平台拓展了编写触摸屏应用的可能性。由于大多数触摸屏手机和平板电脑的屏幕尺寸有限,通常只能一个人同时点击或滑动设备。然而,对于屏幕尺寸通常超过两英尺的更大尺寸多点触控一体机,多人可以围坐在一起同时在屏幕上点击,尤其是在一体机平放在桌子上时。

当然,为大屏幕和多用户构建的触摸屏应用也有其自身的编程挑战。在参加早期的一项英特尔竞赛后,开发者 Dave Gannon 接受了这些挑战,凭借《Wormhole Pinball》(在 英特尔 2013 应用创新竞赛(与 Intel® Developer Zone 合作举办)的游戏类别中的获奖应用)强势回归。

Gannon 从小就热爱电脑,他的父母在他孩提时代就买了一台 Commodore* 64。他通过输入 C-64 手册中的 BASIC 命令来开始编程,然后观察启动屏幕上的变化。

如今,他工作之余会沉迷于电脑游戏的世界。起初只是制作短小的演示片段的爱好,已演变成编写完整的游戏。去年夏天,Gannon 在 CodeProject 上阐述了他的游戏意图,他写道:“我希望利用一体机来扩展弹球游戏的意义。” CodeProject 社区将 Gannon 的弹球应用提交评为游戏类别的大奖得主,这一殊荣为他赢得了 10,000 美元。

一体机平台的吸引力

Gannon 为 联想 IdeaCentre* Horizon 27 开发了《Wormhole Pinball》,这是一款专为休闲游戏设计的桌面 PC。Gannon 对小时候和朋友们围坐在咖啡桌式街机旁玩游戏的时光记忆犹新,一直希望能在家中也拥有一台。“当我看到桌面一体机时,我必须为它开发一款游戏,”他说道。

图 1:《Wormhole Pinball》截图。Gannon 希望他的参赛作品能重现咖啡桌式街机的游戏体验。

Gannon 希望在游戏中充分利用 Horizon 的“桌面”特性。弹球是他首先想到的点子。一个考虑因素是如何渲染图形。3D 球体和挡板在大屏幕上看起来可能会很棒,尽管 Gannon 在去年的比赛中有过经验后变得谨慎。他花费了大部分时间试图在一项能用摄像头跟随玩家面部特征的功能中融入 3D,几乎没有时间用于游戏的其余开发。

这一次,Gannon 坚持使用 2D 图形,并将节省下来的时间用于开发有趣的特性,让游戏对玩家更具吸引力。最典型的例子是虫洞,玩家可以在屏幕上绘制虫洞来传送球体,这是老式街机版本游戏不可能实现的一个精妙功能。“我需要一些东西让它变得疯狂一点,不可预测一点,”Gannon 说。其他功能包括自适应多维重力,会随着玩家数量的增加而变化。Gannon 的应用最多支持四名玩家,这意味着它可以处理同时手势,这是 AIO 平台最独特的特性之一。

构建游戏元素

Gannon 使用开源的 Farseer* Physics Engine 来创建游戏的核心元素,包括挡板,屏幕的每个角落都会出现一对挡板。对于自称爱好者的 Gannon 来说,这是合乎逻辑的起点。“我只是那样做了,”他被问及如何总结他的应用规划和构建策略时说道。“你会从你需要的主要东西开始,那就是一个球和一些挡板(图 2),然后在此基础上进行。”

图 2:Gannon 使用 Farseer* Physics API 中提供的简单图元构建了他挡板的复杂形状。

为了构建组合成挡板的形状,Gannon 在图纸上绘制了硬编码的梯形,以期理解 Farseer 的细微差别。“任何多边形都需要先进行三角剖分才能在 Farseer 中使用,”他说。“你还必须确保你的多边形是凸的,因为使用内置函数对凹多边形进行三角剖分有点麻烦。”

Farseer 主要是一个碰撞检测系统,它会根据构成它的形状的密度和面积为给定对象创建自己的质量,Gannon 发现这个默认设置很麻烦。“大多数时候你可能不想要这个,所以请记住在最后显式设置质量,否则它会被覆盖,”他说。图 3 是 Gannon 完成此操作的代码。

     private void CreateFlipper()
        {
            var fixtures = this.Body.FixtureList;
            fixtures.ForEach(i => this.Body.DestroyFixture(i));
            fixtures = null;

            const float largeCircleRadius = 42.8f;
            const float smallCircleRadius = 21.4f;
            var largeCircle = new CircleShape(FarseerUnitConverter.ToPhysicsUnits(largeCircleRadius) * this.Scale, 1.0f);
            var smallCircle = new CircleShape(FarseerUnitConverter.ToPhysicsUnits(smallCircleRadius) * this.Scale, 1.0f);

            smallCircle.Position = FarseerUnitConverter.ToPhysicsUnits(new Vector2(235.4f * this.Scale, 0.0f));
            List<Vector2> points = new Vector2[] { 
                FarseerUnitConverter.ToPhysicsUnits(new Vector2(0.0f, -largeCircleRadius * this.Scale)),
                FarseerUnitConverter.ToPhysicsUnits(new Vector2(235.4f * this.Scale, -21.8f * this.Scale)),
                FarseerUnitConverter.ToPhysicsUnits(new Vector2(235.4f * this.Scale, 21.8f * this.Scale)),
                FarseerUnitConverter.ToPhysicsUnits(new Vector2(0.0f, largeCircleRadius * this.Scale)) }.ToList();
            var trapezium = new Vertices(points);

            var triangulatedTrapezium = FarseerPhysics.Common.Decomposition.Triangulate.ConvexPartition(trapezium, TriangulationAlgorithm.Bayazit);
            var trapeziumShape = new PolygonShape(triangulatedTrapezium[0], 1.0f);
            this.Body.CreateFixture(largeCircle);
            this.Body.CreateFixture(smallCircle);
            this.Body.CreateFixture(trapeziumShape);
            this.Body.BodyType = BodyType.Dynamic;
            this.Body.Mass = this.mass;
            this.Body.AngularDamping = 0.1f;
        }
图 3:将游戏挡板由简单的形状——圆形和梯形——创建出来的代码。

在 Farseer 中创建的几何图形实际上不会被渲染。相反,精灵会以相同的形状被渲染。“这使得绘制图形所需的代码变得简单得多,因为不需要渲染几何图形,但你可以获得非常漂亮的图形,”Gannon 说。图 4 是一个挡板的精灵,它以与 Gannon 代码中 Farseer 几何图形相同的 Gannon 代码中的位置和角度绘制。

图 4:一个挡板的精灵,其绘制位置和角度与图 3 代码示例中显示的 Farseer* 几何图形相同。

触摸识别的挑战与解决方案

不出所料,Gannon 面临的最大挑战之一是如何让触摸识别在一个典型的游戏中正常工作,因为可能有四个人围在屏幕旁,同时点击和滑动。一定半径内的触摸点被认为是同一个触摸事件的一部分。这很容易。但是如何确定玩家绘制的圆是顺时针还是逆时针方向以创建虫洞呢?这是游戏的一个关键特性,因为虫洞(图 5)的行为方式取决于绘制方向。

图 5:玩家用手指绘制圆以创建虫洞时显示的粒子轨迹。

要解决这个挑战,首先需要遍历一组被确定为同一个触摸事件一部分的触摸点列表。接下来,Gannon 的代码计算列表中相邻两点构成的每个直角三角形的有符号面积。计算手性得分之和,如果得分是正的,则该触摸事件被认为是顺时针;如果是负的,则该触摸事件被认为是逆时针。图 6 是代码,以及 Gannon 在 Stack Exchange 问答网站上搜索后找到的assigned area 函数。

        private void UpdateOrientation()
        {
            int pointCount = this.pointHistory.Count;
            if (pointCount < 3)
                return;

            this.handednessScores.Clear();

            for (int i = 0; i < pointCount - 1; i++)
            {
                // Sum over the edges (x2-x1)(y2+y1)
                Point p1 = this.pointHistory[i];
                Point p2 = this.pointHistory[i + 1];
                int score = (p1.X * p2.Y) - (p1.Y * p2.X);
                this.handednessScores.Add(score);
            }

            int sumScores = this.handednessScores.Sum();
            this.PortalOrientation = sumScores > 0 ? PortalOrientation.Clockwise : PortalOrientation.Anticlockwise;
        }
图 6:用于确定创建虫洞的圆是顺时针还是逆时针绘制的代码。(在游戏中,虫洞的行为方式因绘制方向而异。)

另一个挑战与挡板的工作方式有关。任何弹球高手都知道,挡板的运动范围相当有限。Gannon 在 Farseer 中定义的关节限制上遇到了一些困难。他说,有时他的挡板的早期版本会“突破限制,最后在错误的一侧晃动”。Gannon 添加了图 7 中的代码,这是一项他颇为自豪的技巧。“它最终效果很好,”他说。“它通过在达到极限时反转角速度并将乘以变数反弹(非常接近 1.0 但又不完全是 1.0)来防止挡板永远反弹,甚至给挡板增加了一些弹性。”

        private void BounceOffLimits()
        {
            float angularVelocity = this.Body.AngularVelocity;
            float bounce = -2.9f;
            if (this.Body.Rotation <= this.Joint.LowerLimit)
            {
                this.Body.Rotation = this.Joint.LowerLimit + 0.0001f;
                this.Body.AngularVelocity = angularVelocity * bounce;
            }
            if (this.Body.Rotation >= this.Joint.UpperLimit)
            {
                this.Body.Rotation = this.Joint.UpperLimit - 0.0001f;
                this.Body.AngularVelocity = angularVelocity * bounce;
            }
        }
图 7:控制挡板运动范围和反弹的代码。

Gannon 使用 Windows* 8 API 来收集触摸数据,将大约 10 层深度的数据存储在缓冲区中。其他挑战包括决定使用哪种语言和框架。Gannon 使用 C# 编写了该应用,并采用了 Microsoft 的 XNA* Framework。他遵循了标准的组件模型,顶层组件和服务以及相关的子组件(用于游戏的各个部分,例如球或挡板)位于层级结构的更下方。

Gannon 说,使用 XNA 构建应用程序的一个缺点是,Microsoft 将其视为桌面应用程序,因此不会在 Windows 应用商店中发布它们,而大多数 Windows 8 应用都是在那里销售的。Gannon 新成立的公司 Null Ref(与 AIC 2013 的参赛选手 Adam Hill 共同创立)的首批任务之一可能是将《Wormhole Pinball》移植到 MonoGame,以获得更广泛的覆盖,但这要等到 Gannon 和 Hill 完成对 Hill 的《Hot Shots》的打磨并将其作为他们的第一个商业产品。

给其他开发者的建议

Gannon 说,他对开发者的建议主要归结为适当地确定项目范围,并且不要害怕放弃不合适的功能。同样重要的是要记住,当一体机设备平放在桌子上时,它们可能会如何被使用。《Wormhole Pinball》的玩家没有上下之分,无论玩家在屏幕的哪个位置,体验都应该大体相同。显然,上下之分对于为小型触摸屏设备构建的大多数应用程序的用户体验至关重要。

图 8:《Wormhole Pinball》游戏的获胜者指示图。

也许最重要的是,Gannon 说开发者需要意识到游戏行业中一些周期性的趋势,尤其是由小型开发团队为触摸屏创建的简单游戏再次兴起,并获得了巨大的观众。(难道没有《糖果传奇*》吗?)Gannon 指出,20 世纪 80 年代初,当他在 Commodore 64 上敲击 BASIC 命令时,恰逢 8 位游戏时代的黄金时期。

“在某些方面,这已经回到了 8 位时代,当时你会有一些人在卧室里自己开发游戏,销售并赚了很多钱,”他说。“然后一切开始变得更复杂,你需要越来越大的团队。现在软件和工具已经发展到非常容易使用的阶段,像我这样的人现在可以轻松地坐下来,自己编写游戏,并将其发布出去。”

有用的资源

Gannon 使用免费的开源 Farseer Physics Engine 来构建动态游戏元素。Farseer 是一个具有逼真物理响应的碰撞检测系统。该引擎的特点包括连续碰撞检测(带有时机求解器);接触回调:开始、结束、预解、后解;凸多边形和凹多边形以及圆;等等。当 Gannon 对某个编程挑战感到困惑时,他会花时间研究 Stack Overflow,这是一个面向专业程序员和爱好者程序员的问答网站。他使用 Microsoft XNA Framework 以 C# 编写了该应用。目前,他正在探索将《Wormhole Pinball》移植到 MonoGame,这是一个 Microsoft XNA 4 Framework 的开源实现,可以轻松地将游戏移植到 iOS*、Android* 以及其他操作系统。

Intel® Developer Zone 提供跨平台应用开发的工具和操作指南、平台和技术信息、代码示例以及同行专业知识,帮助开发者进行创新并取得成功。加入我们的社群,参与 物联网AndroidIntel® RealSense™ 技术Windows,下载工具,获取开发套件,与志同道合的开发者分享想法,并参与黑客松、竞赛、路演和本地活动。

相关文章

 

Intel、Intel 徽标、Intel Core 和 Intel RealSense 是 Intel Corporation 在美国和/或其他国家/地区的商标。
*其他名称和品牌可能被声明为他人的财产。
版权所有 © 2014。英特尔公司。保留所有权利。

© . All rights reserved.