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

幕后花絮:使用HTML5构建的互动音乐视频游戏

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2012年6月8日

CPOL

8分钟阅读

viewsIcon

17091

本文探讨了 Jasmine Villegas 如何创造一种互动体验来吸引现有粉丝群,并帮助她接触到新粉丝,同时展示了 HTML5 在网络上的强大功能。

30 天开发一个 Windows 8 应用

音乐视频正在演变。曾经像 MTV 和 VH1 这样的频道上的音乐视频范式,如今已被网络上发布的音乐视频的巨大数量所掩盖。与电视等传统媒体不同,传统媒体是一个音乐视频接一个地播放,网络上的音乐视频却在相互竞争,争夺观众的注意力。那么,艺术家如何才能在众多声音中脱颖而出并受到关注,特别是如果你是像 Jasmine Villegas 这样冉冉升起的新星呢?

这正是 Jasmine 和 Internet Explorer 团队试图解决的挑战。她的愿景是创造一种互动体验,以实现两个目标:1)吸引现有粉丝群,2)帮助她接触到新粉丝。为了做好这件事,微软请来了创意机构 Digital KitchenBradley and Montgomery 的 HTML5 专家来创建 justafriend.ie。结果不仅达到了 Jasmine 的目标,还展示了 HTML5 在网络上的强大功能。

整个音乐视频中都贯穿了大量炫酷的技术亮点,将它带入了生活。无论您是 Jasmine Villegas 的挚友,还是只是想了解更多关于 HTML5 的信息,我们都希望为您提供更多关于我们如何让 Just A Friend 在线上的信息。

  1. 为 HTML5 标准设置站点
  2. 将 Facebook 数据连接到您的 Web 应用
  3. 在 HTML5 画布和视频上投影图像
  4. 逐像素提取视频帧
  5. 为了提高性能而放大 PNG
  6. 序列化和媒体加载
  7. 拨打您的电话号码集成

使用 HTML5 标准设置站点

我们开始项目,确保 现代浏览器能够识别 并使用 HTML5 视频而不是插件。这很容易。

<!DOCTYPE html>

将 Facebook 数据连接到您的 Web 应用

Facebook Connect 是 JustaFriend.ie 的重要组成部分,它真正帮助吸引用户参与体验。当您开始播放视频时,系统会要求用户连接到他们的 Facebook 帐户。这使我们能够从他们的 FB 帐户中提取图像并直接将它们投影到视频中,还可以让我们在整个体验中显示他们的名字。结果是,Jasmine 的粉丝可以感觉自己是视频的一部分,与他们最喜欢的歌手一起。

在 HTML5 画布和视频上投影图像

HTML5 中的图像投影并不是一个新概念。事实上,该项目早期的大部分工作都基于 Steven Wittens 在 http://acko.net/files/projective-canvas/index.html 上提供的内容。但在 IE9 中,画布投影在测试中比其他现代浏览器表现更好,因此必须修改代码以实现跨平台工作。

一个很好的例子是,为了在记分牌上显示从 Facebook Connect 提取的用户姓名而采取的步骤。为了实现这一点,投影代码已更新为使用画布缓冲区而不是图像。这使得各种元素可以在投影之前被合成到缓冲区中。从记分牌的空白 PNG 开始,使用画布绘图 API 绘制姓名。另一个 PNG 被叠加在顶部以提供轻微的眩光。通过将此投影与视频帧匹配,而不是仅仅与静态、平坦的表面匹配,整个过程又向前迈进了一步。

PNG 的分层也用于将用户的 Facebook 照片投影到视频开头的 Jasmine 的卧室墙上。PNG 提供了阴影效果,使照片与墙上现有的照片无缝融合。这项技术在视频结尾 Jasmine 书桌上的照片上再次使用。这是最终的体验和为之提供动力的代码。

if (frame_offset == null) frame_offset = 0;
    var canvas, proj;
    var score_img_1,
        score_img_2,
        overlay,
        board_canvas,
        score_canvas_1,
        score_canvas_2;
    
    // View in the following line is a Backbone.js (http://documentcloud.github.com/backbone/#View) view.
    var self = view.extend({
        template:'<div class="scene HD" id="scoreboard_projection"></div>&',
        name:'scoreboardProjection',
        pageName: 'Bowling Scoreboard',
        onInit:onInit
    });

    return self;

    function onInit() {
        // First we load our images. "media" on the following lines are Media objects from http://www.justafriend.ie/cdn/js/jv/media.js
        score_img_1 = media.getImage('img/bowlingscore1.png');
        score_img_2 = media.getImage('img/bowlingscore2.png');
        overlay = media.getImage('img/bowlingscore_overlay.png');

        var scale_down_to_blur = .75;
        board_canvas = canvasUtil.create(Math.floor(800 * scale_down_to_blur), Math.floor(450 * scale_down_to_blur));
        score_canvas_1 = canvasUtil.create(800, 450);
        score_canvas_2 = canvasUtil.create(800, 450);

        canvas = canvasUtil.create(10, 10);
        
        // projection is part of the canvas projection library at http://www.justafriend.ie/cdn/js/jv/projection.js
        proj = projection(board_canvas, canvas, null, {
            wireframe:false,
            subdivisionLimit:3,
            patchSize:32
        });

    }
  
  // There's more to this, and you can find the full code at http://www.justafriend.ie/cdn/js/jv/scenes/scoreboardProjection.js        

}

使用上述技术和此代码源将产生与您的项目无缝融合的图像投影。

记分牌场景的源代码在这里:http://www.justafriend.ie/cdn/js/jv/scenes/scoreboardProjection.js

