实验游戏开发研究

您如何将一个模糊的想法变成一个游戏-从技术细节中获取有趣和具有挑战性的内容? 最近,我发现自己想知道CSS过渡是否可以用于制作某种游戏。 本文是关于这个想法的探索,以及它如何发展成为一种优雅的(据我所知)独特的游戏玩法。

基本思想

基本思想是使用播放器部分控制的缓慢过渡来为对象的lefttop位置设置动画。 因此,我们将需要一个游戏区域-我们将其称为棋盘和一个动画对象-我们将其称为

<body>
  <div id="board">
    <span id="ball"></span>
  </div>
</body>

板的纵横比为3:2,而球的宽度为5%。 这些值都不是特别重要的,它们似乎才是最合适的-选择了宽高比,以便可以(最终)适合iPhone屏幕,并且球相对较小,因此有足够的移动空间。 下图演示了基本布局,其中球位于板的左上角。

球具有负边距,以使其自身的宽度和高度偏移一半,以便我们在球上设置的任何位置都将是球的中心原点(例如,第一个演示中的球位于0,0 )。 这是该演示的CSS:

#board
{
  position:relative;

  display:block;
  width:720px;
  height:480px;
  margin:24px auto 0 auto;

  border-radius:2px;

  background:#fff;

  box-shadow:0 0 16px -2px rgba(0,0,0, 0.5);
}

#ball
{
  position:absolute;
  left:0;
  top:0;

  display:block;
  width:36px;
  height:36px;
  margin:-18px 0 0 -18px;

  border-radius:18px;

  background:#f00;

  box-shadow:inset 0 0 0 2px rgba(0,0,0, 0.35), 4px 10px 10px rgba(0,0,0, 0.15);
}

理想情况下,我们将根据可用的窗口或屏幕空间动态应用木板和球的尺寸(这对于将游戏移植到移动浏览器是必不可少的),但是为了使这些示例简单易行,尺寸是固定的-木板为720× 480,球为36×36。

现在可以用百分比坐标来描述球的可能运动范围-从左上角的0%,0%到右下角的100%,100% 。 使用百分比比计算像素更简单,并且可以在将来灵活调整尺寸。

现在,我们可以通过应用一些简单的JavaScript轻松地控制位置,该JavaScript根据方向性按键设置来设置lefttop位置,即,如果按下了Left Arrow,则将style.left设置为"0" ,或者如果Down Arrow是按下,然后将style.top设置为"100%"

var
ball = document.getElementById('ball'),
positions =
{
  37  : ['left', '0'],
  38  : ['top', '0'],
  39  : ['left', '100%'],
  40  : ['top', '100%']
};

document.addEventListener('keydown', function(e, data)
{
  if(data = positions[e.keyCode])
  {
    ball.style[data[0]] = data[1];

    e.preventDefault();
  }

}, false);

positions数组为每个箭头keyCode定义了一个属性和值,并且在第一个条件中还使用了该数组来知道是否完全按下了箭头键,在这种情况下,我们必须使用preventDefault()来阻止其本地操作(因此该页面无法同时滚动)。 再次为了简单起见,我没有进行任何功能检测来筛选较旧的浏览器。 实际上,我们希望对浏览器进行预测试,以确保完全支持转换。 以下演示允许将球移动到任何角落。

接下来,让我们添加一个缓慢的transition规则来对运动进行动画处理。 请注意包含供应商前缀。

#ball
{
  -moz-transition:all 5s ease;
  -ms-transition:all 5s ease;
  -o-transition:all 5s ease;
  -webkit-transition:all 5s ease;
  transition:all 5s ease;
}

现在,箭头键更改不会触发快速移动,而是会触发球在整个板上缓慢缓慢地移动。 而且由于每次按键仅改变left top位置(两者都不改变),所以总体效果是一种新颖且相当优雅的运动-一种“弹性”,其编写起来会更加复杂:

例如,尝试该演示中的以下操作:

  1. 刷新页面以重置球
  2. 然后按一次向右箭头
  3. 等到球传中(2.5秒后)
  4. 然后按一次向下箭头

