本文介绍了Scala游戏编程:推进功能风格中的对象位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很长时间的java程序员慢慢地学习scala(顺便喜欢它),我认为我的思想仍然围绕着函数写作的概念。现在我正试图为一些移动2D纹理编写一个简单的可视化工具。这种必要的方法很简单,我相信你们中的大多数人都会认识到这个相对无处不在的代码块(为了保护无辜者,改变了这些东西):

  class MovingTexture(var position,var velocity)扩展带有进度的渲染{
def render:Unit = {...}
def advance(milliseconds:Float):Unit = {
position = position + velocity * milliseconds
}
}

这段代码可以正常工作,但是它有很多可变状态,并且它的功能充满了副作用。我不能让自己逃避这一点,那么必须是更好的方法!

有没有人对这个简单的问题有一个惊人的,优雅的功能解决方案?有没有人知道一个我可以更多地了解解决这些问题的来源?

解决方案

游戏往往是高性能事务,在这种情况下,您可能会发现可变状态正是您需要的。



然而,在这种情况下,有几个简单的解决方案:

 案例类MovingTexture(位置:VecXY,velocity:VecXY)扩展带有进度的渲染{
def advance(ms:Float)= copy (position = position + ms * velocity
def acceleration(acc:Float,ms:Float)= copy(velocity = velocity + ms * acc)
...
}

也就是说,不要让你的类自己更新,而是让它们返回自己的新副本。对于俄罗斯方块来说,没有什么大不了的,对于孤岛危机,也许不那么聪明)。这看起来好像只是把问题推回到了一个层面:现在你需要一个变量来代替 MovingTexture ,对?一点都不:

  Iterator.iterate(MovingTexture(home,defaultSpeed))(_。advance(defaultStep))

这将在同一个方向上产生层出不穷的位置更新。你可以做更复杂的事情混合在用户输入或whatnot。

另外,您可以

  class Origin延伸渲染{
//各种昂贵的东西都放在这里
}
class Transposed(val ori:Origin,val position:VecXY) Advances {
//将TextureAtOrigin用便宜的方法包装起来,使其像行为一样动作
def moving(vel:VecXY,ms:Float)= {
Iterator.iterate(this)。(tt => new Transposed(tt.ori,position + ms * vel))
}
}

也就是说,重量级的东西永远不会被更新并且具有更轻的视图,使得它们看起来好像它们已经以您希望它们改变的方式发生了变化。


Long time java programmer slowly learning scala (loving it by the way), and I think my mind is still wrapping itself around the concept of writing things functionally. Right now I'm attempting to write a simple visualizer for some moving 2d textures. The imperative approach is simple enough, and I'm sure most of you will recognize this relatively ubiquitous block of code (stuff was changed to protect the innocent):

class MovingTexture(var position, var velocity) extends Renders with Advances {
    def render : Unit = {...}
    def advance(milliseconds : Float) : Unit = {
        position = position + velocity * milliseconds
    }
}

This code will work just fine, however it has tons of mutable state and its functions are replete with side effects. I can't let myself get away with this, there must be a better way!

Does anyone have an amazing, elegant, functional solution to this simple problem? Does anyone know of a source where I could learn more about solving these sorts of problems?

解决方案

Games are often high-performance affairs, in which case you may find that mutable state is just the thing you need.

However, in this case, there are a couple of simple solutions:

case class MovingTexture(position: VecXY, velocity: VecXY) extends Renders with Advances {
  def advance(ms: Float) = copy(position = position + ms*velocity
  def accelerate(acc: Float, ms: Float) = copy(velocity = velocity + ms*acc)
  ...
}

That is, instead of having your classes update themselves, have them return new copies of themselves. (You can see how this could get expensive quickly. For Tetris, no big deal. For Crysis? Maybe not so smart.) This seems like it just pushes the problem back one level: now you need a var for the MovingTexture, right? Not at all:

Iterator.iterate(MovingTexture(home, defaultSpeed))(_.advance(defaultStep))

This will produce an endless stream of position updates in the same direction. You can do more complicated things to mix in user input or whatnot.

Alternatively, you can

class Origin extends Renders {
  // All sorts of expensive stuff goes here
}
class Transposed(val ori: Origin, val position: VecXY) extends Renders with Advances {
  // Wrap TextureAtOrigin with inexpensive methods to make it act like it's moved
  def moving(vel: VecXY, ms: Float) = {
   Iterator.iterate(this).(tt => new Transposed(tt.ori, position+ms*vel))
  }
}

That is, have heavyweight things never be updated and have lighter-weight views of them that make them look as though they've changed in the way that you want them changed.

这篇关于Scala游戏编程:推进功能风格中的对象位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-27 16:41