|
|
话说很久没写过代码类的文章了,这次送上的是“翻滚吧舰娘!”的代码攻略。所谓“翻滚吧舰娘!”,最早是“GOODSMILE”为了宣传两只浴室玩具“お風呂これくしょん 島風”和“お風呂これくしょん 赤城”而制作的网站特效。后来国内某11区AMAZON代购网站把该特效给搬上了自己主页,并在代码注释上把其命名为:翻滚吧舰娘!
最初在GOODSMILE官网看到这个特效时,个人已经觉得颇为有趣。而当看到萌购把其搬过来后,个人便也想弄一个放到自己BLOG上。最后工夫不负有心人,花了4天时间敲代码敲得脖子痛死后,终于成功把之折腾出来并放到了个人BLOG首页上了。
虽然“翻滚吧舰娘!”的特效看起来非常简单,但其实有好几个细心留意才会发现的细节。例如舰娘游泳时并不是直线移动,而是会伴随着上下颠簸而左右摇晃。又例如舰娘不仅可以用鼠标捉起四处飞,还会随着浏览器窗口大小改变而有相应的动画。
正因为有这么多细节,刚开始个人还以为是个很简单的网页特效。结果后面越写越多,搞了4天才完成。其实个人最开始是想直接搬萌购的源代码,但点开一看就傻眼了,以个人的水平是完全看不懂……说实在我就只会个document.getelementbyid,萌购源代码那种商业级的水平,是连搬都不懂得怎么去搬,所以最后只能网上搜着自己重新写了个。虽然代码看起来比较脏乱,全局变量也四处乱飞,但至少是把效果给实现出来了。下面便是素材和源码:
-------------华丽的分割线-------------
*素材1:舰娘·徐驰(kankore-bath-shimakaze.png)
*素材2:舰娘·赤城(kankore-bath-akagi.png)
*素材3:海水(kankore-bath-water.png)
源代码:新建记事本并把下面代码全部复制进去,另存为htm文件后与上面3张素材图片放到同一文件夹下,双击打开便可以直接运行“翻滚吧舰娘!”网页特效。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<style type="text/css">
.water
{
background-repeat: repeat;
width: 2760px;
height: 49px;
position: absolute;
bottom: 0px;
opacity: 0.7;
}
.ship
{
width: 170px;
height: 170px;
position: absolute;
top: -180px;
left: -170px;
cursor: pointer;
}
.copyright
{
width: 550px;
position: absolute;
bottom: 0px;
top: -18px;
left: 5px;
text-align: left;
font-family: 微软雅黑;
font-size: 10px;
color: #FFFFFF;
cursor: pointer;
}
</style>
<title>翻滚吧舰娘!</title>
</head>
<body>
<div id="kankore_bath" style="position: fixed; bottom: 0; left: 0; opacity: 1;">
<div style="background-image: url(kankore-bath-shimakaze.png);" id="shimakaze" class="ship">
</div>
<div style="background-image: url(kankore-bath-akagi.png);" id="akagi" class="ship">
</div>
<div>
<div style="background-image: url(kankore-bath-water.png); left: -1380px;" id="kankore_bath_water1"
class="water">
</div>
<div style="background-image: url(kankore-bath-water.png); left: 1380px;" id="kankore_bath_water2"
class="water">
</div>
</div>
<div class="copyright" id="copyright">
Kankore ©2014 DMM.com/KADOKAWA GAMES All Rights Reserved. / Animation by ©GoodSmileCompany</div>
</div>
<script language="javascript" type="text/javascript">
// 初始化动画
$(document).ready(function () {
// if (document.URL == "http://hero32167.blog126.fc2.com/" || document.URL == "http://hero32167.blog126.fc.com/") {
document.ondragstart = function () { return false; }
setDirection();
setShip();
animateWater();
animateShip();
// }
// else {
// $("#kankore_bath").css("display", "none");
// }
})
// 设置水流方向
var direction;
function setDirection() {
var s = Math.random();
if (s <= 0.5) {
direction = "+";
}
else {
direction = "-";
}
}
// 初始化舰娘
var ship = "#shimakaze";
function setShip() {
if ($(ship).is(":animated")) {
stopShip();
}
$("#shimakaze").css({ visibility: "hidden" });
$("#akagi").css({ visibility: "hidden" });
var s = Math.random();
if (s <= 0.5) {
ship = "#shimakaze";
}
else {
ship = "#akagi";
}
if (direction == "+") {
$(ship).css("left", "-170px");
}
else {
$(ship).css("left", getWindowWidth() + "px");
}
$(ship).css({ visibility: "visible" });
}
// 鼠标事件
var offsetX, offsetY, mouse_down_flag = false, mouse_move_flag = false;
$(".ship").click(function () { }).mousedown(function (e) {
stopShip();
animateDargShip();
mouse_down_flag = true;
mouse_move_flag = false;
offsetX = e.pageX - parseInt($(ship).css("left"));
offsetY = e.pageY - parseInt($(ship).css("top"));
});
$(document).mousemove(function (e) {
if (mouse_down_flag) {
mouse_move_flag = true;
var x = e.pageX - offsetX;
var y = e.pageY - offsetY;
$(ship).css({ top: y, left: x });
}
}).mouseup(function () {
if (mouse_down_flag) {
if (!mouse_move_flag) {
if (ship == "#akagi") {
window.open("http://www.goodsmile.info/ja/product/4213/%E3%81%8A%E9%A2%A8%E5%91%82%E3%81%93%E3%82%8C%E3%81%8F%E3%81%97%E3%82%87%E3%82%93+%E8%B5%A4%E5%9F%8E.html", "_blank");
}
else {
window.open("http://www.goodsmile.info/ja/product/4212/%E3%81%8A%E9%A2%A8%E5%91%82%E3%81%93%E3%82%8C%E3%81%8F%E3%81%97%E3%82%87%E3%82%93+%E5%B3%B6%E9%A2%A8.html", "_blank");
}
}
stopDragShip();
animateResetShip();
mouse_down_flag = false;
mouse_move_flag = false;
}
});
// 窗口事件
var windowHeight = getWindowHeight(), newWindowHeight;
var isResizing = false;
window.onresize = function () {
if (!isResizing) {
newWindowHeight = getWindowHeight();
if (newWindowHeight != windowHeight) {
stopShip();
isResizing = true;
var h = 1.2 * (newWindowHeight - windowHeight);
$(ship).css({ top: "-=" + h + "px" });
$(ship).animate({ left: direction + "=10px" }, 500, "linear");
setTimeout("animateResetShip()", 500);
windowHeight = newWindowHeight;
}
}
setTimeout(function () {
isResizing = false;
}, 100);
}
// 获取窗口高度
function getWindowHeight() {
var winHeight;
if (window.innerHeight) {
winHeight = window.innerHeight;
}
else if ((document.body) && (document.body.clientHeight)) {
winHeight = document.body.clientHeight;
}
if (document.documentElement && document.documentElement.clientHeight) {
winHeight = document.documentElement.clientHeight;
}
return winHeight;
}
// 获取窗口宽度
function getWindowWidth() {
var winWidth;
if (window.innerWidth) {
winWidth = window.innerWidth;
}
else if ((document.body) && (document.body.clientWidth)) {
winWidth = document.body.clientWidth;
}
if (document.documentElement && document.documentElement.clientWidth) {
winWidth = document.documentElement.clientWidth;
}
return winWidth;
}
// 舰娘摇晃动画
var timeRotate;
function animateDargShip() {
animateRotateShip("2");
setTimeout('animateRotateShip("-2")', 500);
timeRotate = setTimeout("animateDargShip()", 1000);
}
// 设置舰娘摇晃参数
function animateRotateShip(d) {
$(ship).css("-moz-transition", "-moz-transform 1s");
$(ship).css("-moz-transform", " rotate(" + d + "deg)");
$(ship).css("-webkit-transition", "-webkit-transform 1s");
$(ship).css("-webkit-transform", " rotate(" + d + "deg)");
$(ship).css("-o-transition", "-o-transform 1s");
$(ship).css("-o-transform", " rotate(" + d + "deg)");
$(ship).css("transition", "transform 1s");
$(ship).css("transform", " rotate(" + d + "deg)");
}
// 停止舰娘摇晃
function stopDragShip() {
clearTimeout(timeRotate);
}
// 重置舰娘动画
function animateResetShip() {
var y = parseInt($(ship).css("top"));
if (y != 180) {
if (y < -280) {
$(ship).animate({ top: -160 + "px" }, 700, "linear");
$(ship).animate({ top: -170 + "px" }, 100, "linear");
}
else if (y >= -280 && y < -180) {
$(ship).animate({ top: -170 + "px" }, 700, "linear");
}
else {
$(ship).animate({ top: -180 + "px" }, 500, "linear");
}
}
animateShip();
}
// 舰娘动画
function animateShip() {
if (direction == "+") {
if (parseInt($(ship).css("left")) > $(document.body).width() + 30) {
stopShip();
setShip();
}
}
else {
if (parseInt($(ship).css("left")) < -200) {
stopShip();
setShip();
}
}
var d = Math.random() * 4 - 2;
animateRotateShip(d);
var x = parseInt($(ship).css("left"));
if (direction == "+") {
x += 10;
}
else {
x -= 10;
}
var y = 3 * Math.sin(x) - 180;
$(ship).animate({ left: x + "px", top: y + "px" }, 1000, "linear", animateShip);
}
// 停止舰娘动画
function stopShip() {
$(ship).stop(true);
}
// 水流动画
function animateWater() {
var l1 = parseInt($("#kankore_bath_water1").css("left"));
var l2 = parseInt($("#kankore_bath_water2").css("left"));
if (direction == "+") {
if (l1 > 0 && l2 > 0) {
if (l1 > l2) {
$("#kankore_bath_water1").css("left", (l2 - 2760) + "px");
}
else {
$("#kankore_bath_water2").css("left", (l1 - 2760) + "px");
}
}
}
else {
if (l1 < 0 && l2 < 0) {
if (l1 < l2) {
$("#kankore_bath_water1").css("left", (l2 + 2760) + "px");
}
else {
$("#kankore_bath_water2").css("left", (l1 + 2760) + "px");
}
}
}
$("#kankore_bath_water1").animate({ left: direction + "=2px" }, 30);
$("#kankore_bath_water2").animate({ left: direction + "=2px" }, 30, animateWater);
}
// 设置点击版权后关闭全部动画
$("#copyright").click(function () {
$("#kankore_bath").animate({ opacity: "0" }, 2000);
stopShip();
$("#kankore_bath_water1").stop(true);
$("#kankore_bath_water2").stop(true);
setTimeout(function () { $("#kankore_bath").css("display", "none"); }, 3000);
window.open("http://www.goodsmile.info", "_blank");
});
</script>
</body>
</html>
-------------华丽的分割线-------------
接下来是代码和制作思路解释的时间。要实现“翻滚吧舰娘!”特效,涉及到的技术有:HTML、JavaScript(下简称JS)和CSS。HTML就不用说了,关键是JS和CSS。特效动画都需要用到前者派生的jQuery和后者最新版的CSS3来实现。虽然各种名词看起来很吓人,但这里只涉及到最基础的东西,所以上手难度其实非常低。下面先来看该特效的特点明细:
01、水:循环流动、透明
02、舰:向固定方向上下浮沉的移动
03、舰:到达尽头时从起点再次出发
04、舰:移动时左右摇晃
05、舰:鼠标拖动时跟随鼠标移动
06、舰:跟随鼠标拖移时左右摇晃
07、舰:单击打开官方页面
08、舰:鼠标松开时掉落水面
09、舰:窗口大小变化时动画回到水面
10、总:随机水流方向和浮动方向
11、总:随机选择舰娘
12、总:点击版权声明时打开官网,全动画停止消失
13、总:整体固定在窗口的底部,而非网页的底部
14、总:只在BLOG首页显示该特效
-----------------01-------------------
*01、水:循环流动、透明
水是最开始做的部分,其最难点是循环流动。个人最开始的思路是:首先获取当前窗口的宽度,然后用该宽度除以素材中海水图的宽度,得出需要多少张海水图才能水平铺满整个窗口。其后使用JS动态生成这么多张海水图,并使它们全部向固定方向平移。当最前头的一张完全移出窗口后,把其移动到海水队列的末尾。
该思路来源于网上的“无缝滚动图片特效”,具体代码网上也可以下载到。但实际编写时却先遇到个问题:假设有3张海水图,如何把其放到同一水平面上。个人最开始的方法是使用margin,强制上下移动DIV来达到统一水平面。但后来参考了萌购的代码,决定还是放弃margin而使用绝对定位。两者效果其实是一样的,但我隐约记得margin在IE各版本下是有问题的,而绝对定位操作也更自由,所以最后选择了后者。
接着是复制海水图。最开始的思路是使用jQuery的复制元素功能,但网上那示例硬是没看明白。后来苦思了一段时间,想出了个简单方法:不需要根据窗口最大宽度来动态生成海水图,而是直接定义两张超长的海水图,然后循环移动就行了,HTML和CSS代码如下:
.water
{
background-repeat: repeat;
width: 2760px;
height: 49px;
position: absolute;
bottom: 0px;
opacity: 0.7;
}
<div style="background-image: url(kankore-bath-water.png); left: -1380px;" id="kankore_bath_water1" class="water"></div>
<div style="background-image: url(kankore-bath-water.png); left: 1380px;" id="kankore_bath_water2" class="water"></div>
上述代码定义了两张宽度为2760PX的完全一样的海水图。其中第一张定位为前半部分隐藏在窗口左面,而第二张则左侧紧跟在第一张之后。如果以窗口大小为2760PX看的话,那第二张的后半部分其实也隐藏在窗口的右面。现在高清标准是1080P,也就是1920x1080,所以这里使用2760PX是足够的。
至于图片方面,最开始个人是以标准格式<div><img /></div>来编写的。但后来发现要实现2760PX的效果,直接把图片定义为DIV的背景图片更好。注意图片并不是按DIV宽度来拉伸,而是重复显示,所以需要把DIV定义为和图片一样的高度。
接着是关键的循环动作,以jQuery来实现动画特效,并加上超出屏幕时的重新定位判断,代码如下:
function animateWater() {
var l1 = parseInt($("#kankore_bath_water1").css("left"));
var l2 = parseInt($("#kankore_bath_water2").css("left"));
if (direction == "+") {
if (l1 > 0 && l2 > 0) {
if (l1 > l2) {
$("#kankore_bath_water1").css("left", (l2 - 2760) + "px");
}
else {
$("#kankore_bath_water2").css("left", (l1 - 2760) + "px");
}
}
}
else {
if (l1 < 0 && l2 < 0) {
if (l1 < l2) {
$("#kankore_bath_water1").css("left", (l2 + 2760) + "px");
}
else {
$("#kankore_bath_water2").css("left", (l1 + 2760) + "px");
}
}
}
$("#kankore_bath_water1").animate({ left: direction + "=2px" }, 30);
$("#kankore_bath_water2").animate({ left: direction + "=2px" }, 30, animateWater);
}
首先$("#").css("")是jQuery的格式,等同于JS的document.getElementById("").style。而parseInt()函数则是取字符串中的第一串数字。这段代码的意思是,若海水向右流动,并两张海水图的左边线相对窗口左侧定位都为正数时,把右边的一张移去左边那张的末尾。若海水向左流动,两张图的左边线相对窗口左侧都是负数时,则把左边的一张移去右边那张的末尾。从而形成“循环”效果。
移动海水图的代码使用了jQuery的animate,也就是$("#").animate({},),后面跟随的数字代表在多少毫秒内完成。一般动画都是30帧,也就是一秒钟有30张图片,这里30毫秒动作一次,便是近似于30帧的效果。大家可以试着调整这个数字,会发现要不动画变得飞快,要不就会卡顿而使动画变得不流畅。
这里还使用了“递归算法”,一种听起来很牛13但其实很简单的算法,也就是一个函数结束时,再调用函数自己本身。上面代码最后一句animate参数中,便定义了动画结束后再调用一次整个函数,从而达到整套动画的循环播放。
附带一提,要使用jQuery的话,请在<head></head>中加入这句:<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
--------------02、03------------------
*02、舰:向固定方向上下浮沉的移动
*03、舰:到达尽头时从起点再次出发
完成水流动画后,那舰娘的动画就简单了,原理都是一样。这里的难点是上下浮沉,所谓上下浮沉,其实从运动线来说就是波型,这个我也是从萌购源代码中发现的。只要定义舰娘的运动轨迹为正弦波型就行了,具体代码如下:
function animateShip() {
if (direction == "+") {
if (parseInt($(ship).css("left")) > $(document.body).width() + 30) {
stopShip();
setShip();
}
}
else {
if (parseInt($(ship).css("left")) < -200) {
stopShip();
setShip();
}
}
var d = Math.random() * 4 - 2;
animateRotateShip(d);
var x = parseInt($(ship).css("left"));
if (direction == "+") {
x += 10;
}
else {
x -= 10;
}
var y = 3 * Math.sin(x) - 180;
$(ship).animate({ left: x + "px", top: y + "px" }, 1000, "linear", animateShip);
}
运动轨迹定义是在这句:var y = 3 * Math.sin(x) - 180。这段代码后半段的意思是,若水流方向向右,则舰娘在X轴上向右移动,反之向左。而舰娘的Y轴则根据3 * Math.sin(x) - 180的公式来计算获得。最后通过jQuery的animate来实现移动动画,注意参数“linear”可以让动画过程变得更为平滑,但真正涵义其实我到现在都不知道……
至于这段代码的前半部分,则是根据舰娘左边线相对窗口左侧的距离来定位舰娘。若舰娘完全离开当前窗口,则重置舰娘以达到“到达尽头时从起点再次出发”的效果。关于重置函数可见下面第11点的“随机选择舰娘”部分。
-----------------04-------------------
*04、舰:移动时左右摇晃
所谓左右摇晃,其实就是旋转图片,需要用到CSS3中的transform。而为了实现渐变效果,则需要用到CSS中的transition。由于浏览器对这些参数支持都不同,所以需要分别定义。其中IE9及以下的版本都不支持transition,IE8及以下的版本不支持transform,IE10及以上版本则全部支持。具体代码如下:
function animateRotateShip(d) {
$(ship).css("-moz-transition", "-moz-transform 1s");
$(ship).css("-moz-transform", " rotate(" + d + "deg)");
$(ship).css("-webkit-transition", "-webkit-transform 1s");
$(ship).css("-webkit-transform", " rotate(" + d + "deg)");
$(ship).css("-o-transition", "-o-transform 1s");
$(ship).css("-o-transform", " rotate(" + d + "deg)");
$(ship).css("transition", "transform 1s");
$(ship).css("transform", " rotate(" + d + "deg)");
}
这里稍微说回上面的水流动画,萌购并不是用jQuery的animate,而是使用纯CSS3的transition实现。这就导致萌购的海水在IE9及以下版本是不会流动的……接下来是左右摇晃的实现,其实就是直接调用上面的函数。通过设置参数2和-2,代表旋转角度为2度,并在其后回复原始角度。
var timeRotate;
function animateDargShip() {
animateRotateShip("2");
setTimeout('animateRotateShip("-2")', 500);
timeRotate = setTimeout("animateDargShip()", 1000);
}
setTimeout()函数的功能是延迟一段时间后再执行代码,这里第二句的作用是延迟500毫秒才旋转回原始角度。而最后一句则是1秒后再递归算法的重复调用自己,以达到持续左右摇晃的效果。这里还定义了一个全局变量timeRotate,其作用于下面的停止摇晃函数:
function stopDragShip() {
clearTimeout(timeRotate);
}
顺带一提,由于IE9只支持transform而不支持transition,所以IE9下舰娘的摇晃动画会显得充满硬直而没有渐变的效果。这个问题有望在IE10时可以彻底解决。
--------------05、06、07--------------
*05、舰:鼠标拖动时跟随鼠标移动
*06、舰:跟随鼠标拖移时左右摇晃
*07、舰:单击打开官方页面
当点击舰娘并拖动鼠标时,舰娘会跟随鼠标移动。这是个很有趣的设计,但对于个人来说是完全不懂得怎么去实现……所以最后是在网上找到一段合适的代码,然后根据萌购源代码改写而成:
var offsetX, offsetY, mouse_down_flag = false, mouse_move_flag = false;
$(".ship").click(function () { }).mousedown(function (e) {
stopShip();
animateDargShip();
mouse_down_flag = true;
mouse_move_flag = false;
offsetX = e.pageX - parseInt($(ship).css("left"));
offsetY = e.pageY - parseInt($(ship).css("top"));
});
$(document).mousemove(function (e) {
if (mouse_down_flag) {
mouse_move_flag = true;
var x = e.pageX - offsetX;
var y = e.pageY - offsetY;
$(ship).css({ top: y, left: x });
}
}).mouseup(function () {
if (mouse_down_flag) {
if (!mouse_move_flag) {
if (ship == "#akagi") {
window.open("http://www.goodsmile.info/ja/product/4213/%E3%81%8A%E9%A2%A8%E5%91%82%E3%81%93%E3%82%8C%E3%81%8F%E3%81%97%E3%82%87%E3%82%93+%E8%B5%A4%E5%9F%8E.html", "_blank");
}
else {
window.open("http://www.goodsmile.info/ja/product/4212/%E3%81%8A%E9%A2%A8%E5%91%82%E3%81%93%E3%82%8C%E3%81%8F%E3%81%97%E3%82%87%E3%82%93+%E5%B3%B6%E9%A2%A8.html", "_blank");
}
}
stopDragShip();
animateResetShip();
mouse_down_flag = false;
mouse_move_flag = false;
}
});
所谓的鼠标拖动,原理其实是这样的:根据鼠标初次点击的位置和移动后的位置,利用X轴和Y轴的距离差来让舰娘的运动轨迹形成一条与之平行的平行线。而这两条运动轨迹线连起来的话正好是一个平行四边形。
注意的是,上述代码虽然都是事件处理函数,但事件主体却并不全是舰娘。所以为了限制事件的触发条件,这里定义了全局变量mouse_down_flag和mouse_move_flag。而HTML方面也是使用了DIV背景图片,而非<div><img /></div>格式,使用后者的话会使得整个拖移动画变得非常卡。
摇晃舰娘就不说了,使用的是上面第4点的函数。至于单击舰娘会打开官方页面的话,使用的是window.open()函数,后面参数“_blank”意思是在新窗口打开网页。
-----------------08-------------------
*08、舰:鼠标松开时掉落水面
当鼠标拖移并松开后,舰娘一般都不在正常水平线上了,所以需要一段动画来实现其回归水平线,具体代码如下:
function animateResetShip() {
var y = parseInt($(ship).css("top"));
if (y != 180) {
if (y < -280) {
$(ship).animate({ top: -160 + "px" }, 700, "linear");
$(ship).animate({ top: -170 + "px" }, 100, "linear");
}
else if (y >= -280 && y < -180) {
$(ship).animate({ top: -170 + "px" }, 700, "linear");
}
else {
$(ship).animate({ top: -180 + "px" }, 500, "linear");
}
}
animateShip();
}
这里的区别只在于若舰娘被拖移得太高时,掉落动画会有个水流紧急缓冲的动画特效。但有一点要注意,这个动画里不能同时写left的变化。个人最初是同时写上left动画的,却导致后面舰娘回归水平线后移动时,无法正常获得left的值。也就是说这个掉落水面动画若改变left,会导致后面的动画与该动画的left值不等。具体原因貌似涉及到jQuery的动画队列什么的,个人并没有就此深究下去……
-----------------09-------------------
*09、舰:窗口大小变化时动画回到水面
这是最让我头痛的一个部分,由于萌购实现了这个效果,所以个人也只能想方法做出来。这效果并不是通用效果,网上也没有。个人最开始以为是根据屏幕来锁定舰娘位置,从而不受窗口变化而改变位置。但事实上这是做不到的,因为根本没有屏幕位置的参数……
最后在细心观察下,个人才发现自己理解错误。这个动画效果的本质其实是:若窗口宽度发生改变,舰娘的水平位置便跟随绝对定位变化。若窗口高度发生改变,则根据变化值的比例来调整舰娘距离水平线的高度。舰娘在窗口大小变化前后,其实相对屏幕的位置是变化的。只不过只要比例合适的话,那高度变化可以相对显得不那么明显。具体实现代码如下:
var windowHeight = getWindowHeight(), newWindowHeight;
var isResizing = false;
window.onresize = function () {
if (!isResizing) {
newWindowHeight = getWindowHeight();
if (newWindowHeight != windowHeight) {
stopShip();
isResizing = true;
var h = 1.2 * (newWindowHeight - windowHeight);
$(ship).css({ top: "-=" + h + "px" });
$(ship).animate({ left: direction + "=10px" }, 500, "linear");
setTimeout("animateResetShip()", 500);
windowHeight = newWindowHeight;
}
}
setTimeout(function () {
isResizing = false;
}, 100);
}
代码整体不复杂,不过有几个细节:1、高度变化调整舰娘高度的比例为1.2倍;2、若舰娘浮空的话,则其会先平移一段距离再回归水平线;3、回归水平线的动画使用的是上面第8点的函数;4、窗口变化事件在IE有BUG,会瞬间触发两次,网上对此问题描述为“IE浏览器onresize事件执行多次”。所以这里设置了全局变量isResizing作条件,限制事件函数在100毫秒内只能执行一次,以修复该BUG。
下面再附上网上直接搬下来的,根据不同浏览器情况去获取窗口高度和宽度的通用型函数:
function getWindowHeight() {
var winHeight;
if (window.innerHeight) {
winHeight = window.innerHeight;
}
else if ((document.body) && (document.body.clientHeight)) {
winHeight = document.body.clientHeight;
}
if (document.documentElement && document.documentElement.clientHeight) {
winHeight = document.documentElement.clientHeight;
}
return winHeight;
}
function getWindowWidth() {
var winWidth;
if (window.innerWidth) {
winWidth = window.innerWidth;
}
else if ((document.body) && (document.body.clientWidth)) {
winWidth = document.body.clientWidth;
}
if (document.documentElement && document.documentElement.clientWidth) {
winWidth = document.documentElement.clientWidth;
}
return winWidth;
}
-----------------10-------------------
*10、总:随机水流方向和浮动方向
要做随机水流方向很简单,只要使用随机函数Math.random()获得随机值,然后根据值去定义水流方向就行了。这里定义水流方向的时候要小心一点,因为其不仅会影响水流的方向,还会一并影响舰娘的移动方向。如果弄错的话,那就可能会出现水流和舰娘方向相反的BUG。
个人的思路为,首先定义水流方向direction为:向右则为“+”,向左则为“-”,然后通过随机数去决定水流方向,再根据方向来编写所有舰娘的动画函数。为什么方向取“+”和“-”,个人最初是想利用这个变量来直接定义动画参数,而不写IF来作判断。但可惜最后总览代码,发现并没有实现到想象中的效果……设置水流方向代码如下:
var direction;
function setDirection() {
var s = Math.random();
if (s <= 0.5) {
direction = "+";
}
else {
direction = "-";
}
}
-----------------11-------------------
*11、总:随机选择舰娘
只要懂得设置随机水流方向,那随机选择舰娘就很简单了,在选择舰娘的同时还可以顺便把其初始化。开始默认是所有舰娘都为不可见状态,只有被选中后才会显示出来,具体代码如下:
var ship = "#shimakaze";
function setShip() {
if ($(ship).is(":animated")) {
stopShip();
}
$("#shimakaze").css({ visibility: "hidden" });
$("#akagi").css({ visibility: "hidden" });
var s = Math.random();
if (s <= 0.5) {
ship = "#shimakaze";
}
else {
ship = "#akagi";
}
if (direction == "+") {
$(ship).css("left", "-170px");
}
else {
$(ship).css("left", getWindowWidth() + "px");
}
$(ship).css({ visibility: "visible" });
}
注意这里定义了全局变量ship,用来下面所有函数中代替$()的ID用。不过有个地方出了问题,那就是上面第5点的部分。在绑定鼠标事件时$(ship).click()报错,提示空值。这是因为事件绑定是在页面加载时进行的,但全局变量ship是在页面加载完成后,运行当中JS代码时才定义的,所以会出现没有找到对象的情况。个人的解决方法是:第5点的函数定义从$(ship).click()改为$(".ship").click(),通过CSS名去绑定所有的舰娘就可以了。下面是舰娘的HTML和CSS代码:
.ship
{
width: 170px;
height: 170px;
position: absolute;
top: -180px;
left: -170px;
cursor: pointer;
}
<div style="background-image: url(kankore-bath-shimakaze.png);" id="shimakaze" class="ship"></div>
<div style="background-image: url(kankore-bath-akagi.png);" id="akagi" class="ship"></div>
这里有两个细节:1、图片地址记得写正确,不要搞出硬盘图来了;2、cursor: pointer;的意思是当鼠标移DIV上面时,其图示会变成手指状,实现让DIV变超链接的大变身。
-----------------12-------------------
*12、总:点击版权声明时打开官网,全动画停止消失
这个是个人额外做的,原理在上面的函数都有,所以并没有花费太大功夫便完成了,具体代码如下:
.copyright
{
width: 550px;
position: absolute;
bottom: 0px;
top: -18px;
left: 5px;
text-align: left;
font-family: 微软雅黑;
font-size: 10px;
color: #FFFFFF;
cursor: pointer;
}
<div class="copyright" id="copyright">
Kankore ©2014 DMM.com/KADOKAWA GAMES All Rights Reserved. / Animation by ©GoodSmileCompany</div>
$("#copyright").click(function () {
$("#kankore_bath").animate({ opacity: "0" }, 2000);
stopShip();
$("#kankore_bath_water1").stop(true);
$("#kankore_bath_water2").stop(true);
setTimeout(function () { $("#kankore_bath").css("display", "none"); }, 3000);
window.open("http://www.goodsmile.info", "_blank");
});
CSS属性opacity,其作用是定义透明度,在上面第1点定义海水时也有用到。IE8及以下版本是不支持这个属性的,它们使用的是filter:alpha(opacity=50)。但只要使用这个属性,图片虽然能实现透明,却同时会产生非常恐怖的锯齿。所以个人最后决定还是放弃这个属性。
而若要停止动画,需要用到的函数是$("").stop(true)。如果不停止动画而只是单纯隐藏整个DIV的话,动画会继续播放下去,并持续占用CPU资源,所以紧记一定要在最后写上停止动画的语句。停止舰娘动画的函数如下:
function stopShip() {
$(ship).stop(true);
}
-----------------13-------------------
*13、总:整体固定在窗口的最底部,而非网页的底部
要实现这个效果,只需要CSS属性中position定义为fixed就可以了,下面便是个人最上层DIV的写法。有趣的是,如果把这里的CSS属性提取出来单独写成一个CSS的话,上面那两张2760PX的海水就会把窗口给撑大。但若像下面那样把CSS属性写在DIV的STYLE中,则不会有问题。其实个人觉得把窗口撑大才是正确的,但浏览器自动帮我把这个问题给解决了。
<div id="kankore_bath" style="position: fixed; bottom: 0; left: 0; opacity: 1;">
......
</div>
-----------------14-------------------
*14、总:只在BLOG首页显示该特效
在初始化整个“翻滚吧舰娘!”时写上域名判断就可以了,具体实现代码可见下面。为什么要只在BLOG首页显示?一来是为了保证不影响文章阅读性,二来是为了不那么占用CPU资源。个人的笔记本就是只要一运行该动画特效,CPU风扇就会响得恐怖。所以把其限定在首页上显示就可以了。
$(document).ready(function () {
if (document.URL == "http://hero32167.blog126.fc2.com/") {
document.ondragstart = function () { return false; }
setDirection();
setShip();
animateWater();
animateShip();
}
else {
$("#kankore_bath").css("display", "none");
}
})
document.ondragstart = function () { return false; },这句是从萌购源代码抄回来的,作用是:禁止鼠标拖拽图片。但其实个人没看出这句的实际效果,姑且留着作参考吧。
-------------华丽的分割线-------------
代码解释大概就是这么多了,下面是测试时间,个人特意用了6个浏览器来测试这个特效。可惜公司里的系统不支持IE10,不然就连IE10也可以一起测试了。测试结果如下:
1、FIREFOX:全特效及格
2、IE8:舰娘不会摇晃,海水不会透明,点击版权时整体不会渐变消失
3、IE9:舰娘摇晃时没有动画效果
4、CHROME:鼠标拖动舰娘时有延迟,版权字体偏大
5、OPERA:鼠标拖动舰娘时有延迟,版权字体偏大
6、SAFARI:鼠标在版权变换图示时有延迟,版权字体模糊,整体反应很慢
IE的问题上面已经解释过了;OPERA和CHROME的表现一样,就是字体和FIREFOX不同,反应也比FIREFOX慢,算是不过不失;至于SAFARI,我只想说这玩意在PC上为什么还有人用,水平实在太低了,各种卡得快崩溃似的,完全不能接受。个人还特意试了IPAD MINI上的SAFARI,除了鼠标事件无效外,其余表现正常,还能看到两张海水图的分割线,算是个意外的BUG。
测试完自己这只舰娘后,个人又手痒的测试了萌购的那只。由于是作用在商业环境下,所以萌购的舰娘表现效果限制肯定是比个人这只大的。之后的测试也证实了这个看法,结果如下:
1、FIREFOX:全特效及格
2、IE8:舰娘不会摇晃,海水不会流动和透明
3、IE9:舰娘不会摇晃,海水不会流动,舰娘从高处掉落时没有紧急缓冲动画
4、CHROME:鼠标拖动舰娘时有延迟,版权字体偏大,舰娘从高处掉落时没有紧急缓冲动画
5、OPERA:鼠标拖动舰娘时有延迟,版权字体偏大
6、SAFARI:鼠标事件严重影响到背景,版权字体模糊,整体反应很慢,没有掉落动画
IE9和CHROME没有紧急缓冲动画这个让我有点意外,不知道萌购的代码实现和我的有什么不同,可以让CHROME和OPERA有不同的表现;FIREFOX一如既往的满分表现;IE8还是同样问题;SAFARI又一次被轰杀至渣了……个人又一次拿起了IPAD MINI的SAFARI,除了鼠标事件无效外,萌购这只其余表现同样正常。可惜舰娘和海水出现了位置差,导致两者完全分离,成了水在下面流,舰娘在天上飞的情况……

*
|
|