按下向右箭头将开始向右移动球的过渡,然后按下向下箭头将触发第二个将球向下移动的过渡。 但是第二个过渡不会影响第一个过渡,后者仍将继续,并且总体效果是一条平滑的曲线 -描述了从顶部中心到右下角的弧线。

完善游戏玩法

现在,我们可以使用箭头键将球移动到棋盘内部的任何位置,以建议移动方向。 这提供了控制权,但不是完全控制权,这是可玩游戏的基本挑战。 由于过渡的应用方式,我们拥有的控制量也有所不同。 例如,如果当您按向右箭头时球位于"left:0" ,则需要五秒钟才能到达右边缘(如预期)。 但是,如果按向右箭头时球已经在"left:80%" ,则仍然需要整整五秒钟的时间才能向右边缘移动那么小的距离。 换句话说,球的速度取决于当改变方向时,它与指定方向的接近程度。

转换时序功能的选择也有很大的不同。 在这些示例中,我使用了"ease"功能,该功能等同于以下贝塞尔曲线

该图显示了相对速度,并说明了它在开始时如何加速,然后在最终时减速。 因此,球在过渡的起点和终点附近的移动会更加缓慢,这将使其在这些点上的控制变得更加容易。 实际上,通过快速连续地改变其方向,可以使球几乎保持静止。

增加真正的挑战

现在我们有一个很好的可玩动作,但我们仍然没有游戏。 一定有挑战性,实际上是您必须在受限的控制范围内做的事情 。 也许我们可以使用相同的过渡添加额外的内容?

由于我们已经定义了适用于"all"属性的过渡,因此我们可以简单地扩展JavaScript,以便每个箭头键也可以应用背景色更改 ,并使用不同的粗体颜色来与每个方向相对应:

var
ball = document.getElementById('ball'),
positions =
{
  37  : ['left', '0'],
  38  : ['top', '0'],
  39  : ['left', '100%'],
  40  : ['top', '100%']
},
colors =
{
  37  : '255,0,0',
  38  : '255,255,0',
  39  : '0,0,255',
  40  : '0,255,255'
};

document.addEventListener('keydown', function(e, data)
{
  if(data = positions[e.keyCode])
  {
    ball.style[data[0]] = data[1];
    ball.style.backgroundColor = 'rgb(' + colors[e.keyCode] + ')';

    e.preventDefault();
  }

}, false);

现在,通过按箭头键,我们不仅可以更改球的位置,还可以更改其原色。 让我们还将球的默认位置移到中心,并将其默认颜色设置为灰色(即,将其设置为中等明亮的颜色,该颜色在比赛中将永远不会出现):

但是,当然,颜色并不会立即改变,而是会在单个过渡过程中从一种颜色逐渐淡入另一种颜色,并沿途穿过各种中间阴影。 例如,如果球为红色,然后按向右箭头 ,则它将通过各种深浅的紫色(以及向右移动)从红色变为蓝色。

由于每个方向都有不同的颜色,所以相同的运动也可能导致不同的颜色。 例如,如果您按向右箭头,然后快速按向下箭头 ,则球将移动到右下角并逐渐变为青色(因为青色被映射为向下)。 但是,如果以相反的顺序(向下然后向右)按这些键,则球仍将移动到相同的角,但是这次淡化为蓝色(因为蓝色映射到右侧)。 因此,对于任何给定的物理位置,球可能具有多种可能的颜色阴影。

现在我认为,我们拥有制作游戏所需的一切。 如果很难完全控制球,并且很难将其变为特定的颜色,那么我们可以说必须将球移至特定的位置和 特定的颜色,从而给比赛带来挑战。

最终游戏原型

我们将添加一系列具有不同背景颜色的其他元素(我们称它们为目标 ),然后添加脚本来监视球的位置和颜色。 如果球也位于相同颜色的目标区域内,则我们将其称为比赛,目标消失。 这很容易描述,但实际上已被复杂化为脚本,如下所示。

var targets = 
[
  { "color" : [220,180,40], "coords" : [5,5,12,35] }, 
  { "color" : [210,80,80], "coords" : [45,2.5,10,40] }, 
  { "color" : [160,90,60], "coords" : [65,5,20,20] }, 
  { "color" : [100,100,150], "coords" : [2.5,75,35,15] }, 
  { "color" : [150,70,100], "coords" : [55,65,10,20] }, 
  { "color" : [70,230,150], "coords" : [87.5,60,10,20] } 
];