要了解更多关于使用 HTML5 画布进行开发的信息,请尝试以下链接:

逐像素提取视频帧

HTML5 视频仍然是一项不断发展的技术。尽管已经做了大量工作来确保帧的准确性,但它仍不完美。所以我们不得不借助一些帮助来搞定它。

HTML5 MediaElement API 提供了一个“currentTime”的 getter,它声称精确到毫秒,但这并不总是与渲染到屏幕的当前帧匹配。当在视频渲染过程中执行计算密集型处理时,这尤其是一个问题。

为了绕过这个问题,通过视频外部绘制的黑色和白色像素提取了帧号,这些像素被嵌入到视频中并放置在屏幕外。这不是你在视频中看到的标准 NTSC 扫描显示。相反,它是一个原始的二进制数据,手动创建并嵌入到视频中,以保持一切正确同步。虽然看起来很简单,但它是一种在视频中的交互时刻使用的非常实用的技术。没有它,视频将无法正确同步,这将导致叠加层与相应的帧不匹配。

function getCurrentFrameFromTimecode() {
	frame_canvas_ctx.drawImage(video, 961, 0, 1, 16, 0, 0, 1, 16);
	var timeBitmap = frame_canvas_ctx.getImageData(0, 0, 1, 16);
	var timeData = timeBitmap.data;
	var frame = 0;
	var value;
	for (var i = timeData.length - 1; i >= 0; i -= 4) {
	    value = (timeData[i - 3] + timeData[i - 2]
	    	+ timeData[i - 1]) > 125 ? 1 : 0;
	    if (Math.floor(i / 4) == 15) {
	        frame = value << Math.floor(i / 4);
	    } else {
	        frame |= value << Math.floor(i / 4);
	    }
	}
	current_frame_text = "Frame: "+frame;
	return frame;
}

使用此代码源来帮助保持视频和交互元素的同步。您可以在此处获取“帧代码读取器”模块的源代码:
http://www.justafriend.ie/cdn/js/jv/frameCodeReader.js

为了提高性能而放大 PNG

在舞蹈游戏中,图形元素需要与节拍模式匹配,并在击中挡板时爆炸以产生酷炫的效果。对于爆炸,PNG 精灵被转换为画布图像数据,然后创建了一个粒子系统,其中每个粒子代表图像中的一个像素。粒子系统非常基础,是使用 toxiclibs 的 Javascript 端口中的 2D Vector 类开发的。

在此处获取代码示例:http://haptic-data.com/toxiclibsjs/

在早期测试中,当同时渲染过多粒子时,性能成为一个问题。最简单的解决方案是创建带有大量透明度的 Photoshop 精灵。然后,当创建粒子系统时,仅为那些不透明度超过特定阈值的像素创建粒子。通过快速淡出和销毁粒子,获得了更好的性能。

早期原型可以在这里看到:http://www.justafriend.ie/cdn/dev/proto13b.html

序列和媒体加载

在整个体验过程中,根据用户交互有不同的结果。因为有这些不同的结果,所以必须创建许多不同的视频。因此,媒体加载器需要以一种使过渡看起来无缝的方式工作。

最初使用了 Popcorn.js 和 Popcorn.sequence 模块,该模块在另一个 IE9 项目 Cut The Rope 中使用过。然而,很快就发现该框架对于这个项目来说有点大材小用,并且在序列化方面没有提供所需的精度。首先,在使用非整数的输入和输出点时,序列会中断,并且定时回调实际上不同步。

最终,创建了一个具有帧特定输入和输出点的场景系统。在每一帧上,所有应该在该帧可见的场景都会被渲染。每个场景都可以被看作是一个叠加层,因为 HTML5 视频是在后台渲染的。

每个场景都使用自定义媒体加载器在启动时预加载所需的资源。有各种各样的 HTML5 媒体加载器,但找不到一个满足项目特定需求的。因此,创建了一个自定义媒体加载器,它可以与 RequireJS 一起工作,并支持图像、视频和音频。加载器支持 onComplete 和 onError 回调以及应用程序级别的状态通知。所有请求都排队并限制在一定数量的“线程”中,以避免某些浏览器中最常见的 HTTP 管道问题,幸运的是,这对于 Internet Explorer 9 等现代浏览器来说不是问题。

一个问题是,由于现代浏览器自然地以渐进方式加载视频片段的方式,HTML5 视频片段不会完全预加载。为了确保视频被缓存,它们是通过 Ajax 风格的 XHR 加载的。主视频是唯一允许以传统方式流式传输的视频。主视频是根据用户交互而不改变的唯一元素。如果它被预加载,体验开始时的初始加载时间将非常长。通过组合使用预加载和渐进加载的视频元素,传统缓冲区时间被消除了。

改编此代码源来加载您的资产,以便它们无缝过渡。

媒体加载器的源代码在这里:http://www.justafriend.ie/cdn/js/jv/media.js

拨打您的电话号码

体验中隐藏的一个元素是使用了 Tropo API,它允许您在视频结尾处桌子上的手机上输入您的电话号码。通过这样做,Jasmine 会回拨您拨打的号码并播放 6 条随机语音留言中的一条。API 易于实现,并为经历这一切的个人增添了一层惊喜和愉悦。

总结

感谢阅读 Jasmine Villegas 的 Just A Friend 的幕后开发人员拆解。

要了解更多关于为现代浏览器开发跨浏览器代码的信息,请从 MSDN 开始:http://msdn.microsoft.com/ie

© . All rights reserved.