for(var len = targets.length, i = 0; i < len; i ++)
{
  var target = document.createElement('div');
  target.className = 'target';
  
  target.style.left = targets[i].coords[0] + '%';
  target.style.top = targets[i].coords[1] + '%';
  target.style.width = targets[i].coords[2] + '%';
  target.style.height = targets[i].coords[3] + '%';
  target.style.backgroundColor = 'rgb(' + targets[i].color.join(',') + ')';
  
  targets[i].target = ball.parentNode.insertBefore(target, ball);
}


var tracking = window.setInterval(function()
{
  var ballcolor = window.getComputedStyle(ball).backgroundColor.replace(/[^0-9,]/g, '').split(',');
  for(var n = 0; n < 3; n++)
  {
    ballcolor[n] = parseInt(ballcolor[n], 10);
  }

  for(var i = 0; i < targets.length; i ++)
  {
    if
    (
      ball.offsetLeft > targets[i].target.offsetLeft
      &&
      ball.offsetLeft + ball.offsetWidth < targets[i].target.offsetLeft + targets[i].target.offsetWidth
      &&
      ball.offsetTop > targets[i].target.offsetTop
      &&
      ball.offsetTop + ball.offsetHeight < targets[i].target.offsetTop + targets[i].target.offsetHeight
    )
    {
      var match = 0;
      for(var n = 0; n < 3; n ++)
      {
        if(Math.abs(ballcolor[n] - targets[i].color[n]) < 40)
        {
          match ++;
        }
      }
      
      if(match === 3)
      {
        targets[i].target.parentNode.removeChild(targets[i].target);
        targets.splice(i, 1);

        if(targets.length === 0)
        {
          window.clearInterval(tracking);
          
          window.setTimeout(function(){ alert('Yay!'); }, 250);
        }
      }
    }
  }

}, 62.5);

比较颜色时,我们必须留出一定的余地。 我们不能期望球和目标完全相同 (这几乎是不可能的),因此我们要从另一个中减去一个,并考虑到最大差异。 因为我们需要这样做,所以必须使用RGB来应用颜色,因为RGB值更易于编程使用:

var match = 0;
for(var n = 0; n < 3; n ++)
{
  if(Math.abs(ballcolor[n] - targets[i].color[n]) < 40)
  {
    match ++;
  }
}

if(match === 3)
{
  //... all three channels are sufficiently close
}

跟踪代码本身包装在单个setInterval()循环中(据我所知)是持续监视球的属性的唯一方法-使用getComputedStyle()和offset属性,以获取球的颜色和位置每次迭代。 该间隔不应太快,以至于不会给浏览器造成太大的压力,但它仍然必须足够快才能准确 -基于球的大小和速度。 由于球是板的5%,并且在五秒钟内移动了整个距离,因此,球平均需要250ms才能移动自己的宽度。 因此,无论我们将其用于间隔的任何比例,都将最大跟踪漂移表示为球尺寸的一部分,即,球的间隔计算位置与其实际位置之间的最大差异。 我设置的速度为62.5ms ,这使得最大漂移为球大小的四分之一。 坦白说,这比我想要的要快一点,但是任何比那慢的速度都将不够准确,并且可能导致无法检测到有效的匹配项。

如果有某种CSS过渡的每帧回调事件,一切都会容易得多,但是没有-我们仅有的事件是transitionend事件,该事件在过渡结束时触发,但这没有用。给我们在这里。

但是无论如何-我们现在有一个游戏! 尝试以下完成的原型,看看您如何进行-游戏的目标匹配每个目标,直到棋盘清晰为止

超越原型

当您完成时,什么也没有发生,只有一轮! 这只是一个原型,即使如此,我们仍然可以进行改进。 例如,如果我们限制球的运动,从而不允许其触碰边缘,那将使游戏更具挑战性和前卫性。

因此,请很快加入本文的第二部分 ,作为结束语 ,我们将研究如何(以及实际上是否可以)进一步开发此原型,使其成为一个完善且可分发的游戏。

同时,您可以下载本文所有演示的zip文件:

From: https://www.sitepoint.com/a-study-in-experimental-game-development/